flutter_map icon indicating copy to clipboard operation
flutter_map copied to clipboard

feat: change label placement configuration, add new 'signed area centroid' algorithm, and use new polylabel implementation

Open tidu090 opened this issue 6 months ago • 9 comments

This PR updates the logic used to compute the center of a label by replacing the previous average-based approach with a more accurate polygon centroid calculation.

Motivation Previously, the centroid was calculated by simply averaging all latitudes and longitudes of the polygon points. While this works for simple shapes, it often results in inaccurate label placement for complex or non-convex polygons. The new approach computes the geometric centroid using the signed area formula, which takes the shape of the polygon into account and gives a more accurate center for label placement.

Changes

Replaced the averaging method with a proper polygon centroid computation that: Uses the shoelace formula to calculate the signed area. Computes the weighted average of all vertices to determine the centroid. Falls back to averaging in the rare case of zero area (e.g., collinear points). Handles edge cases such as empty or single-point input.

Reproduction Attached is a screenshot showing the issue with the previous approach. The following sample coordinates help reproduce the difference: [ { "lat": -6.148970663625812, "lng": -80.00502973729147 }, { "lat": -6.151999579408217, "lng": -80.00502266917418 }, { "lat": -6.151996562581506, "lng": -80.00344874575943 }, { "lat": -6.148972613882413, "lng": -80.00346259720905 }, { "lat": -6.148970663625812, "lng": -80.00502973729147 } ]

[ { "lat": -6.148979805893571, "lng": -80.00337467617543 }, { "lat": -6.151993401453232, "lng": -80.00337910858363 }, { "lat": -6.151989815157336, "lng": -80.00179839899332 }, { "lat": -6.148963739527827, "lng": -80.00180957676228 }, { "lat": -6.148979805893571, "lng": -80.00337467617543 } ] Screenshot 2025-05-30 at 4 28 35 PM

tidu090 avatar May 30 '25 11:05 tidu090

Hi @JaffaKetchup this MR requires your attention please review and let me know your feedback Thanks

tidu090 avatar Jun 02 '25 12:06 tidu090

Hi @tidu090, we can't promise any timelines (I'm particularly busy atm), but we'll see what we can do.

It looks like you've got a formatting issue. Can you run the formatter, push, then I can test it out?

JaffaKetchup avatar Jun 02 '25 12:06 JaffaKetchup

@JaffaKetchup ran the formatter should pass now, thank you for your attention!

tidu090 avatar Jun 02 '25 16:06 tidu090

@tidu090 I've made some of the changes I suggested. Your new algorithm is in 'centroid.dart'. The changes have resolved a TODO, and made the label placement system much more extensible.

The only part remaining is whether this can support multi-worlds. Do you think this is possible with your algorithm? If not, I think I'm OK with this.

This will now need a review from another @fleaflet/maintainers since I've made a lot of changes.

JaffaKetchup avatar Jun 03 '25 14:06 JaffaKetchup

@JaffaKetchup thank you for your feedback I will declare a new enum set for user to switch between old & new algo, those changes I will be doing tomorrow. Thank you once again happy to contribute!

Btw I have this question if you can't review this PR anymore who will merge it then?

tidu090 avatar Jun 03 '25 15:06 tidu090

No need to make a new enum anymore, just need the multi-world implementation if possible. You can copy CentroidCalculator and call the new copy MultiWorldCentroidCalculator. Then change the implementation of call in the new one.

The other maintainers are a little busy at the moment, but hopefully at some point quite soon we can get through this backlog of PRs and release v8.2. i.e. the other maintainers can review and merge.

JaffaKetchup avatar Jun 03 '25 15:06 JaffaKetchup

Cool I will work on that

tidu090 avatar Jun 03 '25 15:06 tidu090

(Reminder to self: this needs to be added to the CHANGELOG)

JaffaKetchup avatar Jun 08 '25 21:06 JaffaKetchup

@fleaflet/maintainers I've also changed the polylabel implementation to my own new port (https://github.com/JaffaKetchup/dart_polylabel2). Its similar to the first, but fixes the licensing issue & performance issues (and doesn't rely on 'dart:math's Point). It still requires that list generation to convert from latlong to xy, but I didn't want to tie it to latlong, so I think it's a good middle ground.

It also fixes the TODO of allowing the 'precision'/'threshold' to be customized externally.

JaffaKetchup avatar Jun 10 '25 12:06 JaffaKetchup