I get following exception when using Entity Framework to get data from bounds from a google map:
FormatException: 24201: Latitude values must be between -90 and 90 degrees.
POLYGON((81.9882716924738 140.187434563007,21.5587046599696 140.187434563007,21.5587046599696 -40.1641279369925,81.9882716924738 -40.1641279369925,81.9882716924738 140.187434563007))
I can see other have same problem, but havent found anything that solves this. I would expect that first coordinate for point is the latitude and second for longitude? And none is above 90 so why do I get this error? I tried swapping lat and lng but with same problem.
This is the failing line:
var poly = FindByBoundingBox(northEastLat, northEastLng, southWestLat, southWestLng);
DbGeography polygon = DbGeography.FromText(poly, 4326);
var parksWithinPolygon = dbCtx.SiteList.Where(p =>
p.PolygonCenter.Intersects(polygon)).Select(p=>p.SiteName).ToList();
As Damien states first problem is that Sql server expects longitude first and then lattitude. This throws another error, redirecting to another problem:
"This operation cannot be completed because the instance is not valid".
My best bet is it's the they way/order I build the polygon. Has anyone succeeded in mapping google bounds to a polygon in SQL server? In short I am trying to get any data (data has a point column) within the google map bounds.
The function to calculate polygon is listed below:
public string FindByBoundingBox(double northEastLat, double northEastLng, double southWestLat, double southWestLng)
{ //Create poylgon of bounding box
System.Globalization.CultureInfo customCulture = (System.Globalization.CultureInfo)System.Threading.Thread.CurrentThread.CurrentCulture.Clone();
customCulture.NumberFormat.NumberDecimalSeparator = ".";
System.Threading.Thread.CurrentThread.CurrentCulture = customCulture;
var bboxWKT = string.Format("POLYGON(({1} {0},{1} {2},{3} {2},{3} {0},{1} {0}))", northEastLat, northEastLng, southWestLat, southWestLng);
return bboxWKT;
}
OK i figured it out. As Damien stated the order of coordinates is oppesite of google. In SQL long needs to be first. Next thing is what is the "left hand rule". You need to create your polygon starting from lower left corner and then counter clock wise.
Related
I have an NSManagedObject class that's persisted in a SQLite database in Core Data. This object has persistent Latitude and Longitude properties. I'm trying to create an NSFetchedRequestController that fetches all of the instances of that class that are within a certain distance from the user. Having done some research, it seems impossible to do this with Core Data, because Core Data only supports bounding-box style queries, not predicates with blocks.
For example, I have a class of Groups with latitude and longitude properties. Given the latitude and longitude (of, say, a user), fetch all groups that are within a 6 mile radius of the given latitude and longitude.
class Group{
var latitude: Float
var longitude: Float
}
I'd like to take advantage of Core Data's R-Tree Indexing to do a fast bounding-box query on the latitudes and longitudes of instances of my class near my user. Then I'd like to filter the results with a more precise predicate, using my own block of code to see which of the instances are within my users current location. Here's the "Bounding box" query.
let request: NSFetchRequest<Group> = Group.fetchRequest()
let (topLeft,bottomRight) = boundingBox(center: center, radius: searchRadius)
let maxLat = topLeft.latitude
let minLon = topLeft.longitude
let minLat = bottomRight.latitude
let maxLon = bottomRight.longitude
let predicate = NSPredicate(format: "(%f < longitude AND longitude < %f) AND (%f < latitude AND latitude < %f)", minLon, maxLon, minLat, maxLat)
request.predicate = predicate
The problem is that I'd like a fetch that looked like this:
let location: CLLocation = /* Initialize a CLLocation */
let predicate = NSPredicate { (obj, _) -> Bool in
let object = obj as! Group
let objLocation = CLLocation(latitude: Double(object.latitude), longitude: Double(object.longitude))
return location.distance(from: objLocation) < 9656 //6 miles in meters
}
NSFetched results controller doesn't allow predicate with block. There's a significant difference between these two fetches. The first gets all groups in a Bounding Box, (the minLat, minLon, maxLat, and maxLat), the latter gets all groups in a Circle of a given radius.
I want to then use an NSFetchedRequestController to display the results in a table, and take advantage of the nice auto-update features. But of course, Core Data only supports bounding-box style queries, not the two-step filter method I need. Is there a proper solution?
I'm open to using other databases, if Core Data simply won't work with this type of use. I took a look at YapDatabase, and it seems more flexible, and includes R-Tree indexing, but I'm concerned that it's not well supported. Realm doesn't support R-Tree Indexing.
I am using Azure Maps and the javascript atlas library:
https://learn.microsoft.com/en-us/javascript/api/azure-maps-control/atlas?view=azure-maps-typescript-latest
Below code returns undefined when i access bbox property of Polygon class:
var hull = atlas.math.getConvexHull(positions);
var boundingBox = hull.bbox //returns undefined.
var polygon = new atlas.data.Polygon(positions);
var bBox = polygon.bbox //returns undefined even here.
Code which works is:
var boundingBox = atlas.data.BoundingBox.fromPositions(positions); //Works fine.
I need to calculate centroid from convex hull using:
var centroid = atlas.data.BoundingBox.getCenter(hull.bbox)
Can anyone please help me.
Thanks.
The bbox property of a feature is only defined if it was defined/calculated directly, often this is populated in GeoJSON files and thus would be populated when read in. By default the map does not populate this field if it isn't already populated as it would mean a lot of unnecessary calculations in majority of apps.
For your scenario you would do this:
var hull = atlas.math.getConvexHull(positions);
var boundingBox = atlas.data.BoundingBox.fromData(hull);
var centroid = atlas.data.BoundingBox.getCenter(boundingBox);
Here is a similar sample: https://azuremapscodesamples.azurewebsites.net/index.html?sample=Polygon%20labels%20-%20calculated
If you are looking to place a label on the center of the polygon, you might also want to consider this approach: https://azuremapscodesamples.azurewebsites.net/index.html?sample=Polygon%20labels%20-%20symbol%20layer
I have a set of polygon points that have the SpatialReferences.WebMercator property. I need to convert these points to SpatialReferences.Wgs84 before saving to a database. Ideally I would just keep the WebMercator setting, but the existing database is using the Wgs84 format.
I am using the GeometryEngine class, but I noticed that once I reload the polygon, it is off by some way. It is in a different location. How can I make sure this conversion is accurate?
MapPoint point = new MapPoint(lon, lat, SpatialReferences.WebMercator);
MapPoint convertedPoint = (MapPoint)GeometryEngine.Project(point, SpatialReferences.Wgs84);
So as an example, I just drew a polygon with points -33.9360095288856 18,391141081041, -33,9075206517435 18,390454436898, -33,9303125156119 18,423413355855
After performing the conversion, the points became -36.1141869553583 18.0832273300021, -36.0798547481093 18.0825746003061, -36.1073205139085 18.113902885547
I am trying to pull data from an Entity called latLongInfo and trying to get all the results with the lattitude results within a certain range. Below code should work but it's not:
Filter lowerLatF = new FilterPredicate("lat", FilterOperator.GREATER_THAN, botLat);
Filter topLatF = new FilterPredicate("lat", FilterOperator.LESS_THAN, topLat);
Filter twoFilter = CompositeFilterOperator.and(lowerLatF, topLatF);
Query rip = new Query("latLongInfo").setFilter(twoFilter);
PreparedQuery ripQ = datastore.prepare(rip);
List<Entity> llResult = ripQ.asList(FetchOptions.Builder.withLimit(15));
int sizeOfList=llResult.size();
The value of botLat is 40.94495459565217 and the value of topLat is 41.3797372043.
In the Datastore that I am pulling the data from there's a result with lat = 41.1623459 however, the code above doesn't find it and keeps giving me a sizeOfList = 0.
I should be getting at least one result but it's not returning it. Is there something simple I am missing?
I figured this out. I was saving the lat as String rather than a numerical float or double. Once i changed it to save doubles (these were actually converted to floats in the datastore) I was able to do the comparison without issue.
Decided to answer my own question...in case this helps anyone else.
I'm struggling with the best way of changing the center point of a 3D object (Model3DGroup) in WPF.
I've exported a model from SketchUp and everything is fine, but the centers got off position, causing me trouble in rotating the objects.
Now I need to make some rotations around each object own center and have no idea on how to do it...
Any suggestions would be appreciated.
Thanks
Using Jackson Pope suggestion, I used the code below to get the center point of an object:
var bounds = this.My3DObject.Bounds;
var x = bounds.X + (bounds.SizeX / 2);
var y = bounds.Y + (bounds.SizeY / 2);
var z = bounds.Z + (bounds.SizeZ / 2);
var centerPoint = new Point3D(x, y, z);
Meanwhile I'll try find a better solution to try and move all the points to the desired offset...
To rotate an object around it's centre you need to first translate it so that its centre is at the origin. Then rotate it (and then potentially translate it back to its original position).
Find the minimum and maximum extent of the object, calculate its centre = min + (max-min)/2. Translate by (-centreX, -centreY, -centreZ), rotate and then translate by (centreX, centreY, centreZ).