Mapsforge: deduplicate maps, fix overlapping map regions (#903)

This commit is contained in:
Emux 2022-02-08 14:33:40 +02:00 committed by GitHub
parent c4003bab33
commit 86794c8838
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 121 additions and 62 deletions

View File

@ -2,6 +2,8 @@
## New since 0.17.0 ## New since 0.17.0
- Mapsforge: deduplicate maps [#903](https://github.com/mapsforge/vtm/pull/903)
- Fix overlapping map regions [#903](https://github.com/mapsforge/vtm/pull/903)
- Minor improvements and bug fixes - Minor improvements and bug fixes
- [Solved issues](https://github.com/mapsforge/vtm/issues?q=is%3Aclosed+milestone%3A0.18.0) - [Solved issues](https://github.com/mapsforge/vtm/issues?q=is%3Aclosed+milestone%3A0.18.0)

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2016-2019 devemux86 * Copyright 2016-2022 devemux86
* Copyright 2018-2019 Gustl22 * Copyright 2018-2019 Gustl22
* *
* This file is part of the OpenScienceMap project (http://www.opensciencemap.org). * This file is part of the OpenScienceMap project (http://www.opensciencemap.org).
@ -67,6 +67,7 @@ public class MapsforgeTest extends GdxMapApp {
mapFileTileSource.setMapFile(mapFile.getAbsolutePath()); mapFileTileSource.setMapFile(mapFile.getAbsolutePath());
tileSource.add(mapFileTileSource); tileSource.add(mapFileTileSource);
} }
tileSource.setDeduplicate(true);
//tileSource.setPreferredLanguage("en"); //tileSource.setPreferredLanguage("en");
VectorTileLayer l = mMap.setBaseMap(tileSource); VectorTileLayer l = mMap.setBaseMap(tileSource);
@ -139,13 +140,13 @@ public class MapsforgeTest extends GdxMapApp {
for (String arg : args) { for (String arg : args) {
File mapFile = new File(arg); File mapFile = new File(arg);
if (!mapFile.exists()) { if (!mapFile.exists()) {
throw new IllegalArgumentException("file does not exist: " + mapFile); System.err.println("file does not exist: " + mapFile);
} else if (!mapFile.isFile()) { } else if (!mapFile.isFile()) {
throw new IllegalArgumentException("not a file: " + mapFile); System.err.println("not a file: " + mapFile);
} else if (!mapFile.canRead()) { } else if (!mapFile.canRead()) {
throw new IllegalArgumentException("cannot read file: " + mapFile); System.err.println("cannot read file: " + mapFile);
} } else
result.add(mapFile); result.add(mapFile);
} }
return result; return result;
} }

View File

@ -2,7 +2,7 @@
* Copyright 2012 Hannes Janetzek * Copyright 2012 Hannes Janetzek
* Copyright 2016 Andrey Novikov * Copyright 2016 Andrey Novikov
* Copyright 2017-2019 Gustl22 * Copyright 2017-2019 Gustl22
* Copyright 2018-2019 devemux86 * Copyright 2018-2022 devemux86
* Copyright 2019 marq24 * Copyright 2019 marq24
* *
* This file is part of the OpenScienceMap project (http://www.opensciencemap.org). * This file is part of the OpenScienceMap project (http://www.opensciencemap.org).
@ -38,6 +38,8 @@ public class MapElement extends GeometryBuffer {
*/ */
public int layer; public int layer;
public int level;
public final TagSet tags = new TagSet(); public final TagSet tags = new TagSet();
public MapElement() { public MapElement() {
@ -61,6 +63,7 @@ public class MapElement extends GeometryBuffer {
this.centroidPosition = element.centroidPosition; this.centroidPosition = element.centroidPosition;
this.labelPosition = element.labelPosition; this.labelPosition = element.labelPosition;
this.setLayer(element.layer); this.setLayer(element.layer);
this.level = element.level;
} }
/** /**
@ -121,6 +124,7 @@ public class MapElement extends GeometryBuffer {
@Override @Override
public MapElement clear() { public MapElement clear() {
layer = 5; layer = 5;
level = 0;
super.clear(); super.clear();
return this; return this;
} }

View File

@ -1,6 +1,6 @@
/* /*
* Copyright 2012-2014 Hannes Janetzek * Copyright 2012-2014 Hannes Janetzek
* Copyright 2016-2019 devemux86 * Copyright 2016-2022 devemux86
* *
* This file is part of the OpenScienceMap project (http://www.opensciencemap.org). * This file is part of the OpenScienceMap project (http://www.opensciencemap.org).
* *
@ -18,28 +18,13 @@
package org.oscim.layers.tile.vector; package org.oscim.layers.tile.vector;
import org.oscim.core.GeometryBuffer.GeometryType; import org.oscim.core.GeometryBuffer.GeometryType;
import org.oscim.core.MapElement; import org.oscim.core.*;
import org.oscim.core.MercatorProjection;
import org.oscim.core.Tag;
import org.oscim.core.TagSet;
import org.oscim.core.Tile;
import org.oscim.layers.tile.MapTile; import org.oscim.layers.tile.MapTile;
import org.oscim.layers.tile.TileLoader; import org.oscim.layers.tile.TileLoader;
import org.oscim.renderer.bucket.CircleBucket; import org.oscim.renderer.bucket.*;
import org.oscim.renderer.bucket.LineBucket;
import org.oscim.renderer.bucket.LineTexBucket;
import org.oscim.renderer.bucket.MeshBucket;
import org.oscim.renderer.bucket.PolygonBucket;
import org.oscim.renderer.bucket.RenderBuckets;
import org.oscim.theme.IRenderTheme; import org.oscim.theme.IRenderTheme;
import org.oscim.theme.RenderTheme; import org.oscim.theme.RenderTheme;
import org.oscim.theme.styles.AreaStyle; import org.oscim.theme.styles.*;
import org.oscim.theme.styles.CircleStyle;
import org.oscim.theme.styles.ExtrusionStyle;
import org.oscim.theme.styles.LineStyle;
import org.oscim.theme.styles.RenderStyle;
import org.oscim.theme.styles.SymbolStyle;
import org.oscim.theme.styles.TextStyle;
import org.oscim.tiling.ITileDataSource; import org.oscim.tiling.ITileDataSource;
import org.oscim.tiling.QueryResult; import org.oscim.tiling.QueryResult;
import org.slf4j.Logger; import org.slf4j.Logger;
@ -209,7 +194,7 @@ public class VectorTileLoader extends TileLoader implements RenderStyle.Callback
if (element.type == GeometryType.POINT) { if (element.type == GeometryType.POINT) {
renderNode(renderTheme.matchElement(element.type, tags, mTile.zoomLevel)); renderNode(renderTheme.matchElement(element.type, tags, mTile.zoomLevel));
} else { } else {
mCurBucket = getValidLayer(element.layer) * renderTheme.getLevels(); mCurBucket = getValidLayer(element.layer - (element.isPoly() ? element.level : 0)) * renderTheme.getLevels();
renderWay(renderTheme.matchElement(element.type, tags, mTile.zoomLevel)); renderWay(renderTheme.matchElement(element.type, tags, mTile.zoomLevel));
} }
clearState(); clearState();

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2016-2018 devemux86 * Copyright 2016-2022 devemux86
* *
* This program is free software: you can redistribute it and/or modify it under the * This program is free software: you can redistribute it and/or modify it under the
* terms of the GNU Lesser General Public License as published by the Free Software * terms of the GNU Lesser General Public License as published by the Free Software
@ -17,8 +17,14 @@ package org.oscim.tiling;
import org.oscim.backend.canvas.Bitmap; import org.oscim.backend.canvas.Bitmap;
import org.oscim.core.MapElement; import org.oscim.core.MapElement;
import java.util.HashSet;
import java.util.Set;
public class TileDataSink implements ITileDataSink { public class TileDataSink implements ITileDataSink {
public final Set<Integer> hashPois = new HashSet<>();
public final Set<Integer> hashWays = new HashSet<>();
private QueryResult result; private QueryResult result;
private final ITileDataSink sink; private final ITileDataSink sink;

View File

@ -2,7 +2,7 @@
* Copyright 2010, 2011, 2012 mapsforge.org * Copyright 2010, 2011, 2012 mapsforge.org
* Copyright 2013, 2014 Hannes Janetzek * Copyright 2013, 2014 Hannes Janetzek
* Copyright 2014-2015 Ludwig M Brinckmann * Copyright 2014-2015 Ludwig M Brinckmann
* Copyright 2016-2020 devemux86 * Copyright 2016-2022 devemux86
* Copyright 2016 Andrey Novikov * Copyright 2016 Andrey Novikov
* Copyright 2017-2018 Gustl22 * Copyright 2017-2018 Gustl22
* Copyright 2018 Bezzu * Copyright 2018 Bezzu
@ -31,6 +31,7 @@ import org.oscim.layers.tile.MapTile;
import org.oscim.layers.tile.buildings.BuildingLayer; import org.oscim.layers.tile.buildings.BuildingLayer;
import org.oscim.tiling.ITileDataSink; import org.oscim.tiling.ITileDataSink;
import org.oscim.tiling.ITileDataSource; import org.oscim.tiling.ITileDataSource;
import org.oscim.tiling.TileDataSink;
import org.oscim.tiling.source.mapfile.header.SubFileParameter; import org.oscim.tiling.source.mapfile.header.SubFileParameter;
import org.oscim.utils.Parameters; import org.oscim.utils.Parameters;
import org.oscim.utils.geom.TileClipper; import org.oscim.utils.geom.TileClipper;
@ -224,6 +225,9 @@ public class MapDatabase implements ITileDataSource {
private int zoomLevelMin = 0; private int zoomLevelMin = 0;
private int zoomLevelMax = Byte.MAX_VALUE; private int zoomLevelMax = Byte.MAX_VALUE;
private boolean deduplicate;
private int level;
public MapDatabase(MapFileTileSource tileSource) throws IOException { public MapDatabase(MapFileTileSource tileSource) throws IOException {
mTileSource = tileSource; mTileSource = tileSource;
try { try {
@ -306,7 +310,10 @@ public class MapDatabase implements ITileDataSource {
QueryCalculations.calculateBaseTiles(queryParameters, tile, subFileParameter); QueryCalculations.calculateBaseTiles(queryParameters, tile, subFileParameter);
QueryCalculations.calculateBlocks(queryParameters, subFileParameter); QueryCalculations.calculateBlocks(queryParameters, subFileParameter);
processBlocks(sink, queryParameters, subFileParameter); if (deduplicate)
processBlocks(sink, queryParameters, subFileParameter, tile.getBoundingBox(), Selector.ALL, new MapReadResult());
else
processBlocks(sink, queryParameters, subFileParameter);
} catch (IOException e) { } catch (IOException e) {
log.error(e.getMessage()); log.error(e.getMessage());
sink.completed(FAILED); sink.completed(FAILED);
@ -424,6 +431,14 @@ public class MapDatabase implements ITileDataSource {
} }
} }
void setDeduplicate(boolean deduplicate) {
this.deduplicate = deduplicate;
}
void setLevel(int level) {
this.level = level;
}
private void setTileClipping(QueryParameters queryParameters, SubFileParameter subFileParameter, private void setTileClipping(QueryParameters queryParameters, SubFileParameter subFileParameter,
long currentRow, long currentCol) { long currentRow, long currentCol) {
long numRows = queryParameters.toBlockY - queryParameters.fromBlockY; long numRows = queryParameters.toBlockY - queryParameters.fromBlockY;
@ -693,7 +708,9 @@ public class MapDatabase implements ITileDataSource {
continue; continue;
e.setLayer(layer); e.setLayer(layer);
e.level = level;
PointOfInterest poi = null;
if (pois != null) { if (pois != null) {
List<Tag> tags = new ArrayList<>(); List<Tag> tags = new ArrayList<>();
for (int i = 0; i < e.tags.size(); i++) for (int i = 0; i < e.tags.size(); i++)
@ -702,12 +719,15 @@ public class MapDatabase implements ITileDataSource {
// depending on the zoom level configuration the poi can lie outside // depending on the zoom level configuration the poi can lie outside
// the tile requested, we filter them out here // the tile requested, we filter them out here
if (!filterRequired || boundingBox.contains(position)) { if (!filterRequired || boundingBox.contains(position)) {
pois.add(new PointOfInterest(layer, tags, position)); poi = new PointOfInterest(layer, tags, position);
pois.add(poi);
} }
} }
if (mapDataSink != null) if (mapDataSink != null) {
mapDataSink.process(e); if (!deduplicate || poi == null || ((TileDataSink) mapDataSink).hashPois.add(poi.hashCode()))
mapDataSink.process(e);
}
} }
return true; return true;
@ -1046,7 +1066,9 @@ public class MapDatabase implements ITileDataSource {
e.simplify(1, true); e.simplify(1, true);
e.setLayer(layer); e.setLayer(layer);
e.level = level;
Way way = null;
if (ways != null) { if (ways != null) {
BoundingBox wayFilterBbox = boundingBox.extendMeters(wayFilterDistance); BoundingBox wayFilterBbox = boundingBox.extendMeters(wayFilterDistance);
GeoPoint[][] wayNodesArray = wayNodes.toArray(new GeoPoint[wayNodes.size()][]); GeoPoint[][] wayNodesArray = wayNodes.toArray(new GeoPoint[wayNodes.size()][]);
@ -1056,13 +1078,16 @@ public class MapDatabase implements ITileDataSource {
tags.add(e.tags.get(i)); tags.add(e.tags.get(i));
if (Selector.ALL == selector || hasName || hasHouseNr || hasRef || wayAsLabelTagFilter(tags)) { if (Selector.ALL == selector || hasName || hasHouseNr || hasRef || wayAsLabelTagFilter(tags)) {
GeoPoint labelPos = labelPosition != null ? new GeoPoint(labelPosition[1] / 1E6, labelPosition[0] / 1E6) : null; GeoPoint labelPos = labelPosition != null ? new GeoPoint(labelPosition[1] / 1E6, labelPosition[0] / 1E6) : null;
ways.add(new Way(layer, tags, wayNodesArray, labelPos, e.type)); way = new Way(layer, tags, wayNodesArray, labelPos, e.type);
ways.add(way);
} }
} }
} }
if (mapDataSink != null) if (mapDataSink != null) {
mapDataSink.process(e); if (!deduplicate || way == null || ((TileDataSink) mapDataSink).hashWays.add(way.hashCode()))
mapDataSink.process(e);
}
} }
} }

View File

@ -1,7 +1,7 @@
/* /*
* Copyright 2010, 2011, 2012, 2013 mapsforge.org * Copyright 2010, 2011, 2012, 2013 mapsforge.org
* Copyright 2014-2015 Ludwig M Brinckmann * Copyright 2014-2015 Ludwig M Brinckmann
* Copyright 2017 devemux86 * Copyright 2015-2022 devemux86
* *
* This program is free software: you can redistribute it and/or modify it under the * This program is free software: you can redistribute it and/or modify it under the
* terms of the GNU Lesser General Public License as published by the Free Software * terms of the GNU Lesser General Public License as published by the Free Software
@ -17,13 +17,21 @@
package org.oscim.tiling.source.mapfile; package org.oscim.tiling.source.mapfile;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Set;
/** /**
* An immutable container for the data returned from a MapDataStore. * An immutable container for the data returned from a MapDataStore.
*/ */
public class MapReadResult { public class MapReadResult {
/**
* Hash codes.
*/
private final Set<Integer> hashPois = new HashSet<>();
private final Set<Integer> hashWays = new HashSet<>();
/** /**
* True if the read area is completely covered by water, false otherwise. * True if the read area is completely covered by water, false otherwise.
*/ */
@ -50,8 +58,8 @@ public class MapReadResult {
} }
/** /**
* Adds other MapReadResult by combining pois and ways. Optionally, deduplication can * Adds other MapReadResult by combining pois and ways.
* be requested (much more expensive). * Optionally deduplication can be requested (more expensive).
* *
* @param other the MapReadResult to add to this. * @param other the MapReadResult to add to this.
* @param deduplicate true if check for duplicates is required. * @param deduplicate true if check for duplicates is required.
@ -59,12 +67,12 @@ public class MapReadResult {
public void add(MapReadResult other, boolean deduplicate) { public void add(MapReadResult other, boolean deduplicate) {
if (deduplicate) { if (deduplicate) {
for (PointOfInterest poi : other.pointOfInterests) { for (PointOfInterest poi : other.pointOfInterests) {
if (!this.pointOfInterests.contains(poi)) { if (this.hashPois.add(poi.hashCode())) {
this.pointOfInterests.add(poi); this.pointOfInterests.add(poi);
} }
} }
for (Way way : other.ways) { for (Way way : other.ways) {
if (!this.ways.contains(way)) { if (this.hashWays.add(way.hashCode())) {
this.ways.add(way); this.ways.add(way);
} }
} }
@ -73,5 +81,4 @@ public class MapReadResult {
this.ways.addAll(other.ways); this.ways.addAll(other.ways);
} }
} }
} }

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2016-2018 devemux86 * Copyright 2016-2022 devemux86
* *
* This program is free software: you can redistribute it and/or modify it under the * This program is free software: you can redistribute it and/or modify it under the
* terms of the GNU Lesser General Public License as published by the Free Software * terms of the GNU Lesser General Public License as published by the Free Software
@ -18,6 +18,7 @@ import org.oscim.core.Tile;
import org.oscim.layers.tile.MapTile; import org.oscim.layers.tile.MapTile;
import org.oscim.tiling.ITileDataSink; import org.oscim.tiling.ITileDataSink;
import org.oscim.tiling.ITileDataSource; import org.oscim.tiling.ITileDataSource;
import org.oscim.tiling.QueryResult;
import org.oscim.tiling.TileDataSink; import org.oscim.tiling.TileDataSink;
import java.util.ArrayList; import java.util.ArrayList;
@ -25,9 +26,15 @@ import java.util.List;
public class MultiMapDatabase implements ITileDataSource { public class MultiMapDatabase implements ITileDataSource {
private final boolean deduplicate;
private final List<MapDatabase> mapDatabases = new ArrayList<>(); private final List<MapDatabase> mapDatabases = new ArrayList<>();
public MultiMapDatabase() { public MultiMapDatabase() {
this(false);
}
public MultiMapDatabase(boolean deduplicate) {
this.deduplicate = deduplicate;
} }
public boolean add(MapDatabase mapDatabase) { public boolean add(MapDatabase mapDatabase) {
@ -39,12 +46,29 @@ public class MultiMapDatabase implements ITileDataSource {
@Override @Override
public void query(MapTile tile, ITileDataSink sink) { public void query(MapTile tile, ITileDataSink sink) {
TileDataSink dataSink = new TileDataSink(sink); boolean deduplicate = this.deduplicate;
for (MapDatabase mapDatabase : mapDatabases) { if (deduplicate) {
if (mapDatabase.supportsTile(tile)) int n = 0;
mapDatabase.query(tile, dataSink); for (MapDatabase mapDatabase : mapDatabases) {
if (mapDatabase.supportsTile(tile)) {
if (++n > 1) {
break;
}
}
}
deduplicate = n > 1;
} }
sink.completed(dataSink.getResult());
TileDataSink dataSink = new TileDataSink(sink);
for (int i = 0; i < mapDatabases.size(); i++) {
MapDatabase mapDatabase = mapDatabases.get(i);
if (mapDatabase.supportsTile(tile)) {
mapDatabase.setDeduplicate(deduplicate);
mapDatabase.setLevel(i);
mapDatabase.query(tile, dataSink);
}
}
sink.completed(QueryResult.SUCCESS);
} }
@Override @Override
@ -61,7 +85,7 @@ public class MultiMapDatabase implements ITileDataSource {
} }
} }
public MapReadResult readLabels(Tile tile) { public MapReadResult readLabels(Tile tile, boolean deduplicate) {
MapReadResult mapReadResult = new MapReadResult(); MapReadResult mapReadResult = new MapReadResult();
for (MapDatabase mdb : mapDatabases) { for (MapDatabase mdb : mapDatabases) {
if (mdb.supportsTile(tile)) { if (mdb.supportsTile(tile)) {
@ -71,13 +95,13 @@ public class MultiMapDatabase implements ITileDataSource {
} }
boolean isWater = mapReadResult.isWater & result.isWater; boolean isWater = mapReadResult.isWater & result.isWater;
mapReadResult.isWater = isWater; mapReadResult.isWater = isWater;
mapReadResult.add(result, false); mapReadResult.add(result, deduplicate);
} }
} }
return mapReadResult; return mapReadResult;
} }
public MapReadResult readLabels(Tile upperLeft, Tile lowerRight) { public MapReadResult readLabels(Tile upperLeft, Tile lowerRight, boolean deduplicate) {
MapReadResult mapReadResult = new MapReadResult(); MapReadResult mapReadResult = new MapReadResult();
for (MapDatabase mdb : mapDatabases) { for (MapDatabase mdb : mapDatabases) {
if (mdb.supportsTile(upperLeft)) { if (mdb.supportsTile(upperLeft)) {
@ -87,13 +111,13 @@ public class MultiMapDatabase implements ITileDataSource {
} }
boolean isWater = mapReadResult.isWater & result.isWater; boolean isWater = mapReadResult.isWater & result.isWater;
mapReadResult.isWater = isWater; mapReadResult.isWater = isWater;
mapReadResult.add(result, false); mapReadResult.add(result, deduplicate);
} }
} }
return mapReadResult; return mapReadResult;
} }
public MapReadResult readMapData(Tile tile) { public MapReadResult readMapData(Tile tile, boolean deduplicate) {
MapReadResult mapReadResult = new MapReadResult(); MapReadResult mapReadResult = new MapReadResult();
for (MapDatabase mdb : mapDatabases) { for (MapDatabase mdb : mapDatabases) {
if (mdb.supportsTile(tile)) { if (mdb.supportsTile(tile)) {
@ -103,13 +127,13 @@ public class MultiMapDatabase implements ITileDataSource {
} }
boolean isWater = mapReadResult.isWater & result.isWater; boolean isWater = mapReadResult.isWater & result.isWater;
mapReadResult.isWater = isWater; mapReadResult.isWater = isWater;
mapReadResult.add(result, false); mapReadResult.add(result, deduplicate);
} }
} }
return mapReadResult; return mapReadResult;
} }
public MapReadResult readMapData(Tile upperLeft, Tile lowerRight) { public MapReadResult readMapData(Tile upperLeft, Tile lowerRight, boolean deduplicate) {
MapReadResult mapReadResult = new MapReadResult(); MapReadResult mapReadResult = new MapReadResult();
for (MapDatabase mdb : mapDatabases) { for (MapDatabase mdb : mapDatabases) {
if (mdb.supportsTile(upperLeft)) { if (mdb.supportsTile(upperLeft)) {
@ -119,13 +143,13 @@ public class MultiMapDatabase implements ITileDataSource {
} }
boolean isWater = mapReadResult.isWater & result.isWater; boolean isWater = mapReadResult.isWater & result.isWater;
mapReadResult.isWater = isWater; mapReadResult.isWater = isWater;
mapReadResult.add(result, false); mapReadResult.add(result, deduplicate);
} }
} }
return mapReadResult; return mapReadResult;
} }
public MapReadResult readPoiData(Tile tile) { public MapReadResult readPoiData(Tile tile, boolean deduplicate) {
MapReadResult mapReadResult = new MapReadResult(); MapReadResult mapReadResult = new MapReadResult();
for (MapDatabase mdb : mapDatabases) { for (MapDatabase mdb : mapDatabases) {
if (mdb.supportsTile(tile)) { if (mdb.supportsTile(tile)) {
@ -135,13 +159,13 @@ public class MultiMapDatabase implements ITileDataSource {
} }
boolean isWater = mapReadResult.isWater & result.isWater; boolean isWater = mapReadResult.isWater & result.isWater;
mapReadResult.isWater = isWater; mapReadResult.isWater = isWater;
mapReadResult.add(result, false); mapReadResult.add(result, deduplicate);
} }
} }
return mapReadResult; return mapReadResult;
} }
public MapReadResult readPoiData(Tile upperLeft, Tile lowerRight) { public MapReadResult readPoiData(Tile upperLeft, Tile lowerRight, boolean deduplicate) {
MapReadResult mapReadResult = new MapReadResult(); MapReadResult mapReadResult = new MapReadResult();
for (MapDatabase mdb : mapDatabases) { for (MapDatabase mdb : mapDatabases) {
if (mdb.supportsTile(upperLeft)) { if (mdb.supportsTile(upperLeft)) {
@ -151,7 +175,7 @@ public class MultiMapDatabase implements ITileDataSource {
} }
boolean isWater = mapReadResult.isWater & result.isWater; boolean isWater = mapReadResult.isWater & result.isWater;
mapReadResult.isWater = isWater; mapReadResult.isWater = isWater;
mapReadResult.add(result, false); mapReadResult.add(result, deduplicate);
} }
} }
return mapReadResult; return mapReadResult;

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2016-2018 devemux86 * Copyright 2016-2022 devemux86
* *
* This program is free software: you can redistribute it and/or modify it under the * This program is free software: you can redistribute it and/or modify it under the
* terms of the GNU Lesser General Public License as published by the Free Software * terms of the GNU Lesser General Public License as published by the Free Software
@ -33,6 +33,7 @@ public class MultiMapFileTileSource extends TileSource implements IMapFileTileSo
private static final Logger log = LoggerFactory.getLogger(MultiMapFileTileSource.class); private static final Logger log = LoggerFactory.getLogger(MultiMapFileTileSource.class);
private boolean deduplicate;
private final List<MapFileTileSource> mapFileTileSources = new ArrayList<>(); private final List<MapFileTileSource> mapFileTileSources = new ArrayList<>();
private final Map<MapFileTileSource, int[]> zoomsByTileSource = new HashMap<>(); private final Map<MapFileTileSource, int[]> zoomsByTileSource = new HashMap<>();
@ -72,7 +73,7 @@ public class MultiMapFileTileSource extends TileSource implements IMapFileTileSo
@Override @Override
public ITileDataSource getDataSource() { public ITileDataSource getDataSource() {
MultiMapDatabase multiMapDatabase = new MultiMapDatabase(); MultiMapDatabase multiMapDatabase = new MultiMapDatabase(deduplicate);
for (MapFileTileSource mapFileTileSource : mapFileTileSources) { for (MapFileTileSource mapFileTileSource : mapFileTileSources) {
try { try {
MapDatabase mapDatabase = new MapDatabase(mapFileTileSource); MapDatabase mapDatabase = new MapDatabase(mapFileTileSource);
@ -112,6 +113,10 @@ public class MultiMapFileTileSource extends TileSource implements IMapFileTileSo
} }
} }
public void setDeduplicate(boolean deduplicate) {
this.deduplicate = deduplicate;
}
@Override @Override
public void setPreferredLanguage(String preferredLanguage) { public void setPreferredLanguage(String preferredLanguage) {
for (MapFileTileSource mapFileTileSource : mapFileTileSources) { for (MapFileTileSource mapFileTileSource : mapFileTileSources) {