diff --git a/lib/src/layer/misc/line_patterns/pixel_hiker.dart b/lib/src/layer/misc/line_patterns/pixel_hiker.dart index 4eb4efb05..46b6902ff 100644 --- a/lib/src/layer/misc/line_patterns/pixel_hiker.dart +++ b/lib/src/layer/misc/line_patterns/pixel_hiker.dart @@ -13,6 +13,7 @@ class DottedPixelHiker extends _PixelHiker { required super.closePath, required super.canvasSize, required super.patternFit, + required super.strokeWidth, required double stepLength, }) : super(segmentValues: [stepLength]); @@ -25,7 +26,7 @@ class DottedPixelHiker extends _PixelHiker { } void addVisibleOffset(final Offset offset) { - if (VisibleSegment.isVisible(offset, canvasSize)) { + if (VisibleSegment.isVisible(offset, canvasSize, strokeWidth)) { result.add(offset); } } @@ -69,8 +70,8 @@ class DottedPixelHiker extends _PixelHiker { /// /// Most important method of the class. List? _getVisibleDotList(Offset offset0, Offset offset1) { - final VisibleSegment? visibleSegment = - VisibleSegment.getVisibleSegment(offset0, offset1, canvasSize); + final VisibleSegment? visibleSegment = VisibleSegment.getVisibleSegment( + offset0, offset1, canvasSize, strokeWidth); if (visibleSegment == null) { addDistance(getDistance(offset0, offset1)); return null; @@ -131,6 +132,7 @@ class DashedPixelHiker extends _PixelHiker { required super.canvasSize, required super.segmentValues, required super.patternFit, + required super.strokeWidth, }); /// Returns all visible segments. @@ -155,7 +157,7 @@ class DashedPixelHiker extends _PixelHiker { if (_segmentIndex.isOdd) { if (patternFit == PatternFit.appendDot) { if (!closePath) { - if (VisibleSegment.isVisible(offsets.last, canvasSize)) { + if (VisibleSegment.isVisible(offsets.last, canvasSize, strokeWidth)) { result.add(VisibleSegment(offsets.last, offsets.last)); } } @@ -187,10 +189,7 @@ class DashedPixelHiker extends _PixelHiker { final Offset offset1, ) { final VisibleSegment? visibleSegment = VisibleSegment.getVisibleSegment( - offset0, - offset1, - canvasSize, - ); + offset0, offset1, canvasSize, strokeWidth); if (visibleSegment == null) { addDistance(getDistance(offset0, offset1)); return null; @@ -257,17 +256,30 @@ class SolidPixelHiker extends _PixelHiker { required super.offsets, required super.closePath, required super.canvasSize, + required super.strokeWidth, }) : super( segmentValues: [], patternFit: PatternFit.none, ); - /// Returns all visible segments. - List getAllVisibleSegments() { - final List result = []; - + /// Adds all visible segments to [paths]. + void addAllVisibleSegments(final List paths) { if (offsets.length < 2) { - return result; + return; + } + + double? latestX; + double? latestY; + List polygons = []; + + void addPolygons() { + if (polygons.isEmpty) { + return; + } + for (final path in paths) { + path.addPolygon(polygons, false); + } + polygons = []; } for (int i = 0; i < offsets.length - 1 + (closePath ? 1 : 0); i++) { @@ -275,13 +287,21 @@ class SolidPixelHiker extends _PixelHiker { offsets[i], offsets[(i + 1) % offsets.length], canvasSize, + strokeWidth, ); - if (visibleSegment != null) { - result.add(visibleSegment); + if (visibleSegment == null) { + continue; + } + if (latestX != visibleSegment.begin.dx || + latestY != visibleSegment.begin.dy) { + addPolygons(); + polygons.add(visibleSegment.begin); } + polygons.add(visibleSegment.end); + latestX = visibleSegment.end.dx; + latestY = visibleSegment.end.dy; } - - return result; + addPolygons(); } @override @@ -296,6 +316,7 @@ sealed class _PixelHiker { required this.closePath, required this.canvasSize, required this.patternFit, + required this.strokeWidth, }) { _polylinePixelDistance = _getPolylinePixelDistance(); _init(); @@ -314,6 +335,7 @@ sealed class _PixelHiker { final List segmentValues; final Size canvasSize; final PatternFit patternFit; + final double strokeWidth; /// Factor to be used on offset distances. late final double _factor; diff --git a/lib/src/layer/misc/line_patterns/visible_segment.dart b/lib/src/layer/misc/line_patterns/visible_segment.dart index 6c255f36a..e4c69e1cf 100644 --- a/lib/src/layer/misc/line_patterns/visible_segment.dart +++ b/lib/src/layer/misc/line_patterns/visible_segment.dart @@ -39,23 +39,28 @@ class VisibleSegment { return code; } - /// Returns true if the [offset] is inside the [canvasSize]. - static bool isVisible(Offset offset, Size canvasSize) => + /// Returns true if the [offset] is inside the [canvasSize] + [strokeWidth]. + static bool isVisible(Offset offset, Size canvasSize, double strokeWidth) => _computeOutCode( - offset.dx, offset.dy, 0, 0, canvasSize.width, canvasSize.height) == + offset.dx, + offset.dy, + -strokeWidth / 2, + -strokeWidth / 2, + canvasSize.width + strokeWidth / 2, + canvasSize.height + strokeWidth / 2) == _inside; /// Clips a line segment to a rectangular area (canvas). /// /// Returns null if the segment is invisible. static VisibleSegment? getVisibleSegment( - Offset p0, Offset p1, Size canvasSize) { + Offset p0, Offset p1, Size canvasSize, double strokeWidth) { // Function to compute the outCode for a point relative to the canvas - const double xMin = 0; - const double yMin = 0; - final double xMax = canvasSize.width; - final double yMax = canvasSize.height; + final double xMin = -strokeWidth / 2; + final double yMin = -strokeWidth / 2; + final double xMax = canvasSize.width + strokeWidth / 2; + final double yMax = canvasSize.height + strokeWidth / 2; double x0 = p0.dx; double y0 = p0.dy; diff --git a/lib/src/layer/polygon_layer/painter.dart b/lib/src/layer/polygon_layer/painter.dart index c665a6bee..880daae99 100644 --- a/lib/src/layer/polygon_layer/painter.dart +++ b/lib/src/layer/polygon_layer/painter.dart @@ -215,6 +215,7 @@ class _PolygonPainter extends CustomPainter { size, canvas, _getBorderPaint(polygon), + polygon.borderStrokeWidth, ); } @@ -238,7 +239,7 @@ class _PolygonPainter extends CustomPainter { if (!polygon.disableHolesBorder && polygon.borderStrokeWidth > 0.0) { _addHoleBordersToPath(borderPath, polygon, holeOffsetsList, size, - canvas, _getBorderPaint(polygon)); + canvas, _getBorderPaint(polygon), polygon.borderStrokeWidth); } } @@ -314,6 +315,7 @@ class _PolygonPainter extends CustomPainter { Size canvasSize, Canvas canvas, Paint paint, + double strokeWidth, ) { final isSolid = polygon.pattern == const StrokePattern.solid(); final isDashed = polygon.pattern.segments != null; @@ -323,11 +325,9 @@ class _PolygonPainter extends CustomPainter { offsets: offsets, closePath: true, canvasSize: canvasSize, + strokeWidth: strokeWidth, ); - for (final visibleSegment in hiker.getAllVisibleSegments()) { - path.moveTo(visibleSegment.begin.dx, visibleSegment.begin.dy); - path.lineTo(visibleSegment.end.dx, visibleSegment.end.dy); - } + hiker.addAllVisibleSegments([path]); } else if (isDotted) { final DottedPixelHiker hiker = DottedPixelHiker( offsets: offsets, @@ -335,6 +335,7 @@ class _PolygonPainter extends CustomPainter { patternFit: polygon.pattern.patternFit!, closePath: true, canvasSize: canvasSize, + strokeWidth: strokeWidth, ); for (final visibleDot in hiker.getAllVisibleDots()) { canvas.drawCircle(visibleDot, polygon.borderStrokeWidth / 2, paint); @@ -346,6 +347,7 @@ class _PolygonPainter extends CustomPainter { patternFit: polygon.pattern.patternFit!, closePath: true, canvasSize: canvasSize, + strokeWidth: strokeWidth, ); for (final visibleSegment in hiker.getAllVisibleSegments()) { @@ -362,6 +364,7 @@ class _PolygonPainter extends CustomPainter { Size canvasSize, Canvas canvas, Paint paint, + double strokeWidth, ) { for (final offsets in holeOffsetsList) { _addBorderToPath( @@ -371,6 +374,7 @@ class _PolygonPainter extends CustomPainter { canvasSize, canvas, paint, + strokeWidth, ); } } diff --git a/lib/src/layer/polyline_layer/painter.dart b/lib/src/layer/polyline_layer/painter.dart index 58f5e7bac..db4c9ca52 100644 --- a/lib/src/layer/polyline_layer/painter.dart +++ b/lib/src/layer/polyline_layer/painter.dart @@ -147,6 +147,9 @@ class _PolylinePainter extends CustomPainter { needsLayerSaving = polyline.color.opacity < 1.0 || (polyline.gradientColors?.any((c) => c.opacity < 1.0) ?? false); + // strokeWidth, or strokeWidth + borderWidth if relevant. + late double largestStrokeWidth; + late final double strokeWidth; if (polyline.useStrokeWidthInMeter) { strokeWidth = _metersToStrokeWidth( @@ -158,6 +161,7 @@ class _PolylinePainter extends CustomPainter { } else { strokeWidth = polyline.strokeWidth; } + largestStrokeWidth = strokeWidth; final isSolid = polyline.pattern == const StrokePattern.solid(); final isDashed = polyline.pattern.segments != null; @@ -182,6 +186,7 @@ class _PolylinePainter extends CustomPainter { // Outlined lines are drawn by drawing a thicker path underneath, then // stenciling the middle (in case the line fill is transparent), and // finally drawing the line fill. + largestStrokeWidth = strokeWidth + polyline.borderStrokeWidth; borderPaint = Paint() ..color = polyline.borderColor ..strokeWidth = strokeWidth + polyline.borderStrokeWidth @@ -213,13 +218,9 @@ class _PolylinePainter extends CustomPainter { offsets: offsets, closePath: false, canvasSize: size, + strokeWidth: largestStrokeWidth, ); - for (final visibleSegment in hiker.getAllVisibleSegments()) { - for (final path in paths) { - path.moveTo(visibleSegment.begin.dx, visibleSegment.begin.dy); - path.lineTo(visibleSegment.end.dx, visibleSegment.end.dy); - } - } + hiker.addAllVisibleSegments(paths); } else if (isDotted) { final DottedPixelHiker hiker = DottedPixelHiker( offsets: offsets, @@ -227,6 +228,7 @@ class _PolylinePainter extends CustomPainter { patternFit: polyline.pattern.patternFit!, closePath: false, canvasSize: size, + strokeWidth: largestStrokeWidth, ); final List radii = []; @@ -249,6 +251,7 @@ class _PolylinePainter extends CustomPainter { patternFit: polyline.pattern.patternFit!, closePath: false, canvasSize: size, + strokeWidth: largestStrokeWidth, ); for (final visibleSegment in hiker.getAllVisibleSegments()) {