Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 0 additions & 22 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,28 +8,6 @@ concurrency:
cancel-in-progress: true

jobs:
score-package:
name: "Score Package"
runs-on: ubuntu-latest
steps:
- name: Checkout Repository
uses: actions/checkout@v4
- name: Run Dart Package Analyser
uses: axel-op/dart-package-analyzer@master
id: analysis
with:
githubToken: ${{ secrets.GITHUB_TOKEN }}
- name: Check Package Scores
env:
TOTAL: ${{ steps.analysis.outputs.total }}
TOTAL_MAX: ${{ steps.analysis.outputs.total_max }}
run: |
if (( $TOTAL < $TOTAL_MAX ))
then
echo Package score less than available score. Improve the score!
exit 1
fi

analyse-code:
name: "Analyse Code"
runs-on: ubuntu-latest
Expand Down
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,10 @@ Many thanks to my sponsors, no matter how much or how little they donated. Spons

# Changelog

## [10.1.0] - 2025/02/02

* Added support for flutter_map v8

## [10.0.0] - "Better Browsing" - 2025/01/11

This update builds on v9 to fully embrace the new many-to-many relationship between tiles and stores, which allows for more flexibility when constructing the `FMTCTileProvider`.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -230,9 +230,9 @@ class _DownloadProgressMaskerRenderer extends RenderProxyBox {

/// Project specified coordinates to a screen space [Rect]
Rect _calculateRectOfCoords(LatLng nwCoord, LatLng seCoord) {
final nwScreen = mapCamera.latLngToScreenPoint(nwCoord);
final seScreen = mapCamera.latLngToScreenPoint(seCoord);
return Rect.fromPoints(nwScreen.toOffset(), seScreen.toOffset());
final nwScreen = mapCamera.latLngToScreenOffset(nwCoord);
final seScreen = mapCamera.latLngToScreenOffset(seCoord);
return Rect.fromPoints(nwScreen, seScreen);
}

/// Handles incoming tiles from the input stream, modifying the [_tileMapping]
Expand Down Expand Up @@ -272,9 +272,20 @@ class _DownloadProgressMaskerRenderer extends RenderProxyBox {
} else {
final zoom = tile.z.toDouble();
_tileMapping[intermediateZoomTile] = tmv = _TileMappingValue.newTile(
nwCoord: mapCamera.crs.pointToLatLng(tile * tileSize, zoom),
seCoord: mapCamera.crs
.pointToLatLng((tile + const Point(1, 1)) * tileSize, zoom),
nwCoord: mapCamera.crs.offsetToLatLng(
Offset(
(tile.x * tileSize).toDouble(),
(tile.y * tileSize).toDouble(),
),
zoom,
),
seCoord: mapCamera.crs.offsetToLatLng(
Offset(
((tile.x + 1) * tileSize).toDouble(),
((tile.y + 1) * tileSize).toDouble(),
),
zoom,
),
);
_mostRecentTile =
() => _calculateRectOfCoords(tmv.nwCoord, tmv.seCoord);
Expand Down
9 changes: 3 additions & 6 deletions example/lib/src/screens/main/map_view/map_view.dart
Original file line number Diff line number Diff line change
Expand Up @@ -171,8 +171,7 @@ class _MapViewState extends State<MapView> with TickerProviderStateMixin {
final coords = provider.currentConstructingCoordinates;
if (coords.length > 1) {
final newPointPos = _mapController.mapController.camera
.latLngToScreenPoint(coords.first)
.toOffset();
.latLngToScreenOffset(coords.first);
provider.customPolygonSnap = coords.first != coords.last &&
sqrt(
pow(newPointPos.dx - evt.localPosition.dx, 2) +
Expand All @@ -196,11 +195,9 @@ class _MapViewState extends State<MapView> with TickerProviderStateMixin {
final coords = provider.currentConstructingCoordinates;
if (coords.length > 1) {
final newPointPos = _mapController.mapController.camera
.latLngToScreenPoint(coords.first)
.toOffset();
.latLngToScreenOffset(coords.first);
final centerPos = _mapController.mapController.camera
.latLngToScreenPoint(provider.currentNewPointPos!)
.toOffset();
.latLngToScreenOffset(provider.currentNewPointPos!);
provider.customPolygonSnap = coords.first != coords.last &&
sqrt(
pow(newPointPos.dx - centerPos.dx, 2) +
Expand Down
6 changes: 2 additions & 4 deletions example/pubspec.yaml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
name: fmtc_demo
description: The demo app for 'flutter_map_tile_caching', showcasing its functionality and use-cases.
publish_to: "none"
version: 10.0.0
version: 10.1.0

environment:
sdk: ">=3.6.0 <4.0.0"
Expand Down Expand Up @@ -33,9 +33,7 @@ dependencies:

dependency_overrides:
flutter_map:
git:
url: https://github.com/fleaflet/flutter_map.git
ref: d816b4d54f9245e260b125ea1adbf300b5c39843
git: https://github.com/fleaflet/flutter_map.git
flutter_map_tile_caching:
path: ../

Expand Down
139 changes: 74 additions & 65 deletions lib/src/bulk_download/internal/tile_loops/count.dart
Original file line number Diff line number Diff line change
Expand Up @@ -38,15 +38,17 @@ class TileCounters {
for (double zoomLvl = region.minZoom.toDouble();
zoomLvl <= region.maxZoom;
zoomLvl++) {
final nwPoint = (region.crs.latLngToPoint(northWest, zoomLvl) /
region.options.tileSize)
.floor();
final sePoint = (region.crs.latLngToPoint(southEast, zoomLvl) /
region.options.tileSize)
.ceil() -
const Point(1, 1);

tileCount += (sePoint.x - nwPoint.x + 1) * (sePoint.y - nwPoint.y + 1);
final scaleLvl = region.crs.scale(zoomLvl);

final nw = region.crs.latLngToXY(northWest, scaleLvl);
final nwX = (nw.$1 / region.options.tileDimension).floor();
final nwY = (nw.$2 / region.options.tileDimension).floor();

final se = region.crs.latLngToXY(southEast, scaleLvl);
final seX = (se.$1 / region.options.tileDimension).ceil() - 1;
final seY = (se.$2 / region.options.tileDimension).ceil() - 1;

tileCount += (seX - nwX + 1) * (seY - nwY + 1);
}

return _trimToRange(region, tileCount);
Expand All @@ -64,20 +66,19 @@ class TileCounters {
0,
);

for (int zoomLvl = region.minZoom; zoomLvl <= region.maxZoom; zoomLvl++) {
final centerTile = (region.crs.latLngToPoint(
region.originalRegion.center,
zoomLvl.toDouble(),
) /
region.options.tileSize)
.floor();
for (double zoomLvl = region.minZoom.toDouble();
zoomLvl <= region.maxZoom;
zoomLvl++) {
final scaleLvl = region.crs.scale(zoomLvl);

final (_, rawCenterY) =
region.crs.latLngToXY(region.originalRegion.center, scaleLvl);
final centerY = (rawCenterY / region.options.tileDimension).floor();

final radius = centerTile.y -
(region.crs.latLngToPoint(edgeTile, zoomLvl.toDouble()) /
region.options.tileSize)
.floor()
.y;
final (_, rawEdgeY) = region.crs.latLngToXY(edgeTile, scaleLvl);
final edgeY = (rawEdgeY / region.options.tileDimension).floor();

final radius = centerY - edgeY;
final radiusSquared = radius * radius;

if (radius == 0) {
Expand Down Expand Up @@ -113,20 +114,20 @@ class TileCounters {
final p1 = polygon.points[i1];
final p2 = polygon.points[i2];

final normal = Point(p2.y - p1.y, p1.x - p2.x);
final normal = Point(p2.$2 - p1.$2, p1.$1 - p2.$1);

var minA = largestInt;
var maxA = smallestInt;
for (final p in a.points) {
final projected = normal.x * p.x + normal.y * p.y;
final projected = normal.x * p.$1 + normal.y * p.$2;
if (projected < minA) minA = projected;
if (projected > maxA) maxA = projected;
}

var minB = largestInt;
var maxB = smallestInt;
for (final p in b.points) {
final projected = normal.x * p.x + normal.y * p.y;
final projected = normal.x * p.$1 + normal.y * p.$2;
if (projected < minB) minB = projected;
if (projected > maxB) maxB = projected;
}
Expand All @@ -145,6 +146,8 @@ class TileCounters {
for (double zoomLvl = region.minZoom.toDouble();
zoomLvl <= region.maxZoom;
zoomLvl++) {
final scaleLvl = region.crs.scale(zoomLvl);

final generatedTiles = <int>[];

for (final rect in lineOutline) {
Expand All @@ -169,51 +172,49 @@ class TileCounters {
];

final rotatedRectangleNW =
(region.crs.latLngToPoint(rotatedRectangle.topLeft, zoomLvl) /
region.options.tileSize)
(region.crs.latLngToXY(rotatedRectangle.topLeft, scaleLvl) /
region.options.tileDimension)
.floor();
final rotatedRectangleNE =
(region.crs.latLngToPoint(rotatedRectangle.topRight, zoomLvl) /
region.options.tileSize)
(region.crs.latLngToXY(rotatedRectangle.topRight, scaleLvl) /
region.options.tileDimension)
.ceil() -
const Point(1, 0);
(1, 0);
final rotatedRectangleSW =
(region.crs.latLngToPoint(rotatedRectangle.bottomLeft, zoomLvl) /
region.options.tileSize)
(region.crs.latLngToXY(rotatedRectangle.bottomLeft, scaleLvl) /
region.options.tileDimension)
.ceil() -
const Point(0, 1);
(0, 1);
final rotatedRectangleSE =
(region.crs.latLngToPoint(rotatedRectangle.bottomRight, zoomLvl) /
region.options.tileSize)
(region.crs.latLngToXY(rotatedRectangle.bottomRight, scaleLvl) /
region.options.tileDimension)
.ceil() -
const Point(1, 1);
(1, 1);

final straightRectangleNW = (region.crs.latLngToPoint(
final straightRectangleNW = (region.crs.latLngToXY(
LatLng(rotatedRectangleLats.max, rotatedRectangleLngs.min),
zoomLvl,
scaleLvl,
) /
region.options.tileSize)
region.options.tileDimension)
.floor();
final straightRectangleSE = (region.crs.latLngToPoint(
final straightRectangleSE = (region.crs.latLngToXY(
LatLng(
rotatedRectangleLats.min,
rotatedRectangleLngs.max,
),
zoomLvl,
scaleLvl,
) /
region.options.tileSize)
region.options.tileDimension)
.ceil() -
const Point(1, 1);
(1, 1);

for (int x = straightRectangleNW.x; x <= straightRectangleSE.x; x++) {
for (int x = straightRectangleNW.$1; x <= straightRectangleSE.$1; x++) {
bool foundOverlappingTile = false;
for (int y = straightRectangleNW.y; y <= straightRectangleSE.y; y++) {
final tile = _Polygon(
Point(x, y),
Point(x + 1, y),
Point(x + 1, y + 1),
Point(x, y + 1),
);
for (int y = straightRectangleNW.$2;
y <= straightRectangleSE.$2;
y++) {
final tile =
_Polygon((x, y), (x + 1, y), (x + 1, y + 1), (x, y + 1));
if (generatedTiles.contains(tile.hashCode)) continue;
if (overlap(
_Polygon(
Expand Down Expand Up @@ -251,35 +252,43 @@ class TileCounters {
for (double zoomLvl = region.minZoom.toDouble();
zoomLvl <= region.maxZoom;
zoomLvl++) {
final allOutlineTiles = <Point<int>>{};
final scaleLvl = region.crs.scale(zoomLvl);

final pointsOutline = customPolygonOutline
.map((e) => region.crs.latLngToPoint(e, zoomLvl).floor());
final allOutlineTiles = <(int, int)>{};

for (final triangle in Earcut.triangulateFromPoints(
pointsOutline.map((e) => e.toDoublePoint()),
final pointsOutline = customPolygonOutline
.map((e) => region.crs.latLngToXY(e, scaleLvl).floorToDouble());

for (final triangle in Earcut.triangulateRaw(
List.generate(
pointsOutline.length * 2,
(i) => i.isEven
? pointsOutline.elementAt(i ~/ 2).$1
: pointsOutline.elementAt(i ~/ 2).$2,
growable: false,
),
).map(pointsOutline.elementAt).slices(3)) {
final outlineTiles = {
..._bresenhamsLGA(
Point(triangle[0].x, triangle[0].y),
Point(triangle[1].x, triangle[1].y),
unscaleBy: region.options.tileSize,
triangle[0],
triangle[1],
unscaleBy: region.options.tileDimension,
),
..._bresenhamsLGA(
Point(triangle[1].x, triangle[1].y),
Point(triangle[2].x, triangle[2].y),
unscaleBy: region.options.tileSize,
triangle[1],
triangle[2],
unscaleBy: region.options.tileDimension,
),
..._bresenhamsLGA(
Point(triangle[2].x, triangle[2].y),
Point(triangle[0].x, triangle[0].y),
unscaleBy: region.options.tileSize,
triangle[2],
triangle[0],
unscaleBy: region.options.tileDimension,
),
};
allOutlineTiles.addAll(outlineTiles);

final byY = <int, Set<int>>{};
for (final Point(:x, :y) in outlineTiles) {
for (final (x, y) in outlineTiles) {
(byY[y] ??= {}).add(x);
}

Expand Down
Loading
Loading