diff --git a/lib/src/layer/polygon_layer.dart b/lib/src/layer/polygon_layer.dart index fc3c0e285..8d19eb9e4 100644 --- a/lib/src/layer/polygon_layer.dart +++ b/lib/src/layer/polygon_layer.dart @@ -11,6 +11,17 @@ enum PolygonLabelPlacement { polylabel, } +bool isClockwise(List points) { + double sum = 0; + for (int i = 0; i < points.length; ++i) { + final a = points[i]; + final b = points[(i + 1) % points.length]; + + sum += (b.longitude - a.longitude) * (b.latitude + a.latitude); + } + return sum >= 0; +} + class Polygon { final List points; final List>? holePointsList; @@ -27,6 +38,10 @@ class Polygon { final TextStyle labelStyle; final PolygonLabelPlacement labelPlacement; final bool rotateLabel; + // Designates whether the given polygon points follow a clock or anti-clockwise direction. + // This is respected during draw call batching for filled polygons. Otherwise, batched polygons + // of opposing clock-directions cut holes into each other leading to a leaky optimization. + final bool _filledAndClockwise; LatLngBounds? _boundingBox; LatLngBounds get boundingBox { @@ -49,19 +64,21 @@ class Polygon { this.labelStyle = const TextStyle(), this.labelPlacement = PolygonLabelPlacement.centroid, this.rotateLabel = false, - }); + }) : _filledAndClockwise = isFilled && isClockwise(points); /// Used to batch draw calls to the canvas. int get renderHashCode => Object.hash( - holePointsList, - color, - borderStrokeWidth, - borderColor, - isDotted, - isFilled, - strokeCap, - strokeJoin, - labelStyle); + holePointsList, + color, + borderStrokeWidth, + borderColor, + isDotted, + isFilled, + strokeCap, + strokeJoin, + labelStyle, + _filledAndClockwise, + ); } class PolygonLayer extends StatelessWidget { diff --git a/test/layer/polygon_layer_test.dart b/test/layer/polygon_layer_test.dart index 4291039f5..d59983624 100644 --- a/test/layer/polygon_layer_test.dart +++ b/test/layer/polygon_layer_test.dart @@ -16,10 +16,10 @@ void main() { borderColor: Colors.purple, borderStrokeWidth: 4, label: '$i', - points: [ - const LatLng(55.5, -0.09), - const LatLng(54.3498, -6.2603), - const LatLng(52.8566, 2.3522), + points: const [ + LatLng(55.5, -0.09), + LatLng(54.3498, -6.2603), + LatLng(52.8566, 2.3522), ], ), ]; @@ -35,4 +35,15 @@ void main() { of: find.byType(PolygonLayer), matching: find.byType(CustomPaint)), findsOneWidget); }); + + test('polygon normal/rotation', () { + const clockwise = [ + LatLng(30, 20), + LatLng(30, 30), + LatLng(20, 30), + LatLng(20, 20), + ]; + expect(isClockwise(clockwise), isTrue); + expect(isClockwise(clockwise.reversed.toList()), isFalse); + }); }