From 270b3316a12c264f59dfe991a725dd86700e5a65 Mon Sep 17 00:00:00 2001 From: Sebastian Date: Thu, 9 Nov 2023 13:15:32 +0100 Subject: [PATCH] perf!: reduce work to build and fix bugs in `TileLayer`, and improve culling of off-screen tiles (#1718) --- lib/src/geo/crs.dart | 8 +- .../tile_layer/tile_bounds/tile_bounds.dart | 17 ++-- .../layer/tile_layer/tile_coordinates.dart | 2 +- lib/src/layer/tile_layer/tile_image.dart | 6 -- .../layer/tile_layer/tile_image_manager.dart | 76 ++++++++---------- lib/src/layer/tile_layer/tile_image_view.dart | 79 +++++++++++------- lib/src/layer/tile_layer/tile_layer.dart | 80 ++++++++++++------- lib/src/layer/tile_layer/tile_range.dart | 14 ++-- .../tile_bounds/tile_bounds_at_zoom_test.dart | 4 +- .../tile_layer/tile_image_view_test.dart | 16 ++-- test/layer/tile_layer/tile_range_test.dart | 56 ++++++------- 11 files changed, 191 insertions(+), 167 deletions(-) diff --git a/lib/src/geo/crs.dart b/lib/src/geo/crs.dart index 5ec3d7277..b78b04f2b 100644 --- a/lib/src/geo/crs.dart +++ b/lib/src/geo/crs.dart @@ -39,14 +39,14 @@ abstract class Crs { double zoom(double scale) => math.log(scale / 256) / math.ln2; /// Rescales the bounds to a given zoom value. - Bounds? getProjectedBounds(double zoom) { + Bounds? getProjectedBounds(double zoom) { if (infinite) return null; final b = projection.bounds!; final s = scale(zoom); final min = transformation.transform(b.min, s); final max = transformation.transform(b.max, s); - return Bounds(min, max); + return Bounds(min, max); } bool get infinite; @@ -239,7 +239,7 @@ class Proj4Crs extends Crs { /// Rescales the bounds to a given zoom value. @override - Bounds? getProjectedBounds(double zoom) { + Bounds? getProjectedBounds(double zoom) { if (infinite) return null; final b = projection.bounds!; @@ -249,7 +249,7 @@ class Proj4Crs extends Crs { final min = transformation.transform(b.min, s); final max = transformation.transform(b.max, s); - return Bounds(min, max); + return Bounds(min, max); } /// Zoom to Scale function. diff --git a/lib/src/layer/tile_layer/tile_bounds/tile_bounds.dart b/lib/src/layer/tile_layer/tile_bounds/tile_bounds.dart index 99c596f67..122468ec7 100644 --- a/lib/src/layer/tile_layer/tile_bounds/tile_bounds.dart +++ b/lib/src/layer/tile_layer/tile_bounds/tile_bounds.dart @@ -3,7 +3,6 @@ import 'package:flutter_map/src/geo/latlng_bounds.dart'; import 'package:flutter_map/src/layer/tile_layer/tile_bounds/tile_bounds_at_zoom.dart'; import 'package:flutter_map/src/layer/tile_layer/tile_range.dart'; import 'package:flutter_map/src/misc/bounds.dart'; -import 'package:flutter_map/src/misc/point_extensions.dart'; import 'package:latlong2/latlong.dart'; import 'package:meta/meta.dart'; @@ -76,13 +75,13 @@ class DiscreteTileBounds extends TileBounds { TileBoundsAtZoom _tileBoundsAtZoomImpl(int zoom) { final zoomDouble = zoom.toDouble(); - final Bounds pixelBounds; + final Bounds pixelBounds; if (_latLngBounds == null) { pixelBounds = crs.getProjectedBounds(zoomDouble)!; } else { - pixelBounds = Bounds( - crs.latLngToPoint(_latLngBounds!.southWest, zoomDouble).floor(), - crs.latLngToPoint(_latLngBounds!.northEast, zoomDouble).ceil(), + pixelBounds = Bounds( + crs.latLngToPoint(_latLngBounds!.southWest, zoomDouble), + crs.latLngToPoint(_latLngBounds!.northEast, zoomDouble), ); } @@ -115,13 +114,13 @@ class WrappedTileBounds extends TileBounds { WrappedTileBoundsAtZoom _tileBoundsAtZoomImpl(int zoom) { final zoomDouble = zoom.toDouble(); - final Bounds pixelBounds; + final Bounds pixelBounds; if (_latLngBounds == null) { pixelBounds = crs.getProjectedBounds(zoomDouble)!; } else { - pixelBounds = Bounds( - crs.latLngToPoint(_latLngBounds!.southWest, zoomDouble).floor(), - crs.latLngToPoint(_latLngBounds!.northEast, zoomDouble).ceil(), + pixelBounds = Bounds( + crs.latLngToPoint(_latLngBounds!.southWest, zoomDouble), + crs.latLngToPoint(_latLngBounds!.northEast, zoomDouble), ); } diff --git a/lib/src/layer/tile_layer/tile_coordinates.dart b/lib/src/layer/tile_layer/tile_coordinates.dart index 81fb83385..134c1f353 100644 --- a/lib/src/layer/tile_layer/tile_coordinates.dart +++ b/lib/src/layer/tile_layer/tile_coordinates.dart @@ -32,6 +32,6 @@ class TileCoordinates extends Point { @override int get hashCode { // NOTE: the odd numbers are due to JavaScript's integer precision of 53 bits. - return x | y << 24 | z << 48; + return x ^ y << 24 ^ z << 48; } } diff --git a/lib/src/layer/tile_layer/tile_image.dart b/lib/src/layer/tile_layer/tile_image.dart index a469d5099..cb8502001 100644 --- a/lib/src/layer/tile_layer/tile_image.dart +++ b/lib/src/layer/tile_layer/tile_image.dart @@ -83,8 +83,6 @@ class TileImage extends ChangeNotifier { AnimationController? get animation => _animationController; - TileCoordinates get coordinatesKey => coordinates; - /// Whether the tile is displayable. This means that either: /// * Loading errored but an error image is configured. /// * Loading succeeded and the fade animation has finished. @@ -94,10 +92,6 @@ class TileImage extends ChangeNotifier { /// tile display is used with a maximum opacity less than 1. bool get readyToDisplay => _readyToDisplay; - // Used to sort TileImages by their distance from the current zoom. - double zIndex(double maxZoom, int currentZoom) => - maxZoom - (currentZoom - coordinates.z).abs(); - /// Change the tile display options. set tileDisplay(TileDisplay newTileDisplay) { final oldTileDisplay = _tileDisplay; diff --git a/lib/src/layer/tile_layer/tile_image_manager.dart b/lib/src/layer/tile_layer/tile_image_manager.dart index 04ca232eb..305c87f32 100644 --- a/lib/src/layer/tile_layer/tile_image_manager.dart +++ b/lib/src/layer/tile_layer/tile_image_manager.dart @@ -1,3 +1,5 @@ +import 'dart:collection'; + import 'package:collection/collection.dart'; import 'package:flutter_map/src/layer/tile_layer/tile_bounds/tile_bounds.dart'; import 'package:flutter_map/src/layer/tile_layer/tile_bounds/tile_bounds_at_zoom.dart'; @@ -13,7 +15,8 @@ typedef TileCreator = TileImage Function(TileCoordinates coordinates); @immutable class TileImageManager { - final Map _tiles = {}; + final Map _tiles = + HashMap(); bool containsTileAt(TileCoordinates coordinates) => _tiles.containsKey(coordinates); @@ -21,54 +24,39 @@ class TileImageManager { bool get allLoaded => _tiles.values.none((tile) => tile.loadFinishedAt == null); - /// Returns in the order in which they should be rendered: - /// 1. Tiles at the current zoom. - /// 2. Tiles at the current zoom +/- 1. - /// 3. Tiles at the current zoom +/- 2. - /// 4. ...etc - List inRenderOrder(double maxZoom, int currentZoom) { - final result = _tiles.values.toList() - ..sort((a, b) => a - .zIndex(maxZoom, currentZoom) - .compareTo(b.zIndex(maxZoom, currentZoom))); - - return result; - } - - // Creates missing tiles in the given range. Does not initiate loading of the - // tiles. - void createMissingTiles( - DiscreteTileRange tileRange, - TileBoundsAtZoom tileBoundsAtZoom, { - required TileCreator createTileImage, - }) { - for (final coordinates in tileBoundsAtZoom.validCoordinatesIn(tileRange)) { - _tiles.putIfAbsent( - coordinates, - () => createTileImage(coordinates), - ); - } - } + /// Filter tiles to only tiles that would be visible on screen. Specifically: + /// 1. Tiles in the visible range at the target zoom level. + /// 2. Tiles at non-target zoom level that would cover up holes that would + /// be left by tiles in #1, which are not ready yet. + Iterable getTilesToRender({ + required DiscreteTileRange visibleRange, + }) => + TileImageView( + tileImages: _tiles, + visibleRange: visibleRange, + // `keepRange` is irrelevant here since we're not using the output for + // pruning storage but rather to decide on what to put on screen. + keepRange: visibleRange, + ).renderTiles; bool allWithinZoom(double minZoom, double maxZoom) => _tiles.values .map((e) => e.coordinates) .every((coord) => coord.z > maxZoom || coord.z < minZoom); - /// Creates and returns [TileImage]s which do not already exist with the given - /// [tileCoordinates]. - List createMissingTilesIn( - Iterable tileCoordinates, { + /// Creates missing [TileImage]s within the provided tile range. Returns a + /// list of [TileImage]s which haven't started loading yet. + List createMissingTiles( + DiscreteTileRange tileRange, + TileBoundsAtZoom tileBoundsAtZoom, { required TileCreator createTile, }) { final notLoaded = []; - for (final coordinates in tileCoordinates) { - final tile = _tiles.putIfAbsent( - coordinates, - () => createTile(coordinates), - ); - - if (tile.loadStarted == null) notLoaded.add(tile); + for (final coordinates in tileBoundsAtZoom.validCoordinatesIn(tileRange)) { + final tile = _tiles[coordinates] ??= createTile(coordinates); + if (tile.loadStarted == null) { + notLoaded.add(tile); + } } return notLoaded; @@ -162,11 +150,11 @@ class TileImageManager { case EvictErrorTileStrategy.notVisibleRespectMargin: for (final tileImage in tileRemovalState.errorTilesOutsideOfKeepMargin()) { - _remove(tileImage.coordinatesKey, evictImageFromCache: (_) => true); + _remove(tileImage.coordinates, evictImageFromCache: (_) => true); } case EvictErrorTileStrategy.notVisible: for (final tileImage in tileRemovalState.errorTilesNotVisible()) { - _remove(tileImage.coordinatesKey, evictImageFromCache: (_) => true); + _remove(tileImage.coordinates, evictImageFromCache: (_) => true); } case EvictErrorTileStrategy.dispose: case EvictErrorTileStrategy.none: @@ -193,8 +181,8 @@ class TileImageManager { TileImageView tileRemovalState, EvictErrorTileStrategy evictStrategy, ) { - for (final tileImage in tileRemovalState.staleTiles()) { - _removeWithEvictionStrategy(tileImage.coordinatesKey, evictStrategy); + for (final tileImage in tileRemovalState.staleTiles) { + _removeWithEvictionStrategy(tileImage.coordinates, evictStrategy); } } } diff --git a/lib/src/layer/tile_layer/tile_image_view.dart b/lib/src/layer/tile_layer/tile_image_view.dart index 684288530..ccd3b14f9 100644 --- a/lib/src/layer/tile_layer/tile_image_view.dart +++ b/lib/src/layer/tile_layer/tile_image_view.dart @@ -4,16 +4,16 @@ import 'package:flutter_map/src/layer/tile_layer/tile_coordinates.dart'; 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 class TileImageView { final Map _tileImages; final DiscreteTileRange _visibleRange; final DiscreteTileRange _keepRange; - TileImageView({ + const TileImageView({ required Map tileImages, required DiscreteTileRange visibleRange, required DiscreteTileRange keepRange, - }) : _tileImages = UnmodifiableMapView(tileImages), + }) : _tileImages = tileImages, _visibleRange = visibleRange, _keepRange = keepRange; @@ -27,24 +27,46 @@ class TileImageView { tileImage.loadError && !_visibleRange.contains(tileImage.coordinates)) .toList(); - List staleTiles() { - final tilesInKeepRange = _tileImages.values - .where((tileImage) => _keepRange.contains(tileImage.coordinates)); - final retain = Set.from(tilesInKeepRange); + Iterable get staleTiles { + final stale = HashSet(); + final retain = HashSet(); + + for (final tile in _tileImages.values) { + final c = tile.coordinates; + if (!_keepRange.contains(c)) { + stale.add(tile); + continue; + } + + final retainedAncestor = _retainAncestor(retain, c.x, c.y, c.z, c.z - 5); + if (!retainedAncestor) { + _retainChildren(retain, c.x, c.y, c.z, c.z + 2); + } + } + + return stale.where((tile) => !retain.contains(tile)); + } + + Iterable get renderTiles { + final retain = HashSet(); + + for (final tile in _tileImages.values) { + final c = tile.coordinates; + if (!_visibleRange.contains(c)) { + continue; + } + + retain.add(tile); - for (final tile in tilesInKeepRange) { if (!tile.readyToDisplay) { - final coords = tile.coordinates; - if (!_retainAncestor( - retain, coords.x, coords.y, coords.z, coords.z - 5)) { - _retainChildren(retain, coords.x, coords.y, coords.z, coords.z + 2); + final retainedAncestor = + _retainAncestor(retain, c.x, c.y, c.z, c.z - 5); + if (!retainedAncestor) { + _retainChildren(retain, c.x, c.y, c.z, c.z + 2); } } } - - return _tileImages.values - .where((tileImage) => !retain.contains(tileImage)) - .toList(); + return retain; } // Recurses through the ancestors of the Tile at the given coordinates adding @@ -88,21 +110,22 @@ class TileImageView { int z, int maxZoom, ) { - for (var i = 2 * x; i < 2 * x + 2; i++) { - for (var j = 2 * y; j < 2 * y + 2; j++) { - final coords = TileCoordinates(i, j, z + 1); - - final tile = _tileImages[coords]; - if (tile != null) { - if (tile.readyToDisplay || tile.loadFinishedAt != null) { - retain.add(tile); - } - } + for (final (i, j) in const [(0, 0), (0, 1), (1, 0), (1, 1)]) { + final coords = TileCoordinates(2 * x + i, 2 * y + j, z + 1); + + final tile = _tileImages[coords]; + if (tile != null) { + if (tile.readyToDisplay || tile.loadFinishedAt != null) { + retain.add(tile); - if (z + 1 < maxZoom) { - _retainChildren(retain, i, j, z + 1, maxZoom); + // If have the child, we do not recurse. We don't need the child's children. + continue; } } + + if (z + 1 < maxZoom) { + _retainChildren(retain, i, j, z + 1, maxZoom); + } } } } diff --git a/lib/src/layer/tile_layer/tile_layer.dart b/lib/src/layer/tile_layer/tile_layer.dart index db4d6cf2b..02c415958 100644 --- a/lib/src/layer/tile_layer/tile_layer.dart +++ b/lib/src/layer/tile_layer/tile_layer.dart @@ -524,43 +524,55 @@ class _TileLayerState extends State with TickerProviderStateMixin { _tileImageManager.createMissingTiles( visibleTileRange, tileBoundsAtZoom, - createTileImage: (coordinates) => _createTileImage( + createTile: (coordinates) => _createTileImage( coordinates: coordinates, tileBoundsAtZoom: tileBoundsAtZoom, pruneAfterLoad: false, ), ); - final currentPixelOrigin = Point( - map.pixelOrigin.x, - map.pixelOrigin.y, - ); - _tileScaleCalculator.clearCacheUnlessZoomMatches(map.zoom); + // Note: `renderTiles` filters out all tiles that are either off-screen or + // tiles at non-target zoom levels that are would be completely covered by + // tiles that are *ready* and at the target zoom level. + // We're happy to do a bit of diligent work here, since tiles not rendered are + // cycles saved later on in the render pipeline. + final tiles = _tileImageManager + .getTilesToRender(visibleRange: visibleTileRange) + .map((tileImage) => Tile( + // Must be an ObjectKey, not a ValueKey using the coordinates, in + // case we remove and replace the TileImage with a different one. + key: ObjectKey(tileImage), + scaledTileSize: _tileScaleCalculator.scaledTileSize( + map.zoom, + tileImage.coordinates.z, + ), + currentPixelOrigin: map.pixelOrigin, + tileImage: tileImage, + tileBuilder: widget.tileBuilder, + )) + .toList(); + + // Sort in render order. In reverse: + // 1. Tiles at the current zoom. + // 2. Tiles at the current zoom +/- 1. + // 3. Tiles at the current zoom +/- 2. + // 4. ...etc + int renderOrder(Tile a, Tile b) { + final (za, zb) = (a.tileImage.coordinates.z, b.tileImage.coordinates.z); + final cmp = (zb - tileZoom).abs().compareTo((za - tileZoom).abs()); + if (cmp == 0) { + // When compare parent/child tiles of equal distance, prefer higher res images. + return za.compareTo(zb); + } + return cmp; + } + return MobileLayerTransformer( // ignore: deprecated_member_use_from_same_package child: _addBackgroundColor( - Stack( - children: [ - ..._tileImageManager - .inRenderOrder(widget.maxZoom, tileZoom) - .map((tileImage) { - return Tile( - // Must be an ObjectKey, not a ValueKey using the coordinates, in - // case we remove and replace the TileImage with a different one. - key: ObjectKey(tileImage), - scaledTileSize: _tileScaleCalculator.scaledTileSize( - map.zoom, - tileImage.coordinates.z, - ), - currentPixelOrigin: currentPixelOrigin, - tileImage: tileImage, - tileBuilder: widget.tileBuilder, - ); - }), - ], - ), + Stack(children: tiles..sort(renderOrder)), ), ); } @@ -670,8 +682,9 @@ class _TileLayerState extends State with TickerProviderStateMixin { // Build the queue of tiles to load. Marks all tiles with valid coordinates // in the tileLoadRange as current. final tileBoundsAtZoom = _tileBounds.atZoom(tileZoom); - final tilesToLoad = _tileImageManager.createMissingTilesIn( - tileBoundsAtZoom.validCoordinatesIn(tileLoadRange), + final tilesToLoad = _tileImageManager.createMissingTiles( + tileLoadRange, + tileBoundsAtZoom, createTile: (coordinates) => _createTileImage( coordinates: coordinates, tileBoundsAtZoom: tileBoundsAtZoom, @@ -682,9 +695,8 @@ class _TileLayerState extends State with TickerProviderStateMixin { // Re-order the tiles by their distance to the center of the range. final tileCenter = tileLoadRange.center; tilesToLoad.sort( - (a, b) => a.coordinates - .distanceTo(tileCenter) - .compareTo(b.coordinates.distanceTo(tileCenter)), + (a, b) => _distanceSq(a.coordinates, tileCenter) + .compareTo(_distanceSq(b.coordinates, tileCenter)), ); // Create the new Tiles. @@ -740,3 +752,9 @@ class _TileLayerState extends State with TickerProviderStateMixin { bool _outsideZoomLimits(num zoom) => zoom < widget.minZoom || zoom > widget.maxZoom; } + +double _distanceSq(TileCoordinates coord, Point center) { + final dx = center.x - coord.x; + final dy = center.y - coord.y; + return dx * dx + dy * dy; +} diff --git a/lib/src/layer/tile_layer/tile_range.dart b/lib/src/layer/tile_layer/tile_range.dart index ed3ebaeb4..af91f6504 100644 --- a/lib/src/layer/tile_layer/tile_range.dart +++ b/lib/src/layer/tile_layer/tile_range.dart @@ -34,7 +34,7 @@ class DiscreteTileRange extends TileRange { factory DiscreteTileRange.fromPixelBounds({ required int zoom, required double tileSize, - required Bounds pixelBounds, + required Bounds pixelBounds, }) { final Bounds bounds; if (pixelBounds.min == pixelBounds.max) { @@ -77,9 +77,9 @@ class DiscreteTileRange extends TileRange { return DiscreteTileRange( zoom, - Bounds( - Point(math.max(min.x, minX), min.y), - Point(math.min(max.x, maxX), max.y), + Bounds( + Point(math.max(min.x, minX), min.y), + Point(math.min(max.x, maxX), max.y), ), ); } @@ -92,9 +92,9 @@ class DiscreteTileRange extends TileRange { return DiscreteTileRange( zoom, - Bounds( - Point(min.x, math.max(min.y, minY)), - Point(max.x, math.min(max.y, maxY)), + Bounds( + Point(min.x, math.max(min.y, minY)), + Point(max.x, math.min(max.y, maxY)), ), ); } diff --git a/test/layer/tile_layer/tile_bounds/tile_bounds_at_zoom_test.dart b/test/layer/tile_layer/tile_bounds/tile_bounds_at_zoom_test.dart index e7e390af3..c15bf57e1 100644 --- a/test/layer/tile_layer/tile_bounds/tile_bounds_at_zoom_test.dart +++ b/test/layer/tile_layer/tile_bounds/tile_bounds_at_zoom_test.dart @@ -9,10 +9,12 @@ import 'package:test/test.dart'; void main() { group('TileBoundsAtZoom', () { const hugeCoordinate = TileCoordinates(999999999, 999999999, 0); + final hugePoint = + Point(hugeCoordinate.x.toDouble(), hugeCoordinate.y.toDouble()); final tileRangeWithHugeCoordinate = DiscreteTileRange.fromPixelBounds( zoom: 0, tileSize: 1, - pixelBounds: Bounds(hugeCoordinate, hugeCoordinate), + pixelBounds: Bounds(hugePoint, hugePoint), ); DiscreteTileRange discreteTileRange( diff --git a/test/layer/tile_layer/tile_image_view_test.dart b/test/layer/tile_layer/tile_image_view_test.dart index d9d65294e..f5dcda6f7 100644 --- a/test/layer/tile_layer/tile_image_view_test.dart +++ b/test/layer/tile_layer/tile_image_view_test.dart @@ -54,7 +54,7 @@ void main() { keepRange: discreteTileRange(2, 1, 3, 3, zoom: 1), ); expect( - removalState.staleTiles(), + removalState.staleTiles, containsTileImage(tileImages, const TileCoordinates(1, 1, 1)), ); }); @@ -70,7 +70,7 @@ void main() { keepRange: discreteTileRange(0, 0, 0, 0, zoom: 1), ); expect( - removalState.staleTiles(), + removalState.staleTiles, doesNotContainTileImage(tileImages, const TileCoordinates(0, 0, 0)), ); }); @@ -88,7 +88,7 @@ void main() { keepRange: discreteTileRange(0, 0, 0, 0, zoom: 1), ); expect( - removalState.staleTiles(), + removalState.staleTiles, doesNotContainTileImage(tileImages, const TileCoordinates(0, 0, 2)), ); }); @@ -106,15 +106,15 @@ void main() { keepRange: discreteTileRange(2, 1, 3, 3, zoom: 1), ); expect( - removalState.staleTiles(), + removalState.staleTiles, containsTileImage(tileImages, const TileCoordinates(1, 1, 1)), ); // If an iterator over the original collection is returned then when // looping over that iterator and removing from the original collection // a concurrent modification exception is thrown. This ensures that the // returned collection is not an iterable over the original collection. - for (final staleTile in removalState.staleTiles()) { - tileImages.remove(staleTile.coordinatesKey)!; + for (final staleTile in removalState.staleTiles) { + tileImages.remove(staleTile.coordinates)!; } }); }); @@ -141,7 +141,7 @@ void main() { // a concurrent modification exception is thrown. This ensures that the // returned collection is not an iterable over the original collection. for (final tileImage in tileImageView.errorTilesOutsideOfKeepMargin()) { - tileImages.remove(tileImage.coordinatesKey)!; + tileImages.remove(tileImage.coordinates)!; } }); @@ -167,7 +167,7 @@ void main() { // a concurrent modification exception is thrown. This ensures that the // returned collection is not an iterable over the original collection. for (final tileImage in tileImageView.errorTilesOutsideOfKeepMargin()) { - tileImages.remove(tileImage.coordinatesKey)!; + tileImages.remove(tileImage.coordinates)!; } }); } diff --git a/test/layer/tile_layer/tile_range_test.dart b/test/layer/tile_layer/tile_range_test.dart index 3a60cf71a..346ffb532 100644 --- a/test/layer/tile_layer/tile_range_test.dart +++ b/test/layer/tile_layer/tile_range_test.dart @@ -35,8 +35,8 @@ void main() { zoom: 0, tileSize: 10, pixelBounds: Bounds( - const Point(25.0, 25.0), - const Point(25.0, 25.0), + const Point(25, 25), + const Point(25, 25), ), ); @@ -49,7 +49,7 @@ void main() { zoom: 0, tileSize: 10, pixelBounds: Bounds( - const Point(0.0, 0.0), + const Point(0, 0), const Point(0.1, 0.1), ), ); @@ -63,7 +63,7 @@ void main() { zoom: 0, tileSize: 10, pixelBounds: Bounds( - const Point(0.0, 0.0), + const Point(0, 0), const Point(9.99, 9.99), ), ); @@ -101,8 +101,8 @@ void main() { zoom: 0, tileSize: 10, pixelBounds: Bounds( - const Point(25.0, 25.0), - const Point(25.0, 25.0), + const Point(25, 25), + const Point(25, 25), ), ); @@ -128,8 +128,8 @@ void main() { zoom: 0, tileSize: 10, pixelBounds: Bounds( - const Point(25.0, 25.0), - const Point(25.0, 25.0), + const Point(25, 25), + const Point(25, 25), ), ); @@ -137,8 +137,8 @@ void main() { zoom: 0, tileSize: 10, pixelBounds: Bounds( - const Point(35.0, 35.0), - const Point(35.0, 35.0), + const Point(35, 35), + const Point(35, 35), ), ); @@ -154,8 +154,8 @@ void main() { zoom: 0, tileSize: 10, pixelBounds: Bounds( - const Point(25.0, 25.0), - const Point(35.0, 35.0), + const Point(25, 25), + const Point(35, 35), ), ); @@ -163,8 +163,8 @@ void main() { zoom: 0, tileSize: 10, pixelBounds: Bounds( - const Point(35.0, 35.0), - const Point(45.0, 45.0), + const Point(35, 35), + const Point(45, 45), ), ); @@ -182,8 +182,8 @@ void main() { zoom: 0, tileSize: 10, pixelBounds: Bounds( - const Point(25.0, 25.0), - const Point(35.0, 35.0), + const Point(25, 25), + const Point(35, 35), ), ); @@ -191,8 +191,8 @@ void main() { zoom: 0, tileSize: 10, pixelBounds: Bounds( - const Point(15.0, 15.0), - const Point(45.0, 45.0), + const Point(15, 15), + const Point(45, 45), ), ); @@ -211,8 +211,8 @@ void main() { zoom: 0, tileSize: 10, pixelBounds: Bounds( - const Point(35.0, 35.0), - const Point(45.0, 45.0), + const Point(35, 35), + const Point(45, 45), ), ); @@ -226,8 +226,8 @@ void main() { zoom: 0, tileSize: 10, pixelBounds: Bounds( - const Point(35.0, 35.0), - const Point(35.0, 35.0), + const Point(35, 35), + const Point(35, 35), ), ); @@ -239,8 +239,8 @@ void main() { zoom: 0, tileSize: 10, pixelBounds: Bounds( - const Point(35.0, 35.0), - const Point(45.0, 45.0), + const Point(35, 35), + const Point(45, 45), ), ); @@ -252,8 +252,8 @@ void main() { zoom: 0, tileSize: 10, pixelBounds: Bounds( - const Point(35.0, 35.0), - const Point(55.0, 55.0), + const Point(35, 35), + const Point(55, 55), ), ); @@ -266,8 +266,8 @@ void main() { zoom: 0, tileSize: 10, pixelBounds: Bounds( - const Point(35.0, 35.0), - const Point(35.0, 35.0), + const Point(35, 35), + const Point(35, 35), ), );