Tronald / CoordinateSharp

A library designed to ease geographic coordinate format conversions, and determine sun/moon information in C#
Other
365 stars 59 forks source link

Can we check if a coordinate is within non-square polygon? #235

Closed Matthew-Hiebing closed 6 months ago

Matthew-Hiebing commented 6 months ago

Dear Devs,

It looks like we can check if a coordinate is within a square-like shape but can we check if a point is within a more random shape? For example, I'd like to use this library to check whether a point is within the state of Utah. I have the coordinates Utah's six corners but they don't form a square.

Thanks, Matt

Tronald commented 6 months ago

Hi @Matthew-Hiebing

You can certainly do this. Check out the example here in the developer guide.

This example showcases 5 points to make a 4 sided square. Polygons require an extra point when defining the shape to "close" the shape. The first point and last point will be the same coordinate though.

In your case you would add 7 points to the points collection to make a 6 sided polygon.

Let me know if you need any help.

Matthew-Hiebing commented 6 months ago

Fantastic! I'll give it a try. Thanks!

Matthew-Hiebing commented 6 months ago

@Tronald, if I make a polygon over a large area (say Utah's boundary), does the IsPointInPolygon account for distances between meridians changing? For example, the horizontal distance between two points towards the equator is greater than the distance between those two points if they were near the north or south pole because the meridians are further apart near the equator and closer together near the poles. Does IsPointInPolygon account for this?

If this doesn't make sense let me know and I can provide more information.

Thanks, Matt

Tronald commented 6 months ago

@Matthew-Hiebing Fantastic question! It's a question so good in fact, that it revealed how much our documentation is lacking on this subject. I will note this so that it is updated.

The formula used is a simple 2D ray casting implementation, so you would definitely run into greater error across greater distance. This error margin would likely be very significant for a boundary as large as a state if you are truly using just the 6 corner points. I probably should have specified that in my first comment sorry.

The best way to combat this is with densification techniques, which involve plotting points along the polyline between your base points to mitigate the spherical distortion effects. The more points you have, the greater the accuracy, but in doing this you must weigh performance implications.

If you need help with densification, you may be able to automate the process by using the Moving a Coordinate features in the library. Basically you can start at one corner and then move towards another corner, plotting the points every X distance. You would likely have to determine when you are within the X distance of the last point though, or else the logic will pass the point and just keep going back and forth.

I have not personally tested this technique, but as the move logic does account for curvature I suspect it should work well unless you have high precision requirements (in which case a stronger GIS solution should be sought).

Reopening, as this revealed a document issue. Thanks for following up.

Tronald commented 6 months ago

Researching this further, a good feature would be an automated densification method.

List<GeoFence.Point> points = GeoFence.Densify(int distance, List<GeoFence.Point>);

Essentially, this would create the desired densification for the user to create an ehanced boundary that accounts for earth shape. This would still lack the precision of more advanced GIS tools, but it would be precise enough for many use cases. With this example, the developer could specify the level of densification needed to balance accuracy and performance.

Will work on this and see if it's a feasible feature.

Tronald commented 6 months ago

This will be fairly easy to implement, and performance seems decent. With that said, I know you may be needing work around in the mean time so here is a quick example using corners around Colorado.

I plotted the output on mapcustomizer.com and you can see the plots curving (the map projection there does not appear curved). This needs extensive testing, but its clear the method accounts for the curvature. If you decide to test this out let me know if you see anything negative.

Matthew-Hiebing commented 6 months ago

Sorry for the delay, had some other tickets intrude into this work :)

All of this sounds great. Super glad to hear we can account for the curvature of meridians lines. Its no problem for me to add a few more points along Utah's border to mitigate the spherical distortion effects. I'm not in a huge rush on this but I'd be willing to try the new Densify method you mentioned. If you get it into the code-base, great!

I appreciate you trying this on a another square-looking state like CO :)

Matt

Tronald commented 6 months ago

Densification method added with 2.23.1.1.

nuget: https://www.nuget.org/packages/CoordinateSharp/2.23.1.1

Example:

//Create a four point GeoFence around Utah
List<GeoFence.Point> points = new List<GeoFence.Point>();

points.Add(new GeoFence.Point(41.003444, -109.045223));
points.Add(new GeoFence.Point(41.003444, -102.041524));
points.Add(new GeoFence.Point(36.993076, -102.041524));
points.Add(new GeoFence.Point(36.993076, -109.045223));
points.Add(new GeoFence.Point(41.003444, -109.045223));

GeoFence gf = new GeoFence(points);

// Densify the geofence to plot a coordinate every 5 kilometers using Vincenty to account for Earth's shape
gf.Densify(new Distance(5, DistanceType.Kilometers));

NOTES: This system uses internal navigation methods that employ both the Haversine and Vincenty formulas to account for the Earth's shape. This will inherently cause your shapes to curve by design. However, it should be noted that map projections may have location-specific curvature or may not account for the Earth's curvature at all. As such, you may observe that the curvature does not always align with the map projection.

The current densification method only allows for default WGS84 ellipsoidal parameters within the densification calculations. Future releases will expand this feature to allow user specified earth shapes, which can help when using location specific projections.

It is up to each user to determine their accuracy, precision, and reliability requirements.