Skip to content

Commit

Permalink
Fixed LineRegion tile generating bugs (#132)
Browse files Browse the repository at this point in the history
Former-commit-id: 17aeab35399fca0223356b2b581245f3d7863431 [formerly cd1245f]
Former-commit-id: 90c8e2ac3b6e5f899ad5be1dd693fea1f8726cad
  • Loading branch information
JaffaKetchup authored Jul 29, 2023
1 parent d665b71 commit f78df7a
Show file tree
Hide file tree
Showing 9 changed files with 75 additions and 82 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,10 @@ Many thanks to my sponsors, no matter how much or how little they donated. Spons

# Changelog

## [8.0.1] - 2023/05/05

* Fixed bugs when generating tiles for `LineRegion`

## [8.0.0] - 2023/XX/XX

* Bulk downloading has been rewritten to use a new implementation that generates tile coordinates at the same time as downloading tiles
Expand Down
10 changes: 7 additions & 3 deletions lib/src/bulk_download/downloader.dart
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ Future<Stream<TileProgress>> bulkDownloader({
: region.type == RegionType.circle
? TilesGenerator.circleTiles
: TilesGenerator.lineTiles,
{'sendPort': recievePort.sendPort, ...generateTileLoopsInput(region)},
{'sendPort': recievePort.sendPort, 'region': region},
onExit: recievePort.sendPort,
);
final tileQueue = StreamQueue(
Expand All @@ -64,7 +64,7 @@ Future<Stream<TileProgress>> bulkDownloader({
while (true) {
requestTilePort.send(null);

final List<int>? value;
final List<num>? value;
try {
value = await tileQueue.next;
// ignore: avoid_catching_errors
Expand Down Expand Up @@ -100,7 +100,11 @@ Future<Stream<TileProgress>> bulkDownloader({
break;
}

final coord = TileCoordinates(value[0], value[1], value[2]);
final coord = TileCoordinates(
value[0].toInt(),
value[1].toInt(),
value[2].toInt(),
);

final url = provider.getTileUrl(coord, region.options);
final existingTile = await tiles.tiles.get(DatabaseTools.hash(url));
Expand Down
53 changes: 22 additions & 31 deletions lib/src/bulk_download/tile_loops/count.dart
Original file line number Diff line number Diff line change
Expand Up @@ -4,20 +4,17 @@
part of 'shared.dart';

class TilesCounter {
static int rectangleTiles(Map<String, dynamic> input) {
final LatLngBounds bounds = input['rectOutline'];
final int minZoom = input['minZoom'];
final int maxZoom = input['maxZoom'];
final Crs crs = input['crs'];
final CustomPoint<double> tileSize = input['tileSize'];
static int rectangleTiles(DownloadableRegion region) {
final tileSize = _getTileSize(region);
final bounds = (region.originalRegion as RectangleRegion).bounds;

int numberOfTiles = 0;
for (int zoomLvl = minZoom; zoomLvl <= maxZoom; zoomLvl++) {
final CustomPoint<num> nwCustomPoint = crs
for (int zoomLvl = region.minZoom; zoomLvl <= region.maxZoom; zoomLvl++) {
final CustomPoint<num> nwCustomPoint = region.crs
.latLngToPoint(bounds.northWest, zoomLvl.toDouble())
.unscaleBy(tileSize)
.floor();
final CustomPoint<num> seCustomPoint = crs
final CustomPoint<num> seCustomPoint = region.crs
.latLngToPoint(bounds.southEast, zoomLvl.toDouble())
.unscaleBy(tileSize)
.ceil() -
Expand All @@ -29,30 +26,27 @@ class TilesCounter {
return numberOfTiles;
}

static int circleTiles(Map<String, dynamic> input) {
static int circleTiles(DownloadableRegion region) {
// This took some time and is fairly complicated, so this is the overall explanation:
// 1. Given a `LatLng` for every x degrees on a circle's circumference, convert it into a tile number
// 2. Using a `Map` per zoom level, record all the X values in it without duplicates
// 3. Under the previous record, add all the Y values within the circle (ie. to opposite the X value)
// 4. Loop over these XY values and add them to the list
// Theoretically, this could have been done using the same method as `lineTiles`, but `lineTiles` was built after this algorithm and this makes more sense for a circle

final List<LatLng> circleOutline = input['circleOutline'];
final int minZoom = input['minZoom'];
final int maxZoom = input['maxZoom'];
final Crs crs = input['crs'];
final CustomPoint<double> tileSize = input['tileSize'];
final tileSize = _getTileSize(region);
final circleOutline = region.originalRegion.toOutline();

// Format: Map<z, Map<x, List<y>>>
final Map<int, Map<int, List<int>>> outlineTileNums = {};

int numberOfTiles = 0;

for (int zoomLvl = minZoom; zoomLvl <= maxZoom; zoomLvl++) {
for (int zoomLvl = region.minZoom; zoomLvl <= region.maxZoom; zoomLvl++) {
outlineTileNums[zoomLvl] = <int, List<int>>{};

for (final LatLng node in circleOutline) {
final CustomPoint<num> tile = crs
final CustomPoint<num> tile = region.crs
.latLngToPoint(node, zoomLvl.toDouble())
.unscaleBy(tileSize)
.floor();
Expand Down Expand Up @@ -82,7 +76,7 @@ class TilesCounter {
return numberOfTiles;
}

static int lineTiles(Map<String, dynamic> input) {
static int lineTiles(DownloadableRegion region) {
// This took some time and is fairly complicated, so this is the overall explanation:
// 1. Given 4 `LatLng` points, create a 'straight' rectangle around the 'rotated' rectangle, that can be defined with just 2 `LatLng` points
// 2. Convert the straight rectangle into tile numbers, and loop through the same as `rectangleTiles`
Expand Down Expand Up @@ -130,16 +124,13 @@ class TilesCounter {
return true;
}

final List<List<LatLng>> rects = input['lineOutline'];
final int minZoom = input['minZoom'];
final int maxZoom = input['maxZoom'];
final Crs crs = input['crs'];
final CustomPoint<double> tileSize = input['tileSize'];
final tileSize = _getTileSize(region);
final lineOutline = (region.originalRegion as LineRegion).toOutlines(1);

int numberOfTiles = 0;

for (int zoomLvl = minZoom; zoomLvl <= maxZoom; zoomLvl++) {
for (final List<LatLng> rect in rects) {
for (int zoomLvl = region.minZoom; zoomLvl <= region.maxZoom; zoomLvl++) {
for (final rect in lineOutline) {
final LatLng rrBottomLeft = rect[0];
final LatLng rrBottomRight = rect[1];
final LatLng rrTopRight = rect[2];
Expand All @@ -158,34 +149,34 @@ class TilesCounter {
rrBottomRight.longitude,
];

final CustomPoint<num> rrNorthWest = crs
final CustomPoint<num> rrNorthWest = region.crs
.latLngToPoint(rrTopLeft, zoomLvl.toDouble())
.unscaleBy(tileSize)
.floor();
final CustomPoint<num> rrNorthEast = crs
final CustomPoint<num> rrNorthEast = region.crs
.latLngToPoint(rrTopRight, zoomLvl.toDouble())
.unscaleBy(tileSize)
.ceil() -
const CustomPoint(1, 0);
final CustomPoint<num> rrSouthWest = crs
final CustomPoint<num> rrSouthWest = region.crs
.latLngToPoint(rrBottomLeft, zoomLvl.toDouble())
.unscaleBy(tileSize)
.ceil() -
const CustomPoint(0, 1);
final CustomPoint<num> rrSouthEast = crs
final CustomPoint<num> rrSouthEast = region.crs
.latLngToPoint(rrBottomRight, zoomLvl.toDouble())
.unscaleBy(tileSize)
.ceil() -
const CustomPoint(1, 1);

final CustomPoint<num> srNorthWest = crs
final CustomPoint<num> srNorthWest = region.crs
.latLngToPoint(
LatLng(rrAllLat.max, rrAllLon.min),
zoomLvl.toDouble(),
)
.unscaleBy(tileSize)
.floor();
final CustomPoint<num> srSouthEast = crs
final CustomPoint<num> srSouthEast = region.crs
.latLngToPoint(
LatLng(rrAllLat.min, rrAllLon.max),
zoomLvl.toDouble(),
Expand Down
71 changes: 38 additions & 33 deletions lib/src/bulk_download/tile_loops/generate.dart
Original file line number Diff line number Diff line change
Expand Up @@ -6,23 +6,24 @@ part of 'shared.dart';
class TilesGenerator {
static Future<void> rectangleTiles(Map<String, dynamic> input) async {
final SendPort sendPort = input['sendPort'];
final LatLngBounds bounds = input['rectOutline'];
final int minZoom = input['minZoom'];
final int maxZoom = input['maxZoom'];
final Crs crs = input['crs'];
final CustomPoint<double> tileSize = input['tileSize'];
final DownloadableRegion region = input['region'];
final originalRegion = region.originalRegion as RectangleRegion;

final tileSize = _getTileSize(region);
final northWest = originalRegion.bounds.northWest;
final southEast = originalRegion.bounds.southEast;

final recievePort = ReceivePort();
sendPort.send(recievePort.sendPort);
final requestQueue = StreamQueue(recievePort);

for (int zoomLvl = minZoom; zoomLvl <= maxZoom; zoomLvl++) {
final CustomPoint<num> nwCustomPoint = crs
.latLngToPoint(bounds.northWest, zoomLvl.toDouble())
for (int zoomLvl = region.minZoom; zoomLvl <= region.maxZoom; zoomLvl++) {
final CustomPoint<num> nwCustomPoint = region.crs
.latLngToPoint(northWest, zoomLvl.toDouble())
.unscaleBy(tileSize)
.floor();
final CustomPoint<num> seCustomPoint = crs
.latLngToPoint(bounds.southEast, zoomLvl.toDouble())
final CustomPoint<num> seCustomPoint = region.crs
.latLngToPoint(southEast, zoomLvl.toDouble())
.unscaleBy(tileSize)
.ceil() -
const CustomPoint(1, 1);
Expand All @@ -47,11 +48,10 @@ class TilesGenerator {
// Theoretically, this could have been done using the same method as `lineTiles`, but `lineTiles` was built after this algorithm and this makes more sense for a circle

final SendPort sendPort = input['sendPort'];
final List<LatLng> circleOutline = input['circleOutline'];
final int minZoom = input['minZoom'];
final int maxZoom = input['maxZoom'];
final Crs crs = input['crs'];
final CustomPoint<double> tileSize = input['tileSize'];
final DownloadableRegion region = input['region'];

final tileSize = _getTileSize(region);
final circleOutline = region.originalRegion.toOutline();

final recievePort = ReceivePort();
sendPort.send(recievePort.sendPort);
Expand All @@ -60,11 +60,11 @@ class TilesGenerator {
// Format: Map<z, Map<x, List<y>>>
final Map<int, Map<int, List<int>>> outlineTileNums = {};

for (int zoomLvl = minZoom; zoomLvl <= maxZoom; zoomLvl++) {
for (int zoomLvl = region.minZoom; zoomLvl <= region.maxZoom; zoomLvl++) {
outlineTileNums[zoomLvl] = <int, List<int>>{};

for (final LatLng node in circleOutline) {
final CustomPoint<num> tile = crs
final CustomPoint<num> tile = region.crs
.latLngToPoint(node, zoomLvl.toDouble())
.unscaleBy(tileSize)
.floor();
Expand Down Expand Up @@ -146,18 +146,19 @@ class TilesGenerator {
}

final SendPort sendPort = input['sendPort'];
final List<List<LatLng>> rects = input['lineOutline'];
final int minZoom = input['minZoom'];
final int maxZoom = input['maxZoom'];
final Crs crs = input['crs'];
final CustomPoint<double> tileSize = input['tileSize'];
final DownloadableRegion region = input['region'];

final tileSize = _getTileSize(region);
final lineOutline = (region.originalRegion as LineRegion).toOutlines(1);

final recievePort = ReceivePort();
sendPort.send(recievePort.sendPort);
final requestQueue = StreamQueue(recievePort);

for (double zoomLvl = minZoom.toDouble(); zoomLvl <= maxZoom; zoomLvl++) {
for (final List<LatLng> rect in rects) {
for (double zoomLvl = region.minZoom.toDouble();
zoomLvl <= region.maxZoom;
zoomLvl++) {
for (final List<LatLng> rect in lineOutline) {
final LatLng rrBottomLeft = rect[0];
final LatLng rrBottomRight = rect[1];
final LatLng rrTopRight = rect[2];
Expand All @@ -176,27 +177,31 @@ class TilesGenerator {
rrBottomRight.longitude,
];

final CustomPoint<num> rrNorthWest =
crs.latLngToPoint(rrTopLeft, zoomLvl).unscaleBy(tileSize).floor();
final CustomPoint<num> rrNorthEast =
crs.latLngToPoint(rrTopRight, zoomLvl).unscaleBy(tileSize).ceil() -
const CustomPoint(1, 0);
final CustomPoint<num> rrSouthWest = crs
final CustomPoint<num> rrNorthWest = region.crs
.latLngToPoint(rrTopLeft, zoomLvl)
.unscaleBy(tileSize)
.floor();
final CustomPoint<num> rrNorthEast = region.crs
.latLngToPoint(rrTopRight, zoomLvl)
.unscaleBy(tileSize)
.ceil() -
const CustomPoint(1, 0);
final CustomPoint<num> rrSouthWest = region.crs
.latLngToPoint(rrBottomLeft, zoomLvl)
.unscaleBy(tileSize)
.ceil() -
const CustomPoint(0, 1);
final CustomPoint<num> rrSouthEast = crs
final CustomPoint<num> rrSouthEast = region.crs
.latLngToPoint(rrBottomRight, zoomLvl)
.unscaleBy(tileSize)
.ceil() -
const CustomPoint(1, 1);

final CustomPoint<num> srNorthWest = crs
final CustomPoint<num> srNorthWest = region.crs
.latLngToPoint(LatLng(rrAllLat.max, rrAllLon.min), zoomLvl)
.unscaleBy(tileSize)
.floor();
final CustomPoint<num> srSouthEast = crs
final CustomPoint<num> srSouthEast = region.crs
.latLngToPoint(LatLng(rrAllLat.min, rrAllLon.max), zoomLvl)
.unscaleBy(tileSize)
.ceil() -
Expand Down
13 changes: 2 additions & 11 deletions lib/src/bulk_download/tile_loops/shared.dart
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ import 'package:collection/collection.dart';
import 'package:flutter_map/flutter_map.dart';
import 'package:flutter_map/flutter_map.dart' hide Polygon;
import 'package:latlong2/latlong.dart';
import 'package:meta/meta.dart';

import '../../../flutter_map_tile_caching.dart';

Expand All @@ -26,13 +25,5 @@ class _Polygon {
List<CustomPoint<num>> get points => [nw, ne, se, sw];
}

@internal
Map<String, dynamic> generateTileLoopsInput(DownloadableRegion region) => {
'rectOutline': LatLngBounds.fromPoints(region.points.cast()),
'circleOutline': region.points,
'lineOutline': region.points.slices(4).toList(),
'minZoom': region.minZoom,
'maxZoom': region.maxZoom,
'crs': region.crs,
'tileSize': CustomPoint(region.options.tileSize, region.options.tileSize),
};
CustomPoint<double> _getTileSize(DownloadableRegion region) =>
CustomPoint(region.options.tileSize, region.options.tileSize);
2 changes: 1 addition & 1 deletion lib/src/store/download.dart
Original file line number Diff line number Diff line change
Expand Up @@ -207,7 +207,7 @@ class DownloadManagement {
: region.type == RegionType.circle
? TilesCounter.circleTiles
: TilesCounter.lineTiles,
generateTileLoopsInput(region),
region,
);

/// Cancels the ongoing foreground download and recovery session (within the
Expand Down

This file was deleted.

This file was deleted.

2 changes: 1 addition & 1 deletion pubspec.yaml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
name: flutter_map_tile_caching
description: Plugin for 'flutter_map' providing advanced caching functionality,
with ability to download map regions for offline use.
version: 8.0.0
version: 8.0.1
repository: https://github.com/JaffaKetchup/flutter_map_tile_caching
issue_tracker: https://github.com/JaffaKetchup/flutter_map_tile_caching/issues
documentation: https://fmtc.jaffaketchup.dev
Expand Down

0 comments on commit f78df7a

Please sign in to comment.