* Mapsforge Reverse Geocoding #383 * Mapsforge Reverse Geocoding example #383
This commit is contained in:
@@ -6,6 +6,7 @@
|
||||
- Render themes: line symbol [#124](https://github.com/mapsforge/vtm/issues/124)
|
||||
- Render themes: stroke dash array [#131](https://github.com/mapsforge/vtm/issues/131)
|
||||
- POI Search example [#394](https://github.com/mapsforge/vtm/issues/394)
|
||||
- Mapsforge Reverse Geocoding [#383](https://github.com/mapsforge/vtm/issues/383)
|
||||
- Core utilities [#396](https://github.com/mapsforge/vtm/issues/396)
|
||||
- Mapsforge fix artifacts zoom > 17 [#231](https://github.com/mapsforge/vtm/issues/231)
|
||||
- vtm-theme-comparator module [#387](https://github.com/mapsforge/vtm/issues/387)
|
||||
|
||||
@@ -97,6 +97,9 @@
|
||||
<activity
|
||||
android:name=".POTTextureActivity"
|
||||
android:configChanges="keyboardHidden|orientation|screenSize" />
|
||||
<activity
|
||||
android:name=".ReverseGeocodeActivity"
|
||||
android:configChanges="keyboardHidden|orientation|screenSize" />
|
||||
<activity
|
||||
android:name=".RotateMarkerOverlayActivity"
|
||||
android:configChanges="keyboardHidden|orientation|screenSize" />
|
||||
|
||||
@@ -18,5 +18,6 @@
|
||||
<string name="style_1">Show nature</string>
|
||||
<string name="style_2">Hide nature</string>
|
||||
<string name="menu_gridlayer">Grid</string>
|
||||
<string name="dialog_reverse_geocoding_title">Reverse Geocoding</string>
|
||||
|
||||
</resources>
|
||||
|
||||
@@ -53,6 +53,7 @@ public class MapsforgeMapActivity extends MapActivity {
|
||||
private TileGridLayer mGridLayer;
|
||||
private DefaultMapScaleBar mMapScaleBar;
|
||||
private Menu mMenu;
|
||||
MapFileTileSource mTileSource;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
@@ -152,12 +153,12 @@ public class MapsforgeMapActivity extends MapActivity {
|
||||
return;
|
||||
}
|
||||
|
||||
MapFileTileSource tileSource = new MapFileTileSource();
|
||||
tileSource.setPreferredLanguage("en");
|
||||
mTileSource = new MapFileTileSource();
|
||||
mTileSource.setPreferredLanguage("en");
|
||||
String file = intent.getStringExtra(FilePicker.SELECTED_FILE);
|
||||
if (tileSource.setMapFile(file)) {
|
||||
if (mTileSource.setMapFile(file)) {
|
||||
|
||||
VectorTileLayer l = mMap.setBaseMap(tileSource);
|
||||
VectorTileLayer l = mMap.setBaseMap(mTileSource);
|
||||
loadTheme(null);
|
||||
|
||||
mMap.layers().add(new BuildingLayer(mMap, l));
|
||||
@@ -175,7 +176,7 @@ public class MapsforgeMapActivity extends MapActivity {
|
||||
renderer.setOffset(5 * getResources().getDisplayMetrics().density, 0);
|
||||
mMap.layers().add(mapScaleBarLayer);
|
||||
|
||||
MapInfo info = tileSource.getMapInfo();
|
||||
MapInfo info = mTileSource.getMapInfo();
|
||||
MapPosition pos = new MapPosition();
|
||||
pos.setByBoundingBox(info.boundingBox, Tile.SIZE * 4, Tile.SIZE * 4);
|
||||
mMap.setMapPosition(pos);
|
||||
|
||||
@@ -86,8 +86,11 @@ public class PoiSearchActivity extends MapsforgeMapActivity implements ItemizedL
|
||||
super.onActivityResult(requestCode, resultCode, intent);
|
||||
|
||||
if (requestCode == SELECT_MAP_FILE) {
|
||||
startActivityForResult(new Intent(this, PoiFilePicker.class),
|
||||
SELECT_POI_FILE);
|
||||
if (mTileSource != null)
|
||||
startActivityForResult(new Intent(this, PoiFilePicker.class),
|
||||
SELECT_POI_FILE);
|
||||
else
|
||||
finish();
|
||||
} else if (requestCode == SELECT_POI_FILE) {
|
||||
if (resultCode != RESULT_OK || intent == null || intent.getStringExtra(FilePicker.SELECTED_FILE) == null) {
|
||||
finish();
|
||||
|
||||
@@ -0,0 +1,145 @@
|
||||
/*
|
||||
* Copyright 2017 devemux86
|
||||
*
|
||||
* 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
|
||||
* Foundation, either version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
|
||||
* PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License along with
|
||||
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.oscim.android.test;
|
||||
|
||||
import android.app.AlertDialog;
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.view.Menu;
|
||||
|
||||
import org.oscim.backend.CanvasAdapter;
|
||||
import org.oscim.core.GeoPoint;
|
||||
import org.oscim.core.GeometryBuffer;
|
||||
import org.oscim.core.MercatorProjection;
|
||||
import org.oscim.core.Point;
|
||||
import org.oscim.core.Tag;
|
||||
import org.oscim.core.Tile;
|
||||
import org.oscim.event.Gesture;
|
||||
import org.oscim.event.GestureListener;
|
||||
import org.oscim.event.MotionEvent;
|
||||
import org.oscim.layers.Layer;
|
||||
import org.oscim.layers.TileGridLayer;
|
||||
import org.oscim.map.Map;
|
||||
import org.oscim.tiling.source.mapfile.MapDatabase;
|
||||
import org.oscim.tiling.source.mapfile.MapReadResult;
|
||||
import org.oscim.tiling.source.mapfile.PointOfInterest;
|
||||
import org.oscim.tiling.source.mapfile.Way;
|
||||
import org.oscim.utils.GeoPointUtils;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Reverse Geocoding with long press.
|
||||
* <p/>
|
||||
* - POI in specified radius.<br/>
|
||||
* - Ways containing touch point.
|
||||
*/
|
||||
public class ReverseGeocodeActivity extends MapsforgeMapActivity {
|
||||
|
||||
private static final int TOUCH_RADIUS = 32 / 2;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
// Map events receiver
|
||||
mMap.layers().add(new MapEventsReceiver(mMap));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onCreateOptionsMenu(Menu menu) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onActivityResult(int requestCode, int resultCode, Intent intent) {
|
||||
super.onActivityResult(requestCode, resultCode, intent);
|
||||
|
||||
if (requestCode == SELECT_MAP_FILE) {
|
||||
// For debug
|
||||
TileGridLayer gridLayer = new TileGridLayer(mMap, getResources().getDisplayMetrics().density);
|
||||
mMap.layers().add(gridLayer);
|
||||
}
|
||||
}
|
||||
|
||||
private class MapEventsReceiver extends Layer implements GestureListener {
|
||||
|
||||
MapEventsReceiver(Map map) {
|
||||
super(map);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onGesture(Gesture g, MotionEvent e) {
|
||||
if (g instanceof Gesture.LongPress) {
|
||||
GeoPoint p = mMap.viewport().fromScreenPoint(e.getX(), e.getY());
|
||||
|
||||
// Read all labeled POI and ways for the area covered by the tiles under touch
|
||||
float touchRadius = TOUCH_RADIUS * CanvasAdapter.dpi / CanvasAdapter.DEFAULT_DPI;
|
||||
long mapSize = MercatorProjection.getMapSize((byte) mMap.getMapPosition().getZoomLevel());
|
||||
double pixelX = MercatorProjection.longitudeToPixelX(p.getLongitude(), mapSize);
|
||||
double pixelY = MercatorProjection.latitudeToPixelY(p.getLatitude(), mapSize);
|
||||
int tileXMin = MercatorProjection.pixelXToTileX(pixelX - touchRadius, (byte) mMap.getMapPosition().getZoomLevel());
|
||||
int tileXMax = MercatorProjection.pixelXToTileX(pixelX + touchRadius, (byte) mMap.getMapPosition().getZoomLevel());
|
||||
int tileYMin = MercatorProjection.pixelYToTileY(pixelY - touchRadius, (byte) mMap.getMapPosition().getZoomLevel());
|
||||
int tileYMax = MercatorProjection.pixelYToTileY(pixelY + touchRadius, (byte) mMap.getMapPosition().getZoomLevel());
|
||||
Tile upperLeft = new Tile(tileXMin, tileYMin, (byte) mMap.getMapPosition().getZoomLevel());
|
||||
Tile lowerRight = new Tile(tileXMax, tileYMax, (byte) mMap.getMapPosition().getZoomLevel());
|
||||
MapReadResult mapReadResult = ((MapDatabase) mTileSource.getDataSource()).readLabels(upperLeft, lowerRight);
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
// Filter POI
|
||||
sb.append("*** POI ***");
|
||||
for (PointOfInterest pointOfInterest : mapReadResult.pointOfInterests) {
|
||||
Point layerXY = new Point();
|
||||
mMap.viewport().toScreenPoint(pointOfInterest.position, false, layerXY);
|
||||
Point tapXY = new Point(e.getX(), e.getY());
|
||||
if (layerXY.distance(tapXY) > touchRadius) {
|
||||
continue;
|
||||
}
|
||||
sb.append("\n");
|
||||
List<Tag> tags = pointOfInterest.tags;
|
||||
for (Tag tag : tags) {
|
||||
sb.append("\n").append(tag.key).append("=").append(tag.value);
|
||||
}
|
||||
}
|
||||
|
||||
// Filter ways
|
||||
sb.append("\n\n").append("*** WAYS ***");
|
||||
for (Way way : mapReadResult.ways) {
|
||||
if (way.geometryType != GeometryBuffer.GeometryType.POLY
|
||||
|| !GeoPointUtils.contains(way.geoPoints[0], p)) {
|
||||
continue;
|
||||
}
|
||||
sb.append("\n");
|
||||
List<Tag> tags = way.tags;
|
||||
for (Tag tag : tags) {
|
||||
sb.append("\n").append(tag.key).append("=").append(tag.value);
|
||||
}
|
||||
}
|
||||
|
||||
AlertDialog.Builder builder = new AlertDialog.Builder(ReverseGeocodeActivity.this);
|
||||
builder.setIcon(android.R.drawable.ic_menu_search);
|
||||
builder.setTitle(R.string.dialog_reverse_geocoding_title);
|
||||
builder.setMessage(sb);
|
||||
builder.setPositiveButton(R.string.ok, null);
|
||||
builder.show();
|
||||
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -122,6 +122,7 @@ public class Samples extends Activity {
|
||||
linearLayout.addView(createButton(MultiMapActivity.class));
|
||||
|
||||
linearLayout.addView(createLabel("Experiments"));
|
||||
linearLayout.addView(createButton(ReverseGeocodeActivity.class));
|
||||
linearLayout.addView(createButton(MapPositionActivity.class));
|
||||
linearLayout.addView(createButton(S3DBMapActivity.class));
|
||||
linearLayout.addView(createButton(ThemeStylerActivity.class));
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
/*
|
||||
* Copyright 2012, 2013 Hannes Janetzek
|
||||
* Copyright 2017 devemux86
|
||||
*
|
||||
* This file is part of the OpenScienceMap project (http://www.opensciencemap.org).
|
||||
*
|
||||
@@ -158,6 +159,10 @@ public class MapTile extends Tile {
|
||||
}
|
||||
}
|
||||
|
||||
public MapTile(int tileX, int tileY, int zoomLevel) {
|
||||
this(null, tileX, tileY, zoomLevel);
|
||||
}
|
||||
|
||||
public MapTile(TileNode node, int tileX, int tileY, int zoomLevel) {
|
||||
super(tileX, tileY, (byte) zoomLevel);
|
||||
this.x = (double) tileX / (1 << zoomLevel);
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
/*
|
||||
* Copyright 2010, 2011, 2012 mapsforge.org
|
||||
* Copyright 2013, 2014 Hannes Janetzek
|
||||
* Copyright 2014-2015 Ludwig M Brinckmann
|
||||
* Copyright 2016-2017 devemux86
|
||||
* Copyright 2016 Andrey Novikov
|
||||
*
|
||||
@@ -20,6 +21,8 @@
|
||||
package org.oscim.tiling.source.mapfile;
|
||||
|
||||
import org.oscim.backend.CanvasAdapter;
|
||||
import org.oscim.core.BoundingBox;
|
||||
import org.oscim.core.GeoPoint;
|
||||
import org.oscim.core.GeometryBuffer.GeometryType;
|
||||
import org.oscim.core.MapElement;
|
||||
import org.oscim.core.MercatorProjection;
|
||||
@@ -35,6 +38,9 @@ import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.RandomAccessFile;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import static org.oscim.core.GeometryBuffer.GeometryType.LINE;
|
||||
import static org.oscim.core.GeometryBuffer.GeometryType.POLY;
|
||||
@@ -167,6 +173,18 @@ public class MapDatabase implements ITileDataSource {
|
||||
*/
|
||||
private static final int WAY_NUMBER_OF_TAGS_BITMASK = 0x0f;
|
||||
|
||||
/**
|
||||
* Way filtering reduces the number of ways returned to only those that are
|
||||
* relevant for the tile requested, leading to performance gains, but can
|
||||
* cause line clipping artifacts (particularly at higher zoom levels). The
|
||||
* risk of clipping can be reduced by either turning way filtering off or by
|
||||
* increasing the wayFilterDistance which governs how large an area surrounding
|
||||
* the requested tile will be returned.
|
||||
* For most use cases the standard settings should be sufficient.
|
||||
*/
|
||||
public static boolean wayFilterEnabled = true;
|
||||
public static int wayFilterDistance = 20;
|
||||
|
||||
private long mFileSize;
|
||||
private boolean mDebugFile;
|
||||
private RandomAccessFile mInputFile;
|
||||
@@ -187,6 +205,9 @@ public class MapDatabase implements ITileDataSource {
|
||||
|
||||
private final MapFileTileSource mTileSource;
|
||||
|
||||
private int zoomLevelMin = 0;
|
||||
private int zoomLevelMax = Byte.MAX_VALUE;
|
||||
|
||||
public MapDatabase(MapFileTileSource tileSource) throws IOException {
|
||||
mTileSource = tileSource;
|
||||
try {
|
||||
@@ -305,7 +326,9 @@ public class MapDatabase implements ITileDataSource {
|
||||
* @param mapDataSink the callback which handles the extracted map elements.
|
||||
*/
|
||||
private void processBlock(QueryParameters queryParameters,
|
||||
SubFileParameter subFileParameter, ITileDataSink mapDataSink) {
|
||||
SubFileParameter subFileParameter, ITileDataSink mapDataSink,
|
||||
BoundingBox boundingBox, Selector selector,
|
||||
MapReadResult mapReadResult) {
|
||||
|
||||
if (!processBlockSignature()) {
|
||||
return;
|
||||
@@ -339,7 +362,13 @@ public class MapDatabase implements ITileDataSource {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!processPOIs(mapDataSink, poisOnQueryZoomLevel)) {
|
||||
boolean filterRequired = queryParameters.queryZoomLevel > subFileParameter.baseZoomLevel;
|
||||
|
||||
List<PointOfInterest> pois = null;
|
||||
if (mapReadResult != null)
|
||||
pois = new ArrayList<>();
|
||||
|
||||
if (!processPOIs(mapDataSink, poisOnQueryZoomLevel, boundingBox, filterRequired, pois)) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -355,10 +384,19 @@ public class MapDatabase implements ITileDataSource {
|
||||
/* move the pointer to the first way */
|
||||
mReadBuffer.setBufferPosition(firstWayOffset);
|
||||
|
||||
if (!processWays(queryParameters, mapDataSink, waysOnQueryZoomLevel)) {
|
||||
List<Way> ways = null;
|
||||
if (mapReadResult != null && Selector.POIS != selector)
|
||||
ways = new ArrayList<>();
|
||||
|
||||
if (!processWays(queryParameters, mapDataSink, waysOnQueryZoomLevel, boundingBox, filterRequired, selector, ways)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (mapReadResult != null) {
|
||||
if (Selector.POIS == selector)
|
||||
ways = Collections.emptyList();
|
||||
mapReadResult.add(new PoiWayBundle(pois, ways));
|
||||
}
|
||||
}
|
||||
|
||||
// private long mCurrentRow;
|
||||
@@ -405,8 +443,26 @@ public class MapDatabase implements ITileDataSource {
|
||||
|
||||
//private final static Tag mWaterTag = new Tag("natural", "water");
|
||||
|
||||
/**
|
||||
* Map rendering.
|
||||
*/
|
||||
private void processBlocks(ITileDataSink mapDataSink, QueryParameters queryParams,
|
||||
SubFileParameter subFileParameter) throws IOException {
|
||||
processBlocks(mapDataSink, queryParams, subFileParameter, null, null, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Map data reading.
|
||||
*/
|
||||
private void processBlocks(QueryParameters queryParams,
|
||||
SubFileParameter subFileParameter, BoundingBox boundingBox,
|
||||
Selector selector, MapReadResult mapReadResult) throws IOException {
|
||||
processBlocks(null, queryParams, subFileParameter, boundingBox, selector, mapReadResult);
|
||||
}
|
||||
|
||||
private void processBlocks(ITileDataSink mapDataSink, QueryParameters queryParams,
|
||||
SubFileParameter subFileParameter, BoundingBox boundingBox,
|
||||
Selector selector, MapReadResult mapReadResult) throws IOException {
|
||||
|
||||
/* read and process all blocks from top to bottom and from left to right */
|
||||
for (long row = queryParams.fromBlockY; row <= queryParams.toBlockY; row++) {
|
||||
@@ -508,7 +564,7 @@ public class MapDatabase implements ITileDataSource {
|
||||
mTileLatitude = (int) (tileLatitudeDeg * 1E6);
|
||||
mTileLongitude = (int) (tileLongitudeDeg * 1E6);
|
||||
|
||||
processBlock(queryParams, subFileParameter, mapDataSink);
|
||||
processBlock(queryParams, subFileParameter, mapDataSink, boundingBox, selector, mapReadResult);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -539,7 +595,8 @@ public class MapDatabase implements ITileDataSource {
|
||||
* @return true if the POIs could be processed successfully, false
|
||||
* otherwise.
|
||||
*/
|
||||
private boolean processPOIs(ITileDataSink mapDataSink, int numberOfPois) {
|
||||
private boolean processPOIs(ITileDataSink mapDataSink, int numberOfPois, BoundingBox boundingBox,
|
||||
boolean filterRequired, List<PointOfInterest> pois) {
|
||||
Tag[] poiTags = mTileSource.fileInfo.poiTags;
|
||||
MapElement e = mElem;
|
||||
|
||||
@@ -605,13 +662,26 @@ public class MapDatabase implements ITileDataSource {
|
||||
|
||||
e.setLayer(layer);
|
||||
|
||||
mapDataSink.process(e);
|
||||
if (pois != null) {
|
||||
List<Tag> tags = new ArrayList<>();
|
||||
for (int i = 0; i < e.tags.numTags; i++)
|
||||
tags.add(e.tags.tags[i]);
|
||||
GeoPoint position = new GeoPoint(latitude, longitude);
|
||||
// depending on the zoom level configuration the poi can lie outside
|
||||
// the tile requested, we filter them out here
|
||||
if (!filterRequired || boundingBox.contains(position)) {
|
||||
pois.add(new PointOfInterest(layer, tags, position));
|
||||
}
|
||||
}
|
||||
|
||||
if (mapDataSink != null)
|
||||
mapDataSink.process(e);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private boolean processWayDataBlock(MapElement e, boolean doubleDeltaEncoding, boolean isLine) {
|
||||
private boolean processWayDataBlock(MapElement e, boolean doubleDeltaEncoding, boolean isLine, List<GeoPoint[]> wayCoordinates) {
|
||||
/* get and check the number of way coordinate blocks (VBE-U) */
|
||||
int numBlocks = mReadBuffer.readUnsignedInt();
|
||||
if (numBlocks < 1 || numBlocks > Short.MAX_VALUE) {
|
||||
@@ -638,6 +708,14 @@ public class MapDatabase implements ITileDataSource {
|
||||
|
||||
wayLengths[coordinateBlock] = decodeWayNodes(doubleDeltaEncoding,
|
||||
e, len, isLine);
|
||||
|
||||
if (wayCoordinates != null) {
|
||||
// create the array which will store the current way segment
|
||||
GeoPoint[] waySegment = new GeoPoint[e.getNumPoints()];
|
||||
for (int i = 0; i < e.getNumPoints(); i++)
|
||||
waySegment[i] = new GeoPoint(e.getPointY(i) / 1E6, e.getPointX(i) / 1E6);
|
||||
wayCoordinates.add(waySegment);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
@@ -712,8 +790,9 @@ public class MapDatabase implements ITileDataSource {
|
||||
* @return true if the ways could be processed successfully, false
|
||||
* otherwise.
|
||||
*/
|
||||
private boolean processWays(QueryParameters queryParameters,
|
||||
ITileDataSink mapDataSink, int numberOfWays) {
|
||||
private boolean processWays(QueryParameters queryParameters, ITileDataSink mapDataSink,
|
||||
int numberOfWays, BoundingBox boundingBox, boolean filterRequired,
|
||||
Selector selector, List<Way> ways) {
|
||||
|
||||
Tag[] wayTags = mTileSource.fileInfo.wayTags;
|
||||
MapElement e = mElem;
|
||||
@@ -866,7 +945,11 @@ public class MapDatabase implements ITileDataSource {
|
||||
for (int wayDataBlock = 0; wayDataBlock < wayDataBlocks; wayDataBlock++) {
|
||||
e.clear();
|
||||
|
||||
if (!processWayDataBlock(e, featureWayDoubleDeltaEncoding, linearFeature))
|
||||
List<GeoPoint[]> wayNodes = null;
|
||||
if (ways != null)
|
||||
wayNodes = new ArrayList<>();
|
||||
|
||||
if (!processWayDataBlock(e, featureWayDoubleDeltaEncoding, linearFeature, wayNodes))
|
||||
return false;
|
||||
|
||||
/* drop invalid outer ring */
|
||||
@@ -889,13 +972,112 @@ public class MapDatabase implements ITileDataSource {
|
||||
|
||||
e.setLayer(layer);
|
||||
|
||||
mapDataSink.process(e);
|
||||
if (ways != null) {
|
||||
BoundingBox wayFilterBbox = boundingBox.extendMeters(wayFilterDistance);
|
||||
GeoPoint[][] wayNodesArray = wayNodes.toArray(new GeoPoint[wayNodes.size()][]);
|
||||
if (!filterRequired || !wayFilterEnabled || wayFilterBbox.intersectsArea(wayNodesArray)) {
|
||||
List<Tag> tags = new ArrayList<>();
|
||||
for (int i = 0; i < e.tags.numTags; i++)
|
||||
tags.add(e.tags.tags[i]);
|
||||
if (Selector.ALL == selector || hasName || hasHouseNr || hasRef || wayAsLabelTagFilter(tags)) {
|
||||
GeoPoint labelPos = e.labelPosition != null ? new GeoPoint(e.labelPosition.y / 1E6, e.labelPosition.x / 1E6) : null;
|
||||
ways.add(new Way(layer, tags, wayNodesArray, labelPos, e.type));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (mapDataSink != null)
|
||||
mapDataSink.process(e);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads only labels for tile.
|
||||
*
|
||||
* @param tile tile for which data is requested.
|
||||
* @return label data for the tile.
|
||||
*/
|
||||
public MapReadResult readLabels(Tile tile) {
|
||||
return readMapData(tile, tile, Selector.LABELS);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads data for an area defined by the tile in the upper left and the tile in
|
||||
* the lower right corner.
|
||||
* Precondition: upperLeft.tileX <= lowerRight.tileX && upperLeft.tileY <= lowerRight.tileY
|
||||
*
|
||||
* @param upperLeft tile that defines the upper left corner of the requested area.
|
||||
* @param lowerRight tile that defines the lower right corner of the requested area.
|
||||
* @return map data for the tile.
|
||||
*/
|
||||
public MapReadResult readLabels(Tile upperLeft, Tile lowerRight) {
|
||||
return readMapData(upperLeft, lowerRight, Selector.LABELS);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads all map data for the area covered by the given tile at the tile zoom level.
|
||||
*
|
||||
* @param tile defines area and zoom level of read map data.
|
||||
* @return the read map data.
|
||||
*/
|
||||
public MapReadResult readMapData(Tile tile) {
|
||||
return readMapData(tile, tile, Selector.ALL);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads data for an area defined by the tile in the upper left and the tile in
|
||||
* the lower right corner.
|
||||
* Precondition: upperLeft.tileX <= lowerRight.tileX && upperLeft.tileY <= lowerRight.tileY
|
||||
*
|
||||
* @param upperLeft tile that defines the upper left corner of the requested area.
|
||||
* @param lowerRight tile that defines the lower right corner of the requested area.
|
||||
* @return map data for the tile.
|
||||
*/
|
||||
public MapReadResult readMapData(Tile upperLeft, Tile lowerRight) {
|
||||
return readMapData(upperLeft, lowerRight, Selector.ALL);
|
||||
}
|
||||
|
||||
private MapReadResult readMapData(Tile upperLeft, Tile lowerRight, Selector selector) {
|
||||
if (mTileSource.fileHeader == null)
|
||||
return null;
|
||||
|
||||
MapReadResult mapReadResult = new MapReadResult();
|
||||
|
||||
if (mIntBuffer == null)
|
||||
mIntBuffer = new int[Short.MAX_VALUE * 2];
|
||||
|
||||
try {
|
||||
mTileProjection.setTile(upperLeft);
|
||||
|
||||
QueryParameters queryParameters = new QueryParameters();
|
||||
queryParameters.queryZoomLevel =
|
||||
mTileSource.fileHeader.getQueryZoomLevel(upperLeft.zoomLevel);
|
||||
|
||||
/* get and check the sub-file for the query zoom level */
|
||||
SubFileParameter subFileParameter =
|
||||
mTileSource.fileHeader.getSubFileParameter(queryParameters.queryZoomLevel);
|
||||
|
||||
if (subFileParameter == null) {
|
||||
log.warn("no sub-file for zoom level: "
|
||||
+ queryParameters.queryZoomLevel);
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
QueryCalculations.calculateBaseTiles(queryParameters, upperLeft, lowerRight, subFileParameter);
|
||||
QueryCalculations.calculateBlocks(queryParameters, subFileParameter);
|
||||
processBlocks(queryParameters, subFileParameter, Tile.getBoundingBox(upperLeft, lowerRight), selector, mapReadResult);
|
||||
} catch (IOException e) {
|
||||
log.error(e.getMessage());
|
||||
return null;
|
||||
}
|
||||
|
||||
return mapReadResult;
|
||||
}
|
||||
|
||||
private int[] readOptionalLabelPosition() {
|
||||
int[] labelPosition = new int[2];
|
||||
|
||||
@@ -908,6 +1090,29 @@ public class MapDatabase implements ITileDataSource {
|
||||
return labelPosition;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads only POI data for tile.
|
||||
*
|
||||
* @param tile tile for which data is requested.
|
||||
* @return POI data for the tile.
|
||||
*/
|
||||
public MapReadResult readPoiData(Tile tile) {
|
||||
return readMapData(tile, tile, Selector.POIS);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads POI data for an area defined by the tile in the upper left and the tile in
|
||||
* the lower right corner.
|
||||
* This implementation takes the data storage of a MapFile into account for greater efficiency.
|
||||
*
|
||||
* @param upperLeft tile that defines the upper left corner of the requested area.
|
||||
* @param lowerRight tile that defines the lower right corner of the requested area.
|
||||
* @return map data for the tile.
|
||||
*/
|
||||
public MapReadResult readPoiData(Tile upperLeft, Tile lowerRight) {
|
||||
return readMapData(upperLeft, lowerRight, Selector.POIS);
|
||||
}
|
||||
|
||||
private int[][] readZoomTable(SubFileParameter subFileParameter) {
|
||||
int rows = subFileParameter.zoomLevelMax - subFileParameter.zoomLevelMin + 1;
|
||||
int[][] zoomTable = new int[rows][2];
|
||||
@@ -926,6 +1131,51 @@ public class MapDatabase implements ITileDataSource {
|
||||
return zoomTable;
|
||||
}
|
||||
|
||||
/**
|
||||
* Restricts returns of data to zoom level range specified. This can be used to restrict
|
||||
* the use of this map data base when used in MultiMapDatabase settings.
|
||||
*
|
||||
* @param minZoom minimum zoom level supported
|
||||
* @param maxZoom maximum zoom level supported
|
||||
*/
|
||||
public void restrictToZoomRange(int minZoom, int maxZoom) {
|
||||
this.zoomLevelMax = maxZoom;
|
||||
this.zoomLevelMin = minZoom;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if MapDatabase contains tile.
|
||||
*
|
||||
* @param tile tile to be rendered.
|
||||
* @return true if tile is part of database.
|
||||
*/
|
||||
public boolean supportsTile(Tile tile) {
|
||||
return tile.getBoundingBox().intersects(mTileSource.getMapInfo().boundingBox)
|
||||
&& (tile.zoomLevel >= this.zoomLevelMin && tile.zoomLevel <= this.zoomLevelMax);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if a way should be included in the result set for readLabels()
|
||||
* By default only ways with names, house numbers or a ref are included in the result set
|
||||
* of readLabels(). This is to reduce the set of ways as much as possible to save memory.
|
||||
*
|
||||
* @param tags the tags associated with the way
|
||||
* @return true if the way should be included in the result set
|
||||
*/
|
||||
public boolean wayAsLabelTagFilter(List<Tag> tags) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* The Selector enum is used to specify which data subset is to be retrieved from a MapFile:
|
||||
* ALL: all data (as in version 0.6.0)
|
||||
* POIS: only poi data, no ways (new after 0.6.0)
|
||||
* LABELS: poi data and ways that have a name (new after 0.6.0)
|
||||
*/
|
||||
private enum Selector {
|
||||
ALL, POIS, LABELS
|
||||
}
|
||||
|
||||
static class TileProjection {
|
||||
private static final double COORD_SCALE = 1000000.0;
|
||||
|
||||
@@ -947,7 +1197,7 @@ public class MapDatabase implements ITileDataSource {
|
||||
/* scales longitude(1e6) to map-pixel */
|
||||
divx = (180.0 * COORD_SCALE) / (mapExtents >> 1);
|
||||
|
||||
/* scale latidute to map-pixel */
|
||||
/* scale latitude to map-pixel */
|
||||
divy = (Math.PI * 2.0) / (mapExtents >> 1);
|
||||
}
|
||||
|
||||
|
||||
77
vtm/src/org/oscim/tiling/source/mapfile/MapReadResult.java
Normal file
77
vtm/src/org/oscim/tiling/source/mapfile/MapReadResult.java
Normal file
@@ -0,0 +1,77 @@
|
||||
/*
|
||||
* Copyright 2010, 2011, 2012, 2013 mapsforge.org
|
||||
* Copyright 2014-2015 Ludwig M Brinckmann
|
||||
* Copyright 2017 devemux86
|
||||
*
|
||||
* 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
|
||||
* Foundation, either version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
|
||||
* PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License along with
|
||||
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.oscim.tiling.source.mapfile;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* An immutable container for the data returned from a MapDataStore.
|
||||
*/
|
||||
public class MapReadResult {
|
||||
|
||||
/**
|
||||
* True if the read area is completely covered by water, false otherwise.
|
||||
*/
|
||||
public boolean isWater;
|
||||
|
||||
/**
|
||||
* The read POIs.
|
||||
*/
|
||||
public List<PointOfInterest> pointOfInterests;
|
||||
|
||||
/**
|
||||
* The read ways.
|
||||
*/
|
||||
public List<Way> ways;
|
||||
|
||||
public MapReadResult() {
|
||||
this.pointOfInterests = new ArrayList<>();
|
||||
this.ways = new ArrayList<>();
|
||||
}
|
||||
|
||||
public void add(PoiWayBundle poiWayBundle) {
|
||||
this.pointOfInterests.addAll(poiWayBundle.pois);
|
||||
this.ways.addAll(poiWayBundle.ways);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds other MapReadResult by combining pois and ways. Optionally, deduplication can
|
||||
* be requested (much more expensive).
|
||||
*
|
||||
* @param other the MapReadResult to add to this.
|
||||
* @param deduplicate true if check for duplicates is required.
|
||||
*/
|
||||
public void add(MapReadResult other, boolean deduplicate) {
|
||||
if (deduplicate) {
|
||||
for (PointOfInterest poi : other.pointOfInterests) {
|
||||
if (!this.pointOfInterests.contains(poi)) {
|
||||
this.pointOfInterests.add(poi);
|
||||
}
|
||||
}
|
||||
for (Way way : other.ways) {
|
||||
if (!this.ways.contains(way)) {
|
||||
this.ways.add(way);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
this.pointOfInterests.addAll(other.pointOfInterests);
|
||||
this.ways.addAll(other.ways);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2016 devemux86
|
||||
* Copyright 2016-2017 devemux86
|
||||
*
|
||||
* 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
|
||||
@@ -14,6 +14,7 @@
|
||||
*/
|
||||
package org.oscim.tiling.source.mapfile;
|
||||
|
||||
import org.oscim.core.Tile;
|
||||
import org.oscim.layers.tile.MapTile;
|
||||
import org.oscim.tiling.ITileDataSink;
|
||||
import org.oscim.tiling.ITileDataSource;
|
||||
@@ -41,8 +42,7 @@ public class MultiMapDatabase implements ITileDataSource {
|
||||
public void query(MapTile tile, ITileDataSink mapDataSink) {
|
||||
MultiMapDataSink multiMapDataSink = new MultiMapDataSink(mapDataSink);
|
||||
for (MapDatabase mapDatabase : mapDatabases) {
|
||||
int[] zoomLevels = tileSource.getZoomsByTileSource().get(mapDatabase.getTileSource());
|
||||
if (zoomLevels == null || (zoomLevels[0] <= tile.zoomLevel && tile.zoomLevel <= zoomLevels[1]))
|
||||
if (mapDatabase.supportsTile(tile))
|
||||
mapDatabase.query(tile, multiMapDataSink);
|
||||
}
|
||||
mapDataSink.completed(multiMapDataSink.getResult());
|
||||
@@ -61,4 +61,109 @@ public class MultiMapDatabase implements ITileDataSource {
|
||||
mapDatabase.cancel();
|
||||
}
|
||||
}
|
||||
|
||||
public MapReadResult readLabels(Tile tile) {
|
||||
MapReadResult mapReadResult = new MapReadResult();
|
||||
for (MapDatabase mdb : mapDatabases) {
|
||||
if (mdb.supportsTile(tile)) {
|
||||
MapReadResult result = mdb.readLabels(tile);
|
||||
if (result == null) {
|
||||
continue;
|
||||
}
|
||||
boolean isWater = mapReadResult.isWater & result.isWater;
|
||||
mapReadResult.isWater = isWater;
|
||||
mapReadResult.add(result, false);
|
||||
}
|
||||
}
|
||||
return mapReadResult;
|
||||
}
|
||||
|
||||
public MapReadResult readLabels(Tile upperLeft, Tile lowerRight) {
|
||||
MapReadResult mapReadResult = new MapReadResult();
|
||||
for (MapDatabase mdb : mapDatabases) {
|
||||
if (mdb.supportsTile(upperLeft)) {
|
||||
MapReadResult result = mdb.readLabels(upperLeft, lowerRight);
|
||||
if (result == null) {
|
||||
continue;
|
||||
}
|
||||
boolean isWater = mapReadResult.isWater & result.isWater;
|
||||
mapReadResult.isWater = isWater;
|
||||
mapReadResult.add(result, false);
|
||||
}
|
||||
}
|
||||
return mapReadResult;
|
||||
}
|
||||
|
||||
public MapReadResult readMapData(Tile tile) {
|
||||
MapReadResult mapReadResult = new MapReadResult();
|
||||
for (MapDatabase mdb : mapDatabases) {
|
||||
if (mdb.supportsTile(tile)) {
|
||||
MapReadResult result = mdb.readMapData(tile);
|
||||
if (result == null) {
|
||||
continue;
|
||||
}
|
||||
boolean isWater = mapReadResult.isWater & result.isWater;
|
||||
mapReadResult.isWater = isWater;
|
||||
mapReadResult.add(result, false);
|
||||
}
|
||||
}
|
||||
return mapReadResult;
|
||||
}
|
||||
|
||||
public MapReadResult readMapData(Tile upperLeft, Tile lowerRight) {
|
||||
MapReadResult mapReadResult = new MapReadResult();
|
||||
for (MapDatabase mdb : mapDatabases) {
|
||||
if (mdb.supportsTile(upperLeft)) {
|
||||
MapReadResult result = mdb.readMapData(upperLeft, lowerRight);
|
||||
if (result == null) {
|
||||
continue;
|
||||
}
|
||||
boolean isWater = mapReadResult.isWater & result.isWater;
|
||||
mapReadResult.isWater = isWater;
|
||||
mapReadResult.add(result, false);
|
||||
}
|
||||
}
|
||||
return mapReadResult;
|
||||
}
|
||||
|
||||
public MapReadResult readPoiData(Tile tile) {
|
||||
MapReadResult mapReadResult = new MapReadResult();
|
||||
for (MapDatabase mdb : mapDatabases) {
|
||||
if (mdb.supportsTile(tile)) {
|
||||
MapReadResult result = mdb.readPoiData(tile);
|
||||
if (result == null) {
|
||||
continue;
|
||||
}
|
||||
boolean isWater = mapReadResult.isWater & result.isWater;
|
||||
mapReadResult.isWater = isWater;
|
||||
mapReadResult.add(result, false);
|
||||
}
|
||||
}
|
||||
return mapReadResult;
|
||||
}
|
||||
|
||||
public MapReadResult readPoiData(Tile upperLeft, Tile lowerRight) {
|
||||
MapReadResult mapReadResult = new MapReadResult();
|
||||
for (MapDatabase mdb : mapDatabases) {
|
||||
if (mdb.supportsTile(upperLeft)) {
|
||||
MapReadResult result = mdb.readPoiData(upperLeft, lowerRight);
|
||||
if (result == null) {
|
||||
continue;
|
||||
}
|
||||
boolean isWater = mapReadResult.isWater & result.isWater;
|
||||
mapReadResult.isWater = isWater;
|
||||
mapReadResult.add(result, false);
|
||||
}
|
||||
}
|
||||
return mapReadResult;
|
||||
}
|
||||
|
||||
public boolean supportsTile(Tile tile) {
|
||||
for (MapDatabase mdb : mapDatabases) {
|
||||
if (mdb.supportsTile(tile)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2016 devemux86
|
||||
* Copyright 2016-2017 devemux86
|
||||
*
|
||||
* 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
|
||||
@@ -63,16 +63,16 @@ public class MultiMapFileTileSource extends TileSource implements IMapFileTileSo
|
||||
return boundingBox;
|
||||
}
|
||||
|
||||
Map<MapFileTileSource, int[]> getZoomsByTileSource() {
|
||||
return zoomsByTileSource;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ITileDataSource getDataSource() {
|
||||
MultiMapDatabase multiMapDatabase = new MultiMapDatabase(this);
|
||||
for (MapFileTileSource mapFileTileSource : mapFileTileSources) {
|
||||
try {
|
||||
multiMapDatabase.add(new MapDatabase(mapFileTileSource));
|
||||
MapDatabase mapDatabase = new MapDatabase(mapFileTileSource);
|
||||
int[] zoomLevels = zoomsByTileSource.get(mapFileTileSource);
|
||||
if (zoomLevels != null)
|
||||
mapDatabase.restrictToZoomRange(zoomLevels[0], zoomLevels[1]);
|
||||
multiMapDatabase.add(mapDatabase);
|
||||
} catch (IOException e) {
|
||||
log.debug(e.getMessage());
|
||||
}
|
||||
|
||||
28
vtm/src/org/oscim/tiling/source/mapfile/PoiWayBundle.java
Normal file
28
vtm/src/org/oscim/tiling/source/mapfile/PoiWayBundle.java
Normal file
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
* Copyright 2010, 2011, 2012, 2013 mapsforge.org
|
||||
* Copyright 2017 devemux86
|
||||
*
|
||||
* 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
|
||||
* Foundation, either version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
|
||||
* PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License along with
|
||||
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.oscim.tiling.source.mapfile;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class PoiWayBundle {
|
||||
final List<PointOfInterest> pois;
|
||||
final List<Way> ways;
|
||||
|
||||
public PoiWayBundle(List<PointOfInterest> pois, List<Way> ways) {
|
||||
this.pois = pois;
|
||||
this.ways = ways;
|
||||
}
|
||||
}
|
||||
77
vtm/src/org/oscim/tiling/source/mapfile/PointOfInterest.java
Normal file
77
vtm/src/org/oscim/tiling/source/mapfile/PointOfInterest.java
Normal file
@@ -0,0 +1,77 @@
|
||||
/*
|
||||
* Copyright 2010, 2011, 2012, 2013 mapsforge.org
|
||||
* Copyright 2014-2015 Ludwig M Brinckmann
|
||||
* Copyright 2017 devemux86
|
||||
*
|
||||
* 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
|
||||
* Foundation, either version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
|
||||
* PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License along with
|
||||
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.oscim.tiling.source.mapfile;
|
||||
|
||||
import org.oscim.core.GeoPoint;
|
||||
import org.oscim.core.Tag;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* An immutable container for all data associated with a single point of interest node (POI).
|
||||
*/
|
||||
public class PointOfInterest {
|
||||
/**
|
||||
* The layer of this POI + 5 (to avoid negative values).
|
||||
*/
|
||||
public final byte layer;
|
||||
|
||||
/**
|
||||
* The position of this POI.
|
||||
*/
|
||||
public final GeoPoint position;
|
||||
|
||||
/**
|
||||
* The tags of this POI.
|
||||
*/
|
||||
public final List<Tag> tags;
|
||||
|
||||
public PointOfInterest(byte layer, List<Tag> tags, GeoPoint position) {
|
||||
this.layer = layer;
|
||||
this.tags = tags;
|
||||
this.position = position;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj) {
|
||||
return true;
|
||||
} else if (!(obj instanceof PointOfInterest)) {
|
||||
return false;
|
||||
}
|
||||
PointOfInterest other = (PointOfInterest) obj;
|
||||
if (this.layer != other.layer) {
|
||||
return false;
|
||||
} else if (!this.tags.equals(other.tags)) {
|
||||
return false;
|
||||
} else if (!this.position.equals(other.position)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
int result = 1;
|
||||
result = prime * result + layer;
|
||||
result = prime * result + tags.hashCode();
|
||||
result = prime * result + position.hashCode();
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,5 +1,7 @@
|
||||
/*
|
||||
* Copyright 2010, 2011, 2012 mapsforge.org
|
||||
* Copyright 2014-2015 Ludwig M Brinckmann
|
||||
* Copyright 2017 devemux86
|
||||
*
|
||||
* This file is part of the OpenScienceMap project (http://www.opensciencemap.org).
|
||||
*
|
||||
@@ -100,18 +102,14 @@ final class QueryCalculations {
|
||||
}
|
||||
}
|
||||
|
||||
static void calculateBaseTiles(QueryParameters queryParameters, Tile tile,
|
||||
SubFileParameter subFileParameter) {
|
||||
static void calculateBaseTiles(QueryParameters queryParameters, Tile tile, SubFileParameter subFileParameter) {
|
||||
if (tile.zoomLevel < subFileParameter.baseZoomLevel) {
|
||||
// calculate the XY numbers of the upper left and lower right
|
||||
// sub-tiles
|
||||
// calculate the XY numbers of the upper left and lower right sub-tiles
|
||||
int zoomLevelDifference = subFileParameter.baseZoomLevel - tile.zoomLevel;
|
||||
queryParameters.fromBaseTileX = tile.tileX << zoomLevelDifference;
|
||||
queryParameters.fromBaseTileY = tile.tileY << zoomLevelDifference;
|
||||
queryParameters.toBaseTileX = queryParameters.fromBaseTileX
|
||||
+ (1 << zoomLevelDifference) - 1;
|
||||
queryParameters.toBaseTileY = queryParameters.fromBaseTileY
|
||||
+ (1 << zoomLevelDifference) - 1;
|
||||
queryParameters.toBaseTileX = queryParameters.fromBaseTileX + (1 << zoomLevelDifference) - 1;
|
||||
queryParameters.toBaseTileY = queryParameters.fromBaseTileY + (1 << zoomLevelDifference) - 1;
|
||||
queryParameters.useTileBitmask = false;
|
||||
} else if (tile.zoomLevel > subFileParameter.baseZoomLevel) {
|
||||
// calculate the XY numbers of the parent base tile
|
||||
@@ -132,6 +130,37 @@ final class QueryCalculations {
|
||||
}
|
||||
}
|
||||
|
||||
static void calculateBaseTiles(QueryParameters queryParameters, Tile upperLeft, Tile lowerRight, SubFileParameter subFileParameter) {
|
||||
if (upperLeft.zoomLevel < subFileParameter.baseZoomLevel) {
|
||||
// here we need to combine multiple base tiles
|
||||
int zoomLevelDifference = subFileParameter.baseZoomLevel - upperLeft.zoomLevel;
|
||||
queryParameters.fromBaseTileX = upperLeft.tileX << zoomLevelDifference;
|
||||
queryParameters.fromBaseTileY = upperLeft.tileY << zoomLevelDifference;
|
||||
queryParameters.toBaseTileX = (lowerRight.tileX << zoomLevelDifference) + (1 << zoomLevelDifference) - 1;
|
||||
queryParameters.toBaseTileY = (lowerRight.tileY << zoomLevelDifference) + (1 << zoomLevelDifference) - 1;
|
||||
queryParameters.useTileBitmask = false;
|
||||
} else if (upperLeft.zoomLevel > subFileParameter.baseZoomLevel) {
|
||||
// we might have more than just one base tile as we might span boundaries
|
||||
int zoomLevelDifference = upperLeft.zoomLevel - subFileParameter.baseZoomLevel;
|
||||
queryParameters.fromBaseTileX = upperLeft.tileX >>> zoomLevelDifference;
|
||||
queryParameters.fromBaseTileY = upperLeft.tileY >>> zoomLevelDifference;
|
||||
queryParameters.toBaseTileX = lowerRight.tileX >>> zoomLevelDifference;
|
||||
queryParameters.toBaseTileY = lowerRight.tileY >>> zoomLevelDifference;
|
||||
// TODO understand what is going on here. The tileBitmask is used to extract just
|
||||
// the data from the base tiles that is relevant for the area, but how can this work
|
||||
// for a set of tiles, so not using tileBitmask for the moment.
|
||||
queryParameters.useTileBitmask = true;
|
||||
queryParameters.queryTileBitmask = QueryCalculations.calculateTileBitmask(upperLeft, lowerRight, zoomLevelDifference);
|
||||
} else {
|
||||
// we are on the base zoom level, so we just need all tiles in range
|
||||
queryParameters.fromBaseTileX = upperLeft.tileX;
|
||||
queryParameters.fromBaseTileY = upperLeft.tileY;
|
||||
queryParameters.toBaseTileX = lowerRight.tileX;
|
||||
queryParameters.toBaseTileY = lowerRight.tileY;
|
||||
queryParameters.useTileBitmask = false;
|
||||
}
|
||||
}
|
||||
|
||||
static void calculateBlocks(QueryParameters queryParameters, SubFileParameter subFileParameter) {
|
||||
// calculate the blocks in the file which need to be read
|
||||
queryParameters.fromBlockX = Math.max(queryParameters.fromBaseTileX
|
||||
@@ -171,6 +200,17 @@ final class QueryCalculations {
|
||||
}
|
||||
}
|
||||
|
||||
static int calculateTileBitmask(Tile upperLeft, Tile lowerRight, int zoomLevelDifference) {
|
||||
int bitmask = 0;
|
||||
for (int x = upperLeft.tileX; x <= lowerRight.tileX; x++) {
|
||||
for (int y = upperLeft.tileY; y <= lowerRight.tileY; y++) {
|
||||
Tile current = new Tile(x, y, upperLeft.zoomLevel);
|
||||
bitmask |= calculateTileBitmask(current, zoomLevelDifference);
|
||||
}
|
||||
}
|
||||
return bitmask;
|
||||
}
|
||||
|
||||
private QueryCalculations() {
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
|
||||
114
vtm/src/org/oscim/tiling/source/mapfile/Way.java
Normal file
114
vtm/src/org/oscim/tiling/source/mapfile/Way.java
Normal file
@@ -0,0 +1,114 @@
|
||||
/*
|
||||
* Copyright 2010, 2011, 2012, 2013 mapsforge.org
|
||||
* Copyright 2014-2015 Ludwig M Brinckmann
|
||||
* Copyright 2017 devemux86
|
||||
*
|
||||
* 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
|
||||
* Foundation, either version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
|
||||
* PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License along with
|
||||
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.oscim.tiling.source.mapfile;
|
||||
|
||||
import org.oscim.core.GeoPoint;
|
||||
import org.oscim.core.GeometryBuffer;
|
||||
import org.oscim.core.Tag;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* An immutable container for all data associated with a single way or area (closed way).
|
||||
*/
|
||||
public class Way {
|
||||
/**
|
||||
* The position of the area label (may be null).
|
||||
*/
|
||||
public final GeoPoint labelPosition;
|
||||
|
||||
/**
|
||||
* The geometry type.
|
||||
*/
|
||||
public GeometryBuffer.GeometryType geometryType = GeometryBuffer.GeometryType.NONE;
|
||||
|
||||
/**
|
||||
* The geographical coordinates of the way nodes.
|
||||
*/
|
||||
public final GeoPoint[][] geoPoints;
|
||||
|
||||
/**
|
||||
* The layer of this way + 5 (to avoid negative values).
|
||||
*/
|
||||
public final byte layer;
|
||||
|
||||
/**
|
||||
* The tags of this way.
|
||||
*/
|
||||
public final List<Tag> tags;
|
||||
|
||||
public Way(byte layer, List<Tag> tags, GeoPoint[][] geoPoints, GeoPoint labelPosition) {
|
||||
this.layer = layer;
|
||||
this.tags = tags;
|
||||
this.geoPoints = geoPoints;
|
||||
this.labelPosition = labelPosition;
|
||||
}
|
||||
|
||||
public Way(byte layer, List<Tag> tags, GeoPoint[][] geoPoints, GeoPoint labelPosition, final GeometryBuffer.GeometryType geometryType) {
|
||||
this(layer, tags, geoPoints, labelPosition);
|
||||
this.geometryType = geometryType;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj) {
|
||||
return true;
|
||||
} else if (!(obj instanceof Way)) {
|
||||
return false;
|
||||
}
|
||||
Way other = (Way) obj;
|
||||
if (this.layer != other.layer) {
|
||||
return false;
|
||||
} else if (!this.tags.equals(other.tags)) {
|
||||
return false;
|
||||
} else if (this.labelPosition == null && other.labelPosition != null) {
|
||||
return false;
|
||||
} else if (this.labelPosition != null && !this.labelPosition.equals(other.labelPosition)) {
|
||||
return false;
|
||||
} else if (this.geoPoints.length != other.geoPoints.length) {
|
||||
return false;
|
||||
} else {
|
||||
for (int i = 0; i < this.geoPoints.length; i++) {
|
||||
if (this.geoPoints[i].length != other.geoPoints[i].length) {
|
||||
return false;
|
||||
} else {
|
||||
for (int j = 0; j < this.geoPoints[i].length; j++) {
|
||||
if (!geoPoints[i][j].equals(other.geoPoints[i][j])) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
int result = 1;
|
||||
result = prime * result + layer;
|
||||
result = prime * result + tags.hashCode();
|
||||
result = prime * result + Arrays.deepHashCode(geoPoints);
|
||||
if (labelPosition != null) {
|
||||
result = prime * result + labelPosition.hashCode();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user