EF Core Spatial Data: Query and get distances in meters
Asked Answered
R

3

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.

Ranit answered 27/4, 2020 at 5:30 Comment(0)
R
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.

Ranit answered 2/2, 2021 at 13:39 Comment(0)
M
1

In most spatial databases, there are two distinct data types for spatial data:

  1. GEOMETRY: Represents data in a flat Cartesian plane. This type is suitable for scenarios where spatial features are on a flat surface, such as floor plans, small-scale maps, etc. When you perform distance calculations using the GEOMETRY type, the units returned are often in the "spatial units" of that plane, which could be any arbitrary unit depending on the spatial reference system. In most cases, it could be degrees, especially if you're mistakenly using it for lat-long values.

  2. GEOGRAPHY: Represents data on a round earth surface (spheroid). This type is designed for scenarios involving larger geographic areas such as locations on the earth. When you perform distance calculations using the GEOGRAPHY type, it naturally understands the earth's curvature and will return distances in meters.

From your problem statement, it seems some of your data points were stored using the GEOMETRY type, while others were stored using the GEOGRAPHY type. The solution is to ensure that all your spatial data that represents locations on earth should be stored using the GEOGRAPHY type. By doing so, distance calculations will consistently return values in meters.

Minuend answered 6/9, 2023 at 1:15 Comment(0)
C
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

Caplan answered 27/4, 2020 at 7:27 Comment(3)
This seems to return the distance in degrees for me, instead of metersNocturn
It does for me too. Can't figure out why, but doing this directly in sql gives me the correct units.Organzine
That is expected, you need to project the coordinates to a different system learn.microsoft.com/en-us/ef/core/modeling/…Obligato

© 2022 - 2025 — McMap. All rights reserved.