CoordinateSharp icon indicating copy to clipboard operation
CoordinateSharp copied to clipboard

GeoJson "right hand rule" listing longitude first (GeoFence.Point)

Open houstonhaynes opened this issue 1 year ago • 5 comments

Is your feature request related to a problem? Please describe. It would be nice to have a convenience feature to have a GeoFence.Point (or GeoFence.RightHandPoint) that would provide 'longitude, latitude' as a tuple for outer-bound GeoJson closed geometries.

Describe the solution you'd like It was a little awkward getting a GeoJson object out of a list of GeoFence.Point s. I had to switch out to handling the individual fields, which is not a terrible inconvenience. However, it would be nice to have a means to get back a Point "right handed" for creating geo-plots

Describe alternatives you've considered See the screenshot of my F# code. I created a "rightHandPoint" type with passed it around the functions.

Additional context None Screenshot 2024-07-02 152217 Screenshot 2024-07-02 152327 Screenshot 2024-07-02 152547

houstonhaynes avatar Jul 02 '24 19:07 houstonhaynes

Hi Houston,

I hope all is well with you.

Just to make sure I understand the problem correctly.

  1. You need to the ability to reorder the GeoFence.Points collection for right-handedness.
  2. You need a Tuple<double, double> collection returned instead of a GeoFence.Point collection as it's more convenient to work with.

If I am understanding this correctly, it may be best to place a method within GeoFence class that reorders points for right handedness due to how it works, and then create a method that returns a Tuple (and another that returns an array as some may what that).

I think this makes sense, and I am actually surprised it's never been asked as I can see how this would be convenient. Let me know if I am not understanding correctly though.

Tronald avatar Jul 02 '24 20:07 Tronald

That's a great description, and yes, that sounds pretty on-point. 👍

As a sidebar I also spotted that "outer" rings are enumerated counterclockwise and inner rings are clockwise (in terms of order of pairings) though I don't have any reference as to why that requirement exists. If there was ever an interest in building a helper that would provide a GeoJson object there's that little tidbit to consider. 🤔

houstonhaynes avatar Jul 02 '24 21:07 houstonhaynes

Thanks for that tidbit. Looks like spec interprets the clockwise rings as holes so that it doesn't treat is as an overlapping boundary in a polygon collection I guess. Makes sense. The GeoFence class isn't advanced enough to determine holes on its own, but this could be a great concept to expand the library.

Lefthanded and Righthanded outputs should be easy. I will have to explore what going beyond that to have a GeoJson helper would entail. That would be a nice feature though. Thanks for the suggestion.

Tronald avatar Jul 02 '24 23:07 Tronald

Absolutely. I really appreciate your work. 🔧 😃

FWIW - the current application is to create these polygons to feed into the OpenWeatherMap "Trigger" API to set locale (and datetime) boundaries to evaluate for conditions and provide notifications for weather changes. In my immediate case it's for an #IoT device that senses rainfall/wind and triggers the state of an motorized awning - mainly to retract the awning via a hacked remote control. But in the bigger picture there's a handful of other state-related management tasks I'm considering. I may set the 10 foot X 20 foot awning to partially retract in order to reduce exposure and make the "final" retraction into the wall-mounted cassette take less time as local events dictate.

Another application is to set triggers for parking a motor-positioned solar panel when wind exceeds a threshold. This too will be based on forecast - where the trigger is based on conditions existing before I take that protective action. And of course there's the situation of restoring the position of the panel (similarly with the awning) once the adverse conditions have cleared.

It's been really rewarding to work with CoordinateSharp and the OpenWeatherMaps API in F#. 🚀 😁

houstonhaynes avatar Jul 03 '24 01:07 houstonhaynes

We are getting close with the following features, we just need to build out documentation and unit tests.

  1. Right hand ordering of a GeoFence .
  2. Left hand ordering of a GeoFence.
  3. Closing of a GeoFence (to close the shape after it's ordered).
  4. Centroid of a GeoFence (to get the center point).
  5. GeoJson string builder.

Basically, the way it will work is, you will create your outer fence then inner fences as separate GeoFence objects. Then you will call GeoFence.GeoJsonPolygonBuilder(outerFence, List<GeoFence> innerFences) and it will create a GeoJson polygon string.

It will be limited to polygons for now, but will consider multipolygons once this has been tested for a bit to ensure simple polygons are behaving correctly.

Tronald avatar Oct 12 '24 19:10 Tronald

Feature pushed with v3.1.1.1

Library available on nuget.org

// Create the outer boundary and order (right-handed)
List<GeoFence.Point> outerPoints = new List<GeoFence.Point>
{
    new Coordinate(47.6062, -122.3321),  // Seattle
    new Coordinate(48.7519, -122.4787),  // Bellingham
    new Coordinate(47.2529, -122.4443),  // Tacoma
    new Coordinate(48.0419, -122.9025),  // Port Townsend
    new Coordinate(47.6588, -117.4260),  // Spokane
    new Coordinate(46.6021, -120.5059),  // Yakima
    new Coordinate(46.7324, -117.0002),  // Pullman
    new Coordinate(48.3102, -122.6290),  // Anacortes
    new Coordinate(47.8225, -122.3123),  // Edmonds
    new Coordinate(46.9787, -123.8313),  // Aberdeen
    new Coordinate(47.0379, -122.9007),  // Olympia
    new Coordinate(47.6091, -122.2015),  // Bellevue
    new Coordinate(47.6787, -120.7141),  // Leavenworth
    new Coordinate(48.0812, -123.2643),  // Port Angeles
    new Coordinate(46.7152, -122.9522)   // Centralia
};

GeoFence outerFence = new GeoFence(outerPoints);
outerFence.OrderPoints_RightHanded();

//Ensure polygon is always closed
outerFence.ClosePolygon();

// Create an inner boundary and order (left-handed)
List<Coordinate> innerPoints = new List<Coordinate>()
{
    new Coordinate(46.8523, -121.7603),  // Mount Rainier (center point)
    new Coordinate(46.8625, -121.7401),  // Slightly north-east
    new Coordinate(46.8421, -121.7805),  // Slightly south-west
    new Coordinate(46.8650, -121.7850),  // North-west
    new Coordinate(46.8400, -121.7500)   // South-east
};
GeoFence innerFence = new GeoFence(innerPoints);
innerFence.OrderPoints_LeftHanded();

//Ensure polygon is always closed
innerFence.ClosePolygon();

// Build the GeoJSON polygon with the outer and inner boundaries
string geoJson = GeoFence.GeoJsonPolygonBuilder(outerFence, new List<GeoFence> { innerFence });

Tronald avatar Nov 17 '24 22:11 Tronald