6

I can query and get nearest locations to the client with degrees:

serviceQuery = serviceQuery.Where(s => s.Location.Distance(currentLocation) < <degree>)
    .OrderBy(s => s.Location.Distance(currentLocation));

Location is NetTopologySuite.Geometries.Point type in C# and geography in SQL Server.

How can I provide meter instead of degree in query and also get meter distance instead of degree? Converting the result degree to meter on client-side is acceptable.

Sasan
  • 3,840
  • 1
  • 21
  • 34

2 Answers2

2

I found out the problem.

PostgreSQL (that we are using now) and probably other databases have two types for spatial data: Geometry and Geography.

You can refer to these links for more information (Link 1, Link 2).

Long story short, if you are working with earth's lat/long and you want your calculations to use meter unit, you need to use the Geography type.

Attribute:

[Column(TypeName="geography (point)")]
public Point Location { get; set; }

Fluent API:

builder.Entity<YourEntity>()
    .Property(e => e.Location)
    .HasColumnType("geography (point)");

If you don't specify, the default would be Geometry which is for Cartesian coordinates.

And by the way, the SRID of the database data must be the same as the location you use for query.

Sasan
  • 3,840
  • 1
  • 21
  • 34
0

As far as I understand, it is important which SRID (spatial reference system) is used when inserting the geocoordinates. This documentation is somewhat helpful: https://learn.microsoft.com/en-us/ef/core/modeling/spatial

I'm using this code for SRID 4326:

public static Point CreatePoint(double latitude, double longitude)
{
    // 4326 is most common coordinate system used by GPS/Maps
    var geometryFactory = NtsGeometryServices.Instance.CreateGeometryFactory(srid: 4326);

    // see https://learn.microsoft.com/en-us/ef/core/modeling/spatial
    // Longitude and Latitude
    var newLocation = geometryFactory.CreatePoint(new Coordinate(longitude, latitude));

    return newLocation;
}

Assuming that you create currentLocation in SRID 4326 as well:

var currentLocation = CreatePoint(...

Then,

var meters = 500;
serviceQuery = serviceQuery
    .Where(s => s.Location.Distance(currentLocation) < meters )
    .OrderBy(s => s.Location.Distance(currentLocation));

should work

citronas
  • 19,035
  • 27
  • 96
  • 164
  • 2
    This seems to return the distance in degrees for me, instead of meters – Bassie Feb 24 '21 at 13:14
  • 1
    It does for me too. Can't figure out why, but doing this directly in sql gives me the correct units. – Jake Smith Mar 14 '22 at 22:45
  • That is expected, you need to project the coordinates to a different system https://learn.microsoft.com/en-us/ef/core/modeling/spatial#srid-ignored-during-client-operations – Marcin Jan 16 '23 at 13:06