Reputation: 5159
I'm querying a table in SQL Server to show results on Google Maps, and I'm using Entity Framework and DbGeography data types on the server application.
Simply, I get the map bounds from the Google Maps instance, construct a DbGeography instance from it using something like this:
var wkt = string.Format("POLYGON(({0} {1}, {0} {2}, {3} {2}, {3} {1}, {0} {1}))", EastLng, NorthLat, SouthLat, WestLng);
var bounds = DbGeography.FromText(wkt);
And then query the database using this (as a part of a larger query):
dbset.Where(i => bounds.Intersects(l.GeographicLocation));
This works fine, and I actually have it working in production for a while. Today I noticed that sometimes some results don't show up correctly on the map.
After some investigation, I realized that it is because the earth's curvature; Google Maps uses a rectangular projection of the earth, but what when I create a rectangular polygon, it means a shape like this (copied from SQL Server Management Studio, from the query that was running):
The effect is increased when looking at maps of very large areas (zooming out). But when I zoom in, the effect of earth's curvature decreases and query seems to work fine.
What I need to do, is to basically query the DB for all points that lie within a Lat/Lng boundary. Is there a way to do this?
EDIT:
This is the complete code that I'm using to create a DbGeography instance:
public class LatLngBounds
{
// ...
public DbGeography ToDbGeography()
{
return DbGeographyUtil.CreatePolygon(string.Format("POLYGON(({0} {1}, {0} {2}, {3} {2}, {3} {1}, {0} {1}))", EastLng, NorthLat, SouthLat, WestLng));
}
}
public static class DbGeographyUtil
{
public static DbGeography CreatePolygon(string wktString)
{
if (string.IsNullOrWhiteSpace(wktString))
return null;
var sqlGeography = SqlGeography.STGeomFromText(new SqlChars(wktString), DbGeography.DefaultCoordinateSystemId).MakeValid();
var invertedSqlGeography = sqlGeography.ReorientObject();
if (sqlGeography.STArea() > invertedSqlGeography.STArea())
{
sqlGeography = invertedSqlGeography;
}
return DbSpatialServices.Default.GeographyFromProviderValue(sqlGeography);
}
}
EDIT 2:
The coordinates coming out of Google Maps in the above example is:
This is a part of the query that was running, that I captured using SQL Server Profiler:
declare @p4 sys.geography
set @p4=convert(sys.geography,0xE6100000010405000000463E933FAFD64A40070000006E3F354061E412079A894140070000006E3F354061E412079A894140020000808B245740463E933FAFD64A40020000808B245740463E933FAFD64A40070000006E3F354001000000020000000001000000FFFFFFFF0000000003)
SELECT @p4;
(I added the SELECT
to see how it looks like, and resulted in the image above)
Upvotes: 4
Views: 1420
Reputation: 51
I manage to solve this by using DbGeometry instead of DbGeography
var boundsAsGeometry = DbGeometry.FromText(bounds.AsText(), bounds.CoordinateSystemId);
dbset.Where(x => boundsAsGeometry.Intersects(DbGeometry.FromText(x.GeographicLocation.AsText(), x.GeographicLocation.CoordinateSystemId)));
Be aware that this will not use the existing db index for the GeographicLocation field if you have that.
Upvotes: 1