From 10e1b524c0d9e52f21e6641d3705ac3afff3b23c Mon Sep 17 00:00:00 2001 From: Sebastian Date: Sat, 28 Oct 2023 00:49:39 +0200 Subject: [PATCH] Reduce the tile management overhead. Sources: * Don't compute hash of hashes. * Cache the hash * Use hash as key and avoid string interpolation. Also as a drive-by get rid of the TileCoordinates extends Point + zoom coordinate in favor of more consistent composition. --- .../tile_bounds/tile_bounds_at_zoom.dart | 11 +++++------ lib/src/layer/tile_layer/tile_coordinates.dart | 18 +++++++++++++----- lib/src/layer/tile_layer/tile_image.dart | 2 +- .../layer/tile_layer/tile_image_manager.dart | 8 ++++---- lib/src/layer/tile_layer/tile_image_view.dart | 4 ++-- lib/src/layer/tile_layer/tile_range.dart | 10 ++++++++-- 6 files changed, 33 insertions(+), 20 deletions(-) diff --git a/lib/src/layer/tile_layer/tile_bounds/tile_bounds_at_zoom.dart b/lib/src/layer/tile_layer/tile_bounds/tile_bounds_at_zoom.dart index fbab3f14c..8a7129411 100644 --- a/lib/src/layer/tile_layer/tile_bounds/tile_bounds_at_zoom.dart +++ b/lib/src/layer/tile_layer/tile_bounds/tile_bounds_at_zoom.dart @@ -112,12 +112,11 @@ class WrappedTileBoundsAtZoom extends TileBoundsAtZoom { } bool _wrappedBothContains(TileCoordinates coordinates) { - return tileRange.contains( - Point( - _wrapInt(coordinates.x, wrapX!), - _wrapInt(coordinates.y, wrapY!), - ), - ); + return tileRange.contains(TileCoordinates( + _wrapInt(coordinates.x, wrapX!), + _wrapInt(coordinates.y, wrapY!), + coordinates.z, + )); } bool _wrappedXInRange(TileCoordinates coordinates) { diff --git a/lib/src/layer/tile_layer/tile_coordinates.dart b/lib/src/layer/tile_layer/tile_coordinates.dart index 7b0ebe122..0522591db 100644 --- a/lib/src/layer/tile_layer/tile_coordinates.dart +++ b/lib/src/layer/tile_layer/tile_coordinates.dart @@ -3,25 +3,33 @@ import 'dart:math'; import 'package:meta/meta.dart'; @immutable -class TileCoordinates extends Point { +class TileCoordinates { + final int x; + final int y; final int z; - const TileCoordinates(super.x, super.y, this.z); + int? _hashCode; - String get key => '$x:$y:$z'; + TileCoordinates(this.x, this.y, this.z); + + //int get key => ((x & 0xffff) << (20)) | ((y & 0xffff) << 8) | (z & 0xff); + int get key => hashCode; @override String toString() => 'TileCoordinate($x, $y, $z)'; // Overridden because Point's distanceTo does not allow comparing with a point // of a different type. - @override double distanceTo(Point other) { final dx = x - other.x; final dy = y - other.y; return sqrt(dx * dx + dy * dy); } + Point scaleBy(Point p) { + return Point(x * p.x, y * p.y); + } + @override bool operator ==(Object other) { if (identical(this, other)) return true; @@ -32,5 +40,5 @@ class TileCoordinates extends Point { } @override - int get hashCode => Object.hash(x.hashCode, y.hashCode, z.hashCode); + int get hashCode => _hashCode ??= Object.hash(x, y, z); } diff --git a/lib/src/layer/tile_layer/tile_image.dart b/lib/src/layer/tile_layer/tile_image.dart index 8aeeb44f9..4f343f38c 100644 --- a/lib/src/layer/tile_layer/tile_image.dart +++ b/lib/src/layer/tile_layer/tile_image.dart @@ -83,7 +83,7 @@ class TileImage extends ChangeNotifier { AnimationController? get animation => _animationController; - String get coordinatesKey => coordinates.key; + int get coordinatesKey => coordinates.key; /// Whether the tile is displayable. This means that either: /// * Loading errored but an error image is configured. diff --git a/lib/src/layer/tile_layer/tile_image_manager.dart b/lib/src/layer/tile_layer/tile_image_manager.dart index bc7130895..522cd3cf1 100644 --- a/lib/src/layer/tile_layer/tile_image_manager.dart +++ b/lib/src/layer/tile_layer/tile_image_manager.dart @@ -13,7 +13,7 @@ typedef TileCreator = TileImage Function(TileCoordinates coordinates); @immutable class TileImageManager { - final Map _tiles = {}; + final Map _tiles = {}; bool containsTileAt(TileCoordinates coordinates) => _tiles.containsKey(coordinates.key); @@ -83,7 +83,7 @@ class TileImageManager { /// All removals should be performed by calling this method to ensure that // disposal is performed correctly. void _remove( - String key, { + int key, { required bool Function(TileImage tileImage) evictImageFromCache, }) { final removed = _tiles.remove(key); @@ -94,7 +94,7 @@ class TileImageManager { } void _removeWithEvictionStrategy( - String key, + int key, EvictErrorTileStrategy strategy, ) { _remove( @@ -105,7 +105,7 @@ class TileImageManager { } void removeAll(EvictErrorTileStrategy evictStrategy) { - final keysToRemove = List.from(_tiles.keys); + final keysToRemove = List.from(_tiles.keys); for (final key in keysToRemove) { _removeWithEvictionStrategy(key, evictStrategy); diff --git a/lib/src/layer/tile_layer/tile_image_view.dart b/lib/src/layer/tile_layer/tile_image_view.dart index 7aca827e2..8dbb51c02 100644 --- a/lib/src/layer/tile_layer/tile_image_view.dart +++ b/lib/src/layer/tile_layer/tile_image_view.dart @@ -5,12 +5,12 @@ import 'package:flutter_map/src/layer/tile_layer/tile_image.dart'; import 'package:flutter_map/src/layer/tile_layer/tile_range.dart'; class TileImageView { - final Map _tileImages; + final Map _tileImages; final DiscreteTileRange _visibleRange; final DiscreteTileRange _keepRange; TileImageView({ - required Map tileImages, + required Map tileImages, required DiscreteTileRange visibleRange, required DiscreteTileRange keepRange, }) : _tileImages = UnmodifiableMapView(tileImages), diff --git a/lib/src/layer/tile_layer/tile_range.dart b/lib/src/layer/tile_layer/tile_range.dart index ed3ebaeb4..c70ade63a 100644 --- a/lib/src/layer/tile_layer/tile_range.dart +++ b/lib/src/layer/tile_layer/tile_range.dart @@ -99,8 +99,14 @@ class DiscreteTileRange extends TileRange { ); } - bool contains(Point point) { - return _bounds.contains(point); + bool contains(TileCoordinates point) { + if (zoom != point.z) { + return false; + } + return (point.x >= _bounds.min.x) && + (point.x <= _bounds.max.x) && + (point.y >= _bounds.min.y) && + (point.y <= _bounds.max.y); } Point get min => _bounds.min;