This is a point in a polygon. Latitude and Longitude Coordinates. GeoTools - geotools

Given a polygon that I trace with Coordinates of Latitude and Longitude, given an fline that I also receive in (in Latitude, Longitude).
I need to know if this point is inside my polygon or not
import org.geotools.geometry.jts.JTSFactoryFinder;
import org.locationtech.jts.geom.Coordinate;
import org.locationtech.jts.geom.Geometry;
import org.locationtech.jts.geom.GeometryFactory;
import org.locationtech.jts.geom.Polygon;
import org.locationtech.jts.geom.PrecisionModel;
import org.opengis.geometry.MismatchedDimensionException;
import org.opengis.referencing.FactoryException;
import org.opengis.referencing.NoSuchAuthorityCodeException;
import org.opengis.referencing.operation.TransformException;
private void isPointInPolygon() {
GeometryFactory geometryFactory = JTSFactoryFinder.getGeometryFactory();
Coordinate[] coords = new Coordinate[] { new Coordinate(40.174256, -3.483185),
new Coordinate(40.173279, -3.481339), new Coordinate(40.172597, -3.482541),
new Coordinate(40.173403, -3.485401), new Coordinate(40.174256, -3.483185) };
Polygon polygon = geometryFactory.createPolygon(coords);
System.out.println("polygon : " + polygon.isValid());
double scale = Math.pow(10, 2);
PrecisionModel pm = new PrecisionModel(scale);
GeometryFactory gf = new GeometryFactory(pm);
Geometry testPoint = gf.createPoint(new Coordinate(40.173597, -3.483798));
System.out.println("polygon contains point : " + polygon.contains(testPoint));
}
// MAVEN
<dependency>
<groupId>org.geotools</groupId>
<artifactId>gt-geojson</artifactId>
<version>24-SNAPSHOT</version>
</dependency>
The following code is correct, that is, it does not give any error.
I have doubt if its result is correct, or if I have to do some kind of conversion for the result to be correct. If I have to flatten it or if it is code, it already knows how to cure well.

Provided that your polygon is reasonably small it will be fine.
If your polygon:
is approaching half of the world then the answer may be wrong.
crosses the anti-meridian (180W/E) then the answer will probably be wrong.
if the sides of the polygon are very long but have few points on them, then the answer may well be wrong.

Related

MySQL query claims point is not within polygon

I've drawn a polygon which contains a point in Google Maps. But if I pass the coordinates to MySQL to calculate if the point is within the polygon, it returns false.
SELECT ST_Within(
ST_GeomFromText('POINT(8.34047 54.91320)', 4326),
ST_GeomFromText('POLYGON((62.144619879597 10.486242310988,54.622536815923 2.3124141859883,55.403637023919 23.977453248488,62.144619879597 10.486242310988))', 4326)
) AS is_point_within_polygon;
=> returns 0
But the point is obviously within the polygon:
I double-checked that using Python:
import numpy as np
from shapely.geometry import Point
from shapely.geometry.polygon import Polygon
if __name__ == '__main__':
v0 = [62.144619879597, 10.486242310988]
v1 = [54.622536815923, 2.3124141859883]
v2 = [55.403637023919, 23.977453248488]
lats_vect = np.array([v0[0], v1[0], v2[0]])
lons_vect = np.array([v0[1], v1[1], v2[1]])
lats_vect = np.append(lats_vect, lats_vect[0])
lons_vect = np.append(lons_vect, lons_vect[0])
lons_lats_vect = np.column_stack((lons_vect, lats_vect))
polygon = Polygon(lons_lats_vect)
point = Point(8.34047, 54.9132)
print(point.within(polygon))
=> prints True
What's wrong with the MySQL query?
I think there are two issues here:
First with the query. You list polygon in lat-lon order, but the point seems to be in lon-lat order. You probably want
SELECT ST_Within(
ST_GeomFromText('POINT(54.91320 8.34047)', 4326), -- NOTE CHANGE HERE
ST_GeomFromText('POLYGON((62.144619879597 10.486242310988,54.622536815923 2.3124141859883,55.403637023919 23.977453248488,62.144619879597 10.486242310988))', 4326)
) AS is_point_within_polygon;
Even this query returns FALSE, and this is expected in MySQL. 4326 is Geodesic coordinate system, meaning it operates on the spherical Earth, not on this flat map. With geodesic CRS, edges follow the geodesic shortest lines on Earth, not straight lines on flat map, and for really long lines like here and points close to the edge it matter:
Points slightly further North would be within the polygon, e.g. check out
SELECT ST_Within(
ST_GeomFromText('POINT(56 8.34047)', 4326),
ST_GeomFromText('POLYGON((62.144619879597 10.486242310988,54.622536815923 2.3124141859883,55.403637023919 23.977453248488,62.144619879597 10.486242310988))', 4326)
) AS is_point_within_polygon

GLTF file not well positioned by Cesium

I want to display a hurricane (big isosurface object) in Cesium. For this I converted an OBJ file with longitude, latitude, altitude columns for each vertex of the isosurface representing the hurricane, in a new OBJ file reprojected in ECEF (Earth Centered) projection.So the final OBJ file contains now X,Y,Z for each vertex instead of longitude, latitude, altitude. After final reformat by obj2gltf, I try to display the GLTF "hurricane" file in Cesium.JS using the code below:
console.log('loading hurricane.gltf';
var mymodel = viewer.scene.primitives.add(Cesium.Model.fromGltf({
url : 'data/hurricane.gltf',
modelMatrix : Cesium.Matrix4.IDENTITY,
asynchronous: false
}));
I can see my hurricane on the earth, but not at the good position. I suspect a problem of matrix. IDENTITY matrix seems not to be the good one. I could try to make a new matrix but I can't find enough informations about the axes orientation used by Cesium.
I verified the X,Y,Z ECEF coordinates, they are good. Does anyone already meet this problem ?
If your glTF model origin is at the center of the hurricane, you can place it using a Cesium Entity, something like this:
// Longitude degrees, Latitude degrees, height in meters
var position = Cesium.Cartesian3.fromDegrees(-123.0744619, 44.0503706, height);
var heading = Cesium.Math.toRadians(0);
var pitch = 0;
var roll = 0;
var hpr = new Cesium.HeadingPitchRoll(heading, pitch, roll);
var orientation = Cesium.Transforms.headingPitchRollQuaternion(position, hpr);
var entity = viewer.entities.add({
name : 'Hurricane',
position : position,
orientation : orientation,
model : {
uri : 'data/hurricane.gltf'
}
});
viewer.trackedEntity = entity;
There are more complete working demos of this on Sandcastle.
But, if your hurricane is visible on the surface of the Earth using the identity matrix, that likely means that the origin of that model is nowhere near the center of the hurricane. You may need to edit the glTF file, to make sure that the model is centered on its own origin, and does not have some fixed Earth location pre-baked into the model's internal transformations.

How can I scale my map to fit my svg size with d3 and geojson path data

I am trying to create a d3 SVG that draws a map of New York State and scale it so that it fits the size of my SVG, the issue I am having is that when I use .fitSize([height, width], mapObject) it only returns a NaN error in the console.
the topoJSON file of NYS I am using
I am able to get the map to display without scaling but of course, it is not optimized and needs to be scaled
I have attempted what is said in this post but I have not figured out the correct solution
var map = d3.json('./ny.json')
Promise.all([map]).then(data => {
var height = 800;
var width = 800;
var mapData = data[0]
// original geoJSON to that works without scaling
// var geoData = topojson.feature(mapData, mapData.objects["cb_2015_new_york_county_20m"]).features
//
var geoData = topojson.feature(mapData, {
type:"GeometryCollection",
geometries: mapData.objects["cb_2015_new_york_county_20m"].geometries,
})
var projection = d3.geoMercator()
.fitSize([width, height], geoData)
var path = d3.geoPath()
.projection(projection)
d3.select('svg')
.attr('height', height)
.attr('width', width)
.selectAll('.county')
.data(geoData)
.enter()
.append('path')
.classed('.county', true)
.attr('d', path)
})
I am pretty sure this is a formatting error on my part, but I am unsure of what data .fitSize() or .fitExtent() is trying to compare against.
right now the way the code site I receive no error outputted to the console but I also have no data append to the SVG
The issue is that fitSize takes a geojson object while selectAll.data() takes an array, you are using one of these two for both in geoData. This leaves two solutions:
Solution 1:
If we use
var geoData = topojson.feature(mapData, mapData.objects["cb_2015_new_york_county_20m"]).features
var projection = d3.geoMercator()
.fitSize([width, height], geoData)
We get NaN errors because the projection is not set properly as we aren't passing a geojson object, just an array of geojson objects. We could solve this by making a feature collection with geoData and passing that to fitSize:
var geoData = topojson.feature(mapData, mapData.objects["cb_2015_new_york_county_20m"]).features
var projection = d3.geoMercator()
.fitSize([width, height], {type:"FeatureCollection", features: geoData})
Now we are passing a geojson feature collection to fitSize, we're all go on the projection, and since geoData is still an array, we can pass that to selectAll.data() unchanged.
Here's a block.
Solution 2:
If we use:
var geoData = topojson.feature(mapData, {
type:"GeometryCollection",
geometries: mapData.objects["cb_2015_new_york_county_20m"].geometries,
})
We get a geojson object, projection.fitSize works, but selectAll().data(geoData) doesn't add any features as it isn't an array - the enter selection is empty. We can substitute in selectAll().data(geoData.features) to solve this and enter one path per feature (alternatively we could use .data([geoData]) to enter one feature for all the paths).
Here's a block.
Both blocks are drawn at the correct scale - the map exceeds the block bounds as I didn't alter your 800x800 dimensions

DbGeography.Distance() returning incorrect distance

I'm experimenting with System.Data.Spatial.DbGeography, that I want to use to determine the distance from one coordinate to another (going to be stored in SQL server).
My coordinates are in lat/long, and I got them from Bing Maps (I've tried with coordinates from Google Maps too, with the same result).
var osloCentralStation = DbGeography.FromText("POINT(59.9109 10.7523)", 4326);
var drammen = DbGeography.FromText("POINT(59.7378 10.2050)", 4326);
Console.WriteLine("Distance: {0}km", osloCentralStation.Distance(drammen) / 1000);
Returns:
Distance: 63,4340839088124km
The returned distance is approximately double what it should be.
https://maps.google.com/maps?saddr=59.9109+10.7523&daddr=59.7378+10.2050
Does anybody have any idea as to what's going on?
You're not declaring the element in WKT in the right order.
WKT should be in your case:
POINT(10.2050 59.7378)
See OGC standard here:
http://msdn.microsoft.com/en-us/library/bb933834.aspx
http://en.wikipedia.org/wiki/Well-known_text
And then it has to be declared like:
POINT(LONGITUDE LATITUDE)
Also keep in mind that it won't be the driving distance but the distance by air.
It turns out that lat/long are given as long/lat when creating new DbGeography objects.
I've written a little helper method so that I don't get it wrong again in the future:
private static DbGeography CreateDbGeography(double latitude, double longitude, int srid = 0)
{
var text = string.Format(CultureInfo.InvariantCulture.NumberFormat, "POINT({0} {1})", longitude, latitude);
if (srid > 0)
{
return DbGeography.FromText(text, srid);
}
return DbGeography.FromText(text);
}

Fetching all the coordinates along a route generated by Directions Service in Google Maps Apiv3

My application allows a user to select two points on the map and find a route between them using the Directions Service of the Google maps Apiv3. Then the coordinates along this route has to be saved to the database. I could successfully write all the code to accomplish this. However I am left out with an issue.
I know that there are several other questions in StackOverflow- One, Two on the same, but I think surely either they or me has missed out something here.
Sample Code:
function getCoordinates(result) {
var currentRouteArray = result.routes[0]; //Returns a complex object containing the results of the current route
var currentRoute = currentRouteArray.overview_path; //Returns a simplified version of all the coordinates on the path
obj_newPolyline = new google.maps.Polyline({ map: map }); //a polyline just to verify my code is fetching the coordinates
var path = obj_newPolyline.getPath();
for (var x = 0; x < currentRoute.length; x++) {
var pos = new google.maps.LatLng(currentRoute[x].kb, currentRoute[x].lb)
latArray[x] = currentRoute[x].kb; //Returns the latitude
lngArray[x] = currentRoute[x].lb; //Returns the longitude
path.push(pos);
}
}
The above code works perfect except that the kb and lb properties of the overview path which seem to hold the lat and lng coordinates are not always the same. The last time I made the code, it was kb and lb for few days, and later it changed to mb, nb and today jb and kb.
I dont see any other properties in the object that can provide me the latlng's other than the above. Answers to other similar questions dint mention this issue. Am I missing something here? Any reliable solutions please.
do not use kb and lb which are minified names and undocumented. Use only the documented properties .lat() and .lng()
Another option is to decode the "points" string:
http://home.provide.net/~bratliff/routes/
It is a lot faster than using the lat() / lng() methods for every individual point.