Skip to content

Commit

Permalink
Minor layout/style improvements
Browse files Browse the repository at this point in the history
  • Loading branch information
JaffaKetchup authored and ignatz committed Jan 21, 2024
1 parent 2fdccb4 commit 9e07d1f
Show file tree
Hide file tree
Showing 5 changed files with 96 additions and 97 deletions.
45 changes: 0 additions & 45 deletions lib/src/layer/polygon_layer/painter.dart
Original file line number Diff line number Diff line change
@@ -1,50 +1,5 @@
part of 'polygon_layer.dart';

class _ProjectedPolygon {
final Polygon polygon;
final List<DoublePoint> points;
final List<List<DoublePoint>>? holePoints;

const _ProjectedPolygon._({
required this.polygon,
required this.points,
this.holePoints,
});

_ProjectedPolygon.fromPolygon(Projection projection, Polygon polygon)
: this._(
polygon: polygon,
points: List<DoublePoint>.generate(
polygon.points.length,
(j) {
final (x, y) = projection.projectXY(polygon.points[j]);
return DoublePoint(x, y);
},
growable: false,
),
holePoints: () {
final holes = polygon.holePointsList;
if (holes == null) return null;

return List<List<DoublePoint>>.generate(
holes.length,
(j) {
final points = holes[j];
return List<DoublePoint>.generate(
points.length,
(k) {
final (x, y) = projection.projectXY(points[k]);
return DoublePoint(x, y);
},
growable: false,
);
},
growable: false,
);
}(),
);
}

class _PolygonPainter extends CustomPainter {
final List<_ProjectedPolygon> polygons;
final MapCamera camera;
Expand Down
48 changes: 22 additions & 26 deletions lib/src/layer/polygon_layer/polygon_layer.dart
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import 'package:polylabel/polylabel.dart'; // conflict with Path from UI
part 'label.dart';
part 'painter.dart';
part 'polygon.dart';
part 'projected_polygon.dart';

@immutable
class PolygonLayer extends StatefulWidget {
Expand Down Expand Up @@ -66,12 +67,10 @@ class _PolygonLayerState extends State<PolygonLayer> {
void didUpdateWidget(PolygonLayer oldWidget) {
super.didUpdateWidget(oldWidget);

// Reuse cache
if (widget.simplificationTolerance != 0 &&
oldWidget.simplificationTolerance == widget.simplificationTolerance &&
listEquals(oldWidget.polygons, widget.polygons)) {
// Reuse cache.
return;
}
listEquals(oldWidget.polygons, widget.polygons)) return;

_cachedSimplifiedPolygons.clear();
_cachedProjectedPolygons = null;
Expand All @@ -90,15 +89,13 @@ class _PolygonLayerState extends State<PolygonLayer> {
growable: false,
);

final zoom = camera.zoom.floor();

final simplified = widget.simplificationTolerance <= 0
? projected
: _cachedSimplifiedPolygons[zoom] ??= _computeZoomLevelSimplification(
camera.crs,
projected,
widget.simplificationTolerance,
zoom,
: _cachedSimplifiedPolygons[camera.zoom.floor()] ??=
_computeZoomLevelSimplification(
polygons: projected,
pixelTolerance: widget.simplificationTolerance,
camera: camera,
);

final culled = !widget.polygonCulling
Expand All @@ -122,16 +119,15 @@ class _PolygonLayerState extends State<PolygonLayer> {
);
}

static List<_ProjectedPolygon> _computeZoomLevelSimplification(
Crs crs,
List<_ProjectedPolygon> polygons,
double pixelTolerance,
int zoom,
) {
static List<_ProjectedPolygon> _computeZoomLevelSimplification({
required List<_ProjectedPolygon> polygons,
required double pixelTolerance,
required MapCamera camera,
}) {
final tolerance = getEffectiveSimplificationTolerance(
crs,
zoom,
pixelTolerance,
crs: camera.crs,
zoom: camera.zoom.floor(),
pixelTolerance: pixelTolerance,
);

return List<_ProjectedPolygon>.generate(
Expand All @@ -143,18 +139,18 @@ class _PolygonLayerState extends State<PolygonLayer> {
return _ProjectedPolygon._(
polygon: polygon.polygon,
points: simplifyPoints(
polygon.points,
tolerance,
highestQuality: true,
points: polygon.points,
tolerance: tolerance,
highQuality: true,
),
holePoints: holes == null
? null
: List<List<DoublePoint>>.generate(
holes.length,
(j) => simplifyPoints(
holes[j],
tolerance,
highestQuality: true,
points: holes[j],
tolerance: tolerance,
highQuality: true,
),
growable: false,
),
Expand Down
47 changes: 47 additions & 0 deletions lib/src/layer/polygon_layer/projected_polygon.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
part of 'polygon_layer.dart';

@immutable
class _ProjectedPolygon {
final Polygon polygon;
final List<DoublePoint> points;
final List<List<DoublePoint>>? holePoints;

const _ProjectedPolygon._({
required this.polygon,
required this.points,
this.holePoints,
});

_ProjectedPolygon.fromPolygon(Projection projection, Polygon polygon)
: this._(
polygon: polygon,
points: List<DoublePoint>.generate(
polygon.points.length,
(j) {
final (x, y) = projection.projectXY(polygon.points[j]);
return DoublePoint(x, y);
},
growable: false,
),
holePoints: () {
final holes = polygon.holePointsList;
if (holes == null) return null;

return List<List<DoublePoint>>.generate(
holes.length,
(j) {
final points = holes[j];
return List<DoublePoint>.generate(
points.length,
(k) {
final (x, y) = projection.projectXY(points[k]);
return DoublePoint(x, y);
},
growable: false,
);
},
growable: false,
);
}(),
);
}
7 changes: 4 additions & 3 deletions lib/src/layer/polyline_layer/polyline_layer.dart
Original file line number Diff line number Diff line change
Expand Up @@ -131,14 +131,15 @@ class _PolylineLayerState<R extends Object> extends State<PolylineLayer<R>> {
);
}

// TODO BEFORE v7: Use same algorithm as polygons
List<Polyline<R>> _computeZoomLevelSimplification(int zoom) =>
_cachedSimplifiedPolylines[zoom] ??= widget.polylines
.map(
(polyline) => polyline.copyWithNewPoints(
simplify(
polyline.points,
widget.simplificationTolerance / math.pow(2, zoom),
highestQuality: true,
points: polyline.points,
tolerance: widget.simplificationTolerance / math.pow(2, zoom),
highQuality: true,
),
),
)
Expand Down
46 changes: 23 additions & 23 deletions lib/src/misc/simplify.dart
Original file line number Diff line number Diff line change
@@ -1,13 +1,16 @@
// implementation based on
// https://github.com/mourner/simplify-js/blob/master/simplify.js

import 'dart:math' as math;

import 'package:flutter_map/src/geo/crs.dart';
import 'package:latlong2/latlong.dart';
import 'package:meta/meta.dart';

// Custom point due to math.Point<double> being slow. Math operations tend to
// have 20+x penalty for virtual function overhead given the reified nature of
// Dart generics.
@internal
class DoublePoint {
// Note: Allow mutability for reuse/pooling to reduce GC pressure and increase performance.
// Geometry operations should be safe-by-default to avoid accidental bugs.
Expand Down Expand Up @@ -55,6 +58,7 @@ double getSqSegDist(
return dx * dx + dy * dy;
}

//! Might actually be more expensive than DP, which is also better
List<DoublePoint> simplifyRadialDist(
List<DoublePoint> points,
double sqTolerance,
Expand Down Expand Up @@ -107,7 +111,6 @@ void _simplifyDPStep(
}
}

// simplification using Ramer-Douglas-Peucker algorithm
List<DoublePoint> simplifyDouglasPeucker(
List<DoublePoint> points,
double sqTolerance,
Expand All @@ -119,10 +122,10 @@ List<DoublePoint> simplifyDouglasPeucker(
return simplified;
}

List<LatLng> simplify(
List<LatLng> points,
double tolerance, {
bool highestQuality = false,
List<LatLng> simplify({
required List<LatLng> points,
required double tolerance,
required bool highQuality,
}) {
// Don't simplify anything less than a square
if (points.length <= 4) return points;
Expand All @@ -132,38 +135,35 @@ List<LatLng> simplify(
(i) => DoublePoint(points[i].longitude, points[i].latitude),
);
final double sqTolerance = tolerance * tolerance;
nextPoints =
highestQuality ? nextPoints : simplifyRadialDist(nextPoints, sqTolerance);
nextPoints = simplifyDouglasPeucker(nextPoints, sqTolerance);
nextPoints = highQuality
? simplifyDouglasPeucker(nextPoints, sqTolerance)
: simplifyRadialDist(nextPoints, sqTolerance);

return List<LatLng>.generate(
nextPoints.length,
(i) => LatLng(nextPoints[i].y, nextPoints[i].x),
);
}

List<DoublePoint> simplifyPoints(
final List<DoublePoint> points,
double tolerance, {
bool highestQuality = false,
List<DoublePoint> simplifyPoints({
required final List<DoublePoint> points,
required double tolerance,
required bool highQuality,
}) {
// Don't simplify anything less than a square
if (points.length <= 4) return points;

List<DoublePoint> nextPoints = points;
final double sqTolerance = tolerance * tolerance;
nextPoints =
highestQuality ? nextPoints : simplifyRadialDist(nextPoints, sqTolerance);
nextPoints = simplifyDouglasPeucker(nextPoints, sqTolerance);

return nextPoints;
return highQuality
? simplifyDouglasPeucker(points, sqTolerance)
: simplifyRadialDist(points, sqTolerance);
}

double getEffectiveSimplificationTolerance(
Crs crs,
int zoom,
double pixelTolerance,
) {
double getEffectiveSimplificationTolerance({
required Crs crs,
required int zoom,
required double pixelTolerance,
}) {
if (pixelTolerance <= 0) return 0;

final (x0, y0) = crs.untransform(0, 0, crs.scale(zoom.toDouble()));
Expand Down

0 comments on commit 9e07d1f

Please sign in to comment.