add mapsforge-map android part to VectorTileMap
This commit is contained in:
@@ -25,7 +25,7 @@
|
|||||||
</intent-filter>
|
</intent-filter>
|
||||||
</activity>
|
</activity>
|
||||||
<activity android:name="de.sfb.tilemap.preferences.EditPreferences" />
|
<activity android:name="de.sfb.tilemap.preferences.EditPreferences" />
|
||||||
<activity android:name="de.sfb.tilemap.filepicker.FilePicker" />
|
<activity android:name=".filepicker.FilePicker" />
|
||||||
</application>
|
</application>
|
||||||
|
|
||||||
</manifest>
|
</manifest>
|
||||||
@@ -4,7 +4,7 @@
|
|||||||
android:layout_width="fill_parent"
|
android:layout_width="fill_parent"
|
||||||
android:layout_height="fill_parent" >
|
android:layout_height="fill_parent" >
|
||||||
|
|
||||||
<org.mapsforge.android.maps.MapView
|
<org.mapsforge.android.MapView
|
||||||
android:id="@+id/mapView"
|
android:id="@+id/mapView"
|
||||||
android:layout_width="fill_parent"
|
android:layout_width="fill_parent"
|
||||||
android:layout_height="fill_parent" />
|
android:layout_height="fill_parent" />
|
||||||
|
|||||||
@@ -19,7 +19,6 @@ import android.os.Bundle;
|
|||||||
import android.preference.PreferenceManager;
|
import android.preference.PreferenceManager;
|
||||||
import android.view.WindowManager;
|
import android.view.WindowManager;
|
||||||
import android.webkit.WebView;
|
import android.webkit.WebView;
|
||||||
import de.sfb.tilemap.R;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Simple activity to display the info web page from the assets folder.
|
* Simple activity to display the info web page from the assets folder.
|
||||||
|
|||||||
@@ -19,7 +19,6 @@ import org.mapsforge.core.GeoPoint;
|
|||||||
import android.location.Location;
|
import android.location.Location;
|
||||||
import android.location.LocationListener;
|
import android.location.LocationListener;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import de.sfb.tilemap.R;
|
|
||||||
|
|
||||||
class MyLocationListener implements LocationListener {
|
class MyLocationListener implements LocationListener {
|
||||||
private final TileMap advancedMapViewer;
|
private final TileMap advancedMapViewer;
|
||||||
|
|||||||
@@ -16,7 +16,6 @@ package de.sfb.tilemap;
|
|||||||
|
|
||||||
import android.widget.SeekBar;
|
import android.widget.SeekBar;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
import de.sfb.tilemap.R;
|
|
||||||
|
|
||||||
class SeekBarChangeListener implements SeekBar.OnSeekBarChangeListener {
|
class SeekBarChangeListener implements SeekBar.OnSeekBarChangeListener {
|
||||||
private final TextView textView;
|
private final TextView textView;
|
||||||
|
|||||||
@@ -5,20 +5,20 @@ import java.io.FileNotFoundException;
|
|||||||
import java.text.DateFormat;
|
import java.text.DateFormat;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
|
|
||||||
import org.mapsforge.android.maps.DebugSettings;
|
import org.mapsforge.android.DebugSettings;
|
||||||
import org.mapsforge.android.maps.MapActivity;
|
import org.mapsforge.android.MapActivity;
|
||||||
import org.mapsforge.android.maps.MapController;
|
import org.mapsforge.android.MapController;
|
||||||
import org.mapsforge.android.maps.MapScaleBar;
|
import org.mapsforge.android.MapScaleBar;
|
||||||
import org.mapsforge.android.maps.MapView;
|
import org.mapsforge.android.MapView;
|
||||||
import org.mapsforge.android.maps.mapgenerator.MapDatabaseFactory;
|
import org.mapsforge.android.mapgenerator.MapDatabaseFactory;
|
||||||
import org.mapsforge.android.maps.mapgenerator.MapDatabaseInternal;
|
import org.mapsforge.android.mapgenerator.MapDatabaseInternal;
|
||||||
import org.mapsforge.android.maps.mapgenerator.MapGenerator;
|
import org.mapsforge.android.mapgenerator.MapGenerator;
|
||||||
import org.mapsforge.android.maps.rendertheme.InternalRenderTheme;
|
import org.mapsforge.android.rendertheme.InternalRenderTheme;
|
||||||
import org.mapsforge.android.maps.utils.AndroidUtils;
|
import org.mapsforge.android.utils.AndroidUtils;
|
||||||
import org.mapsforge.core.BoundingBox;
|
import org.mapsforge.core.BoundingBox;
|
||||||
import org.mapsforge.core.GeoPoint;
|
import org.mapsforge.core.GeoPoint;
|
||||||
import org.mapsforge.map.IMapDatabase;
|
import org.mapsforge.mapdatabase.IMapDatabase;
|
||||||
import org.mapsforge.map.MapFileInfo;
|
import org.mapsforge.mapdatabase.MapFileInfo;
|
||||||
|
|
||||||
import android.app.AlertDialog;
|
import android.app.AlertDialog;
|
||||||
import android.app.Dialog;
|
import android.app.Dialog;
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ package de.sfb.tilemap.filefilter;
|
|||||||
|
|
||||||
import java.io.FileFilter;
|
import java.io.FileFilter;
|
||||||
|
|
||||||
import org.mapsforge.map.FileOpenResult;
|
import org.mapsforge.mapdatabase.FileOpenResult;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An extension of the {@link FileFilter} interface.
|
* An extension of the {@link FileFilter} interface.
|
||||||
|
|||||||
@@ -16,9 +16,9 @@ package de.sfb.tilemap.filefilter;
|
|||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
|
||||||
import org.mapsforge.map.FileOpenResult;
|
import org.mapsforge.mapdatabase.FileOpenResult;
|
||||||
import org.mapsforge.map.IMapDatabase;
|
import org.mapsforge.mapdatabase.IMapDatabase;
|
||||||
import org.mapsforge.map.reader.MapDatabase;
|
import org.mapsforge.mapdatabase.mapfile.MapDatabase;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Accepts all valid map files.
|
* Accepts all valid map files.
|
||||||
|
|||||||
@@ -22,8 +22,8 @@ import java.io.InputStream;
|
|||||||
import javax.xml.parsers.ParserConfigurationException;
|
import javax.xml.parsers.ParserConfigurationException;
|
||||||
import javax.xml.parsers.SAXParserFactory;
|
import javax.xml.parsers.SAXParserFactory;
|
||||||
|
|
||||||
import org.mapsforge.android.maps.rendertheme.RenderThemeHandler;
|
import org.mapsforge.android.rendertheme.RenderThemeHandler;
|
||||||
import org.mapsforge.map.FileOpenResult;
|
import org.mapsforge.mapdatabase.FileOpenResult;
|
||||||
import org.xml.sax.InputSource;
|
import org.xml.sax.InputSource;
|
||||||
import org.xml.sax.SAXException;
|
import org.xml.sax.SAXException;
|
||||||
import org.xml.sax.XMLReader;
|
import org.xml.sax.XMLReader;
|
||||||
|
|||||||
93
src/org/mapsforge/android/DebugSettings.java
Normal file
93
src/org/mapsforge/android/DebugSettings.java
Normal file
@@ -0,0 +1,93 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010, 2011, 2012 mapsforge.org
|
||||||
|
*
|
||||||
|
* 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.mapsforge.android;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A simple DTO to stores flags for debugging rendered map tiles.
|
||||||
|
*/
|
||||||
|
public class DebugSettings implements Serializable {
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* True if drawing of tile coordinates is enabled, false otherwise.
|
||||||
|
*/
|
||||||
|
public final boolean mDrawTileCoordinates;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* True if drawing of tile frames is enabled, false otherwise.
|
||||||
|
*/
|
||||||
|
public final boolean mDrawTileFrames;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* True if highlighting of water tiles is enabled, false otherwise.
|
||||||
|
*/
|
||||||
|
public final boolean mDisablePolygons;
|
||||||
|
|
||||||
|
private final int mHashCodeValue;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param drawTileCoordinates
|
||||||
|
* if drawing of tile coordinates is enabled.
|
||||||
|
* @param drawTileFrames
|
||||||
|
* if drawing of tile frames is enabled.
|
||||||
|
* @param disablePolygons
|
||||||
|
* if highlighting of water tiles is enabled.
|
||||||
|
*/
|
||||||
|
public DebugSettings(boolean drawTileCoordinates, boolean drawTileFrames, boolean disablePolygons) {
|
||||||
|
mDrawTileCoordinates = drawTileCoordinates;
|
||||||
|
mDrawTileFrames = drawTileFrames;
|
||||||
|
mDisablePolygons = disablePolygons;
|
||||||
|
mHashCodeValue = calculateHashCode();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object obj) {
|
||||||
|
if (this == obj) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (!(obj instanceof DebugSettings)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
DebugSettings other = (DebugSettings) obj;
|
||||||
|
if (mDrawTileCoordinates != other.mDrawTileCoordinates) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (mDrawTileFrames != other.mDrawTileFrames) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (mDisablePolygons != other.mDisablePolygons) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return mHashCodeValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the hash code of this object.
|
||||||
|
*/
|
||||||
|
private int calculateHashCode() {
|
||||||
|
int result = 1;
|
||||||
|
result = 31 * result + (mDrawTileCoordinates ? 1231 : 1237);
|
||||||
|
result = 31 * result + (mDrawTileFrames ? 1231 : 1237);
|
||||||
|
result = 31 * result + (mDisablePolygons ? 1231 : 1237);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
138
src/org/mapsforge/android/MapActivity.java
Normal file
138
src/org/mapsforge/android/MapActivity.java
Normal file
@@ -0,0 +1,138 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010, 2011, 2012 mapsforge.org
|
||||||
|
*
|
||||||
|
* 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.mapsforge.android;
|
||||||
|
|
||||||
|
import org.mapsforge.android.mapgenerator.MapGenerator;
|
||||||
|
import org.mapsforge.core.GeoPoint;
|
||||||
|
import org.mapsforge.core.MapPosition;
|
||||||
|
|
||||||
|
import android.app.Activity;
|
||||||
|
import android.content.SharedPreferences;
|
||||||
|
import android.content.SharedPreferences.Editor;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* MapActivity is the abstract base class which must be extended in order to use a {@link MapView}. There are no
|
||||||
|
* abstract methods in this implementation which subclasses need to override and no API key or registration is required.
|
||||||
|
* <p>
|
||||||
|
* A subclass may create a MapView either via one of the MapView constructors or by inflating an XML layout file. It is
|
||||||
|
* possible to use more than one MapView at the same time.
|
||||||
|
* <p>
|
||||||
|
* When the MapActivity is shut down, the current center position, zoom level and map file of the MapView are saved in a
|
||||||
|
* preferences file and restored in the next startup process.
|
||||||
|
*/
|
||||||
|
public abstract class MapActivity extends Activity {
|
||||||
|
private static final String KEY_LATITUDE = "latitude";
|
||||||
|
private static final String KEY_LONGITUDE = "longitude";
|
||||||
|
private static final String KEY_MAP_FILE = "mapFile";
|
||||||
|
private static final String KEY_ZOOM_LEVEL = "zoomLevel";
|
||||||
|
private static final String PREFERENCES_FILE = "MapActivity";
|
||||||
|
|
||||||
|
private static boolean containsMapViewPosition(SharedPreferences sharedPreferences) {
|
||||||
|
return sharedPreferences.contains(KEY_LATITUDE) && sharedPreferences.contains(KEY_LONGITUDE)
|
||||||
|
&& sharedPreferences.contains(KEY_ZOOM_LEVEL);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Counter to store the last ID given to a MapView.
|
||||||
|
*/
|
||||||
|
private int lastMapViewId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Internal list which contains references to all running MapView objects.
|
||||||
|
*/
|
||||||
|
private MapView mMapView;
|
||||||
|
|
||||||
|
private void destroyMapViews() {
|
||||||
|
mMapView.destroy();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void restoreMapView(MapView mapView) {
|
||||||
|
SharedPreferences sharedPreferences = getSharedPreferences(PREFERENCES_FILE, MODE_PRIVATE);
|
||||||
|
if (containsMapViewPosition(sharedPreferences)) {
|
||||||
|
MapGenerator mapGenerator = mapView.getMapGenerator();
|
||||||
|
if (!mapGenerator.requiresInternetConnection() && sharedPreferences.contains(KEY_MAP_FILE)) {
|
||||||
|
// get and set the map file
|
||||||
|
mapView.setMapFile(sharedPreferences.getString(KEY_MAP_FILE, null));
|
||||||
|
}
|
||||||
|
|
||||||
|
// get and set the map position and zoom level
|
||||||
|
int latitudeE6 = sharedPreferences.getInt(KEY_LATITUDE, 0);
|
||||||
|
int longitudeE6 = sharedPreferences.getInt(KEY_LONGITUDE, 0);
|
||||||
|
int zoomLevel = sharedPreferences.getInt(KEY_ZOOM_LEVEL, -1);
|
||||||
|
|
||||||
|
GeoPoint geoPoint = new GeoPoint(latitudeE6, longitudeE6);
|
||||||
|
MapPosition mapPosition = new MapPosition(geoPoint, (byte) zoomLevel, 1);
|
||||||
|
mapView.setCenterAndZoom(mapPosition);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onDestroy() {
|
||||||
|
super.onDestroy();
|
||||||
|
destroyMapViews();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onPause() {
|
||||||
|
super.onPause();
|
||||||
|
mMapView.onPause();
|
||||||
|
|
||||||
|
Editor editor = getSharedPreferences(PREFERENCES_FILE, MODE_PRIVATE).edit();
|
||||||
|
editor.clear();
|
||||||
|
|
||||||
|
// save the map position and zoom level
|
||||||
|
MapPosition mapPosition = mMapView.getMapPosition().getMapPosition();
|
||||||
|
if (mapPosition != null) {
|
||||||
|
GeoPoint geoPoint = mapPosition.geoPoint;
|
||||||
|
editor.putInt(KEY_LATITUDE, geoPoint.latitudeE6);
|
||||||
|
editor.putInt(KEY_LONGITUDE, geoPoint.longitudeE6);
|
||||||
|
editor.putInt(KEY_ZOOM_LEVEL, mapPosition.zoomLevel);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!mMapView.getMapGenerator().requiresInternetConnection() && mMapView.getMapFile() != null) {
|
||||||
|
// save the map file
|
||||||
|
editor.putString(KEY_MAP_FILE, mMapView.getMapFile());
|
||||||
|
}
|
||||||
|
|
||||||
|
editor.commit();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onResume() {
|
||||||
|
super.onResume();
|
||||||
|
mMapView.onResume();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return a unique MapView ID on each call.
|
||||||
|
*/
|
||||||
|
final int getMapViewId() {
|
||||||
|
return ++lastMapViewId;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method is called once by each MapView during its setup process.
|
||||||
|
*
|
||||||
|
* @param mapView
|
||||||
|
* the calling MapView.
|
||||||
|
*/
|
||||||
|
final void registerMapView(MapView mapView) {
|
||||||
|
if (mMapView != null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
mMapView = mapView;
|
||||||
|
restoreMapView(mapView);
|
||||||
|
}
|
||||||
|
}
|
||||||
89
src/org/mapsforge/android/MapController.java
Normal file
89
src/org/mapsforge/android/MapController.java
Normal file
@@ -0,0 +1,89 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010, 2011, 2012 mapsforge.org
|
||||||
|
*
|
||||||
|
* 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.mapsforge.android;
|
||||||
|
|
||||||
|
import org.mapsforge.core.GeoPoint;
|
||||||
|
|
||||||
|
import android.view.KeyEvent;
|
||||||
|
import android.view.View;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A MapController is used to programmatically modify the position and zoom level of a MapView. Each MapController is
|
||||||
|
* assigned to a single MapView instance. To retrieve a MapController for a given MapView, use the
|
||||||
|
* {@link MapView#getController()} method.
|
||||||
|
*/
|
||||||
|
public final class MapController implements View.OnKeyListener {
|
||||||
|
private final MapView mMapView;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param mapView
|
||||||
|
* the MapView which should be controlled by this MapController.
|
||||||
|
*/
|
||||||
|
MapController(MapView mapView) {
|
||||||
|
mMapView = mapView;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onKey(View view, int keyCode, KeyEvent keyEvent) {
|
||||||
|
if (keyEvent.getAction() == KeyEvent.ACTION_DOWN) {
|
||||||
|
// forward the event to the MapView
|
||||||
|
return mMapView.onKeyDown(keyCode, keyEvent);
|
||||||
|
} else if (keyEvent.getAction() == KeyEvent.ACTION_UP) {
|
||||||
|
// forward the event to the MapView
|
||||||
|
return mMapView.onKeyUp(keyCode, keyEvent);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the center of the MapView without an animation to the given point.
|
||||||
|
*
|
||||||
|
* @param geoPoint
|
||||||
|
* the new center point of the map.
|
||||||
|
*/
|
||||||
|
public void setCenter(GeoPoint geoPoint) {
|
||||||
|
mMapView.setCenter(geoPoint);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the zoom level of the MapView.
|
||||||
|
*
|
||||||
|
* @param zoomLevel
|
||||||
|
* the new zoom level, will be limited by the maximum and minimum possible zoom level.
|
||||||
|
* @return the new zoom level.
|
||||||
|
*/
|
||||||
|
public int setZoom(int zoomLevel) {
|
||||||
|
mMapView.zoom((byte) (zoomLevel - mMapView.getMapPosition().getZoomLevel()));
|
||||||
|
return mMapView.getMapPosition().getZoomLevel();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Increases the zoom level of the MapView, unless the maximum zoom level has been reached.
|
||||||
|
*
|
||||||
|
* @return true if the zoom level has been changed, false otherwise.
|
||||||
|
*/
|
||||||
|
public boolean zoomIn() {
|
||||||
|
return mMapView.zoom((byte) 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Decreases the zoom level of the MapView, unless the minimum zoom level has been reached.
|
||||||
|
*
|
||||||
|
* @return true if the zoom level has been changed, false otherwise.
|
||||||
|
*/
|
||||||
|
public boolean zoomOut() {
|
||||||
|
return mMapView.zoom((byte) -1);
|
||||||
|
}
|
||||||
|
}
|
||||||
47
src/org/mapsforge/android/MapRenderer.java
Normal file
47
src/org/mapsforge/android/MapRenderer.java
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2012 Hannes Janetzek
|
||||||
|
*
|
||||||
|
* 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.mapsforge.android;
|
||||||
|
|
||||||
|
import org.mapsforge.android.mapgenerator.MapGeneratorJob;
|
||||||
|
|
||||||
|
import android.opengl.GLSurfaceView;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public interface MapRenderer extends GLSurfaceView.Renderer {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param mapGeneratorJob
|
||||||
|
* the mapGeneratorJob holding Tile data
|
||||||
|
* @return true if the tile was processed
|
||||||
|
*/
|
||||||
|
public boolean passTile(MapGeneratorJob mapGeneratorJob);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return true when tile passed to renderer is processed false otherwise.
|
||||||
|
* used to lock overwriting resources passed with the tile
|
||||||
|
* (e.g. lock until bitmap is loaded to texture)
|
||||||
|
*/
|
||||||
|
public boolean processedTile();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* called by MapView on position and map changes
|
||||||
|
*
|
||||||
|
* @param clear
|
||||||
|
* ...
|
||||||
|
*/
|
||||||
|
public void redrawTiles(boolean clear);
|
||||||
|
}
|
||||||
273
src/org/mapsforge/android/MapScaleBar.java
Normal file
273
src/org/mapsforge/android/MapScaleBar.java
Normal file
@@ -0,0 +1,273 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010, 2011, 2012 mapsforge.org
|
||||||
|
*
|
||||||
|
* 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.mapsforge.android;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import org.mapsforge.core.MapPosition;
|
||||||
|
import org.mapsforge.core.MercatorProjection;
|
||||||
|
|
||||||
|
import android.graphics.Bitmap;
|
||||||
|
import android.graphics.Canvas;
|
||||||
|
import android.graphics.Color;
|
||||||
|
import android.graphics.Paint;
|
||||||
|
import android.graphics.Typeface;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A MapScaleBar displays the ratio of a distance on the map to the corresponding distance on the ground.
|
||||||
|
*/
|
||||||
|
public class MapScaleBar {
|
||||||
|
/**
|
||||||
|
* Enumeration of all text fields.
|
||||||
|
*/
|
||||||
|
public enum TextField {
|
||||||
|
/**
|
||||||
|
* Unit symbol for one foot.
|
||||||
|
*/
|
||||||
|
FOOT,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unit symbol for one kilometer.
|
||||||
|
*/
|
||||||
|
KILOMETER,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unit symbol for one meter.
|
||||||
|
*/
|
||||||
|
METER,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unit symbol for one mile.
|
||||||
|
*/
|
||||||
|
MILE;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final int BITMAP_HEIGHT = 50;
|
||||||
|
private static final int BITMAP_WIDTH = 150;
|
||||||
|
private static final double LATITUDE_REDRAW_THRESHOLD = 0.2;
|
||||||
|
private static final int MARGIN_BOTTOM = 5;
|
||||||
|
private static final int MARGIN_LEFT = 5;
|
||||||
|
private static final double METER_FOOT_RATIO = 0.3048;
|
||||||
|
private static final int ONE_KILOMETER = 1000;
|
||||||
|
private static final int ONE_MILE = 5280;
|
||||||
|
private static final Paint SCALE_BAR = new Paint(Paint.ANTI_ALIAS_FLAG);
|
||||||
|
private static final Paint SCALE_BAR_STROKE = new Paint(Paint.ANTI_ALIAS_FLAG);
|
||||||
|
private static final int[] SCALE_BAR_VALUES_IMPERIAL = { 26400000, 10560000, 5280000, 2640000, 1056000, 528000,
|
||||||
|
264000, 105600, 52800, 26400, 10560, 5280, 2000, 1000, 500, 200, 100, 50, 20, 10, 5, 2, 1 };
|
||||||
|
private static final int[] SCALE_BAR_VALUES_METRIC = { 10000000, 5000000, 2000000, 1000000, 500000, 200000, 100000,
|
||||||
|
50000, 20000, 10000, 5000, 2000, 1000, 500, 200, 100, 50, 20, 10, 5, 2, 1 };
|
||||||
|
private static final Paint SCALE_TEXT = new Paint(Paint.ANTI_ALIAS_FLAG);
|
||||||
|
private static final Paint SCALE_TEXT_STROKE = new Paint(Paint.ANTI_ALIAS_FLAG);
|
||||||
|
|
||||||
|
private static void configurePaints() {
|
||||||
|
SCALE_BAR.setStrokeWidth(2);
|
||||||
|
SCALE_BAR.setStrokeCap(Paint.Cap.SQUARE);
|
||||||
|
SCALE_BAR.setColor(Color.BLACK);
|
||||||
|
SCALE_BAR_STROKE.setStrokeWidth(5);
|
||||||
|
SCALE_BAR_STROKE.setStrokeCap(Paint.Cap.SQUARE);
|
||||||
|
SCALE_BAR_STROKE.setColor(Color.WHITE);
|
||||||
|
|
||||||
|
SCALE_TEXT.setTypeface(Typeface.defaultFromStyle(Typeface.BOLD));
|
||||||
|
SCALE_TEXT.setTextSize(17);
|
||||||
|
SCALE_TEXT.setColor(Color.BLACK);
|
||||||
|
SCALE_TEXT_STROKE.setTypeface(Typeface.defaultFromStyle(Typeface.BOLD));
|
||||||
|
SCALE_TEXT_STROKE.setStyle(Paint.Style.STROKE);
|
||||||
|
SCALE_TEXT_STROKE.setColor(Color.WHITE);
|
||||||
|
SCALE_TEXT_STROKE.setStrokeWidth(2);
|
||||||
|
SCALE_TEXT_STROKE.setTextSize(17);
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean mImperialUnits;
|
||||||
|
private MapPosition mMapPosition;
|
||||||
|
private final Bitmap mMapScaleBitmap;
|
||||||
|
private final Canvas mMapScaleCanvas;
|
||||||
|
private final MapView mMapView;
|
||||||
|
private boolean mRedrawNeeded;
|
||||||
|
private boolean mShowMapScaleBar;
|
||||||
|
private final Map<TextField, String> mTextFields;
|
||||||
|
|
||||||
|
MapScaleBar(MapView mapView) {
|
||||||
|
mMapView = mapView;
|
||||||
|
mMapScaleBitmap = Bitmap.createBitmap(BITMAP_WIDTH, BITMAP_HEIGHT, Bitmap.Config.ARGB_4444);
|
||||||
|
mMapScaleCanvas = new Canvas(mMapScaleBitmap);
|
||||||
|
mTextFields = new HashMap<TextField, String>();
|
||||||
|
setDefaultTexts();
|
||||||
|
configurePaints();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return true if imperial units are used, false otherwise.
|
||||||
|
*/
|
||||||
|
public boolean isImperialUnits() {
|
||||||
|
return mImperialUnits;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return true if this map scale bar is visible, false otherwise.
|
||||||
|
*/
|
||||||
|
public boolean isShowMapScaleBar() {
|
||||||
|
return mShowMapScaleBar;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param imperialUnits
|
||||||
|
* true if imperial units should be used rather than metric units.
|
||||||
|
*/
|
||||||
|
public void setImperialUnits(boolean imperialUnits) {
|
||||||
|
mImperialUnits = imperialUnits;
|
||||||
|
mRedrawNeeded = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param showMapScaleBar
|
||||||
|
* true if the map scale bar should be drawn, false otherwise.
|
||||||
|
*/
|
||||||
|
public void setShowMapScaleBar(boolean showMapScaleBar) {
|
||||||
|
mShowMapScaleBar = showMapScaleBar;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Overrides the specified text field with the given string.
|
||||||
|
*
|
||||||
|
* @param textField
|
||||||
|
* the text field to override.
|
||||||
|
* @param value
|
||||||
|
* the new value of the text field.
|
||||||
|
*/
|
||||||
|
public void setText(TextField textField, String value) {
|
||||||
|
mTextFields.put(textField, value);
|
||||||
|
mRedrawNeeded = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void drawScaleBar(float scaleBarLength, Paint paint) {
|
||||||
|
mMapScaleCanvas.drawLine(7, 25, scaleBarLength + 3, 25, paint);
|
||||||
|
mMapScaleCanvas.drawLine(5, 10, 5, 40, paint);
|
||||||
|
mMapScaleCanvas.drawLine(scaleBarLength + 5, 10, scaleBarLength + 5, 40, paint);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void drawScaleText(int scaleValue, String unitSymbol, Paint paint) {
|
||||||
|
mMapScaleCanvas.drawText(scaleValue + unitSymbol, 12, 18, paint);
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isRedrawNecessary() {
|
||||||
|
if (mRedrawNeeded || mMapPosition == null) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
MapPosition currentMapPosition = mMapView.getMapPosition().getMapPosition();
|
||||||
|
|
||||||
|
if (currentMapPosition.zoomLevel != mMapPosition.zoomLevel) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
double latitudeDiff = Math.abs(currentMapPosition.geoPoint.getLatitude()
|
||||||
|
- mMapPosition.geoPoint.getLatitude());
|
||||||
|
if (latitudeDiff > LATITUDE_REDRAW_THRESHOLD) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Redraws the map scale bitmap with the given parameters.
|
||||||
|
*
|
||||||
|
* @param scaleBarLength
|
||||||
|
* the length of the map scale bar in pixels.
|
||||||
|
* @param mapScaleValue
|
||||||
|
* the map scale value in meters.
|
||||||
|
*/
|
||||||
|
private void redrawMapScaleBitmap(float scaleBarLength, int mapScaleValue) {
|
||||||
|
mMapScaleBitmap.eraseColor(Color.TRANSPARENT);
|
||||||
|
|
||||||
|
// draw the scale bar
|
||||||
|
drawScaleBar(scaleBarLength, SCALE_BAR_STROKE);
|
||||||
|
drawScaleBar(scaleBarLength, SCALE_BAR);
|
||||||
|
|
||||||
|
int scaleValue;
|
||||||
|
String unitSymbol;
|
||||||
|
if (mImperialUnits) {
|
||||||
|
if (mapScaleValue < ONE_MILE) {
|
||||||
|
scaleValue = mapScaleValue;
|
||||||
|
unitSymbol = mTextFields.get(TextField.FOOT);
|
||||||
|
} else {
|
||||||
|
scaleValue = mapScaleValue / ONE_MILE;
|
||||||
|
unitSymbol = mTextFields.get(TextField.MILE);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (mapScaleValue < ONE_KILOMETER) {
|
||||||
|
scaleValue = mapScaleValue;
|
||||||
|
unitSymbol = mTextFields.get(TextField.METER);
|
||||||
|
} else {
|
||||||
|
scaleValue = mapScaleValue / ONE_KILOMETER;
|
||||||
|
unitSymbol = mTextFields.get(TextField.KILOMETER);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// draw the scale text
|
||||||
|
drawScaleText(scaleValue, unitSymbol, SCALE_TEXT_STROKE);
|
||||||
|
drawScaleText(scaleValue, unitSymbol, SCALE_TEXT);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setDefaultTexts() {
|
||||||
|
mTextFields.put(TextField.FOOT, " ft");
|
||||||
|
mTextFields.put(TextField.MILE, " mi");
|
||||||
|
|
||||||
|
mTextFields.put(TextField.METER, " m");
|
||||||
|
mTextFields.put(TextField.KILOMETER, " km");
|
||||||
|
}
|
||||||
|
|
||||||
|
void destroy() {
|
||||||
|
mMapScaleBitmap.recycle();
|
||||||
|
}
|
||||||
|
|
||||||
|
void draw(Canvas canvas) {
|
||||||
|
int top = mMapView.getHeight() - BITMAP_HEIGHT - MARGIN_BOTTOM;
|
||||||
|
canvas.drawBitmap(mMapScaleBitmap, MARGIN_LEFT, top, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
void redrawScaleBar() {
|
||||||
|
if (!isRedrawNecessary()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
mMapPosition = mMapView.getMapPosition().getMapPosition();
|
||||||
|
double groundResolution = MercatorProjection.calculateGroundResolution(mMapPosition.geoPoint.getLatitude(),
|
||||||
|
mMapPosition.zoomLevel);
|
||||||
|
|
||||||
|
int[] scaleBarValues;
|
||||||
|
if (mImperialUnits) {
|
||||||
|
groundResolution = groundResolution / METER_FOOT_RATIO;
|
||||||
|
scaleBarValues = SCALE_BAR_VALUES_IMPERIAL;
|
||||||
|
} else {
|
||||||
|
scaleBarValues = SCALE_BAR_VALUES_METRIC;
|
||||||
|
}
|
||||||
|
|
||||||
|
float scaleBarLength = 0;
|
||||||
|
int mapScaleValue = 0;
|
||||||
|
|
||||||
|
for (int i = 0; i < scaleBarValues.length; ++i) {
|
||||||
|
mapScaleValue = scaleBarValues[i];
|
||||||
|
scaleBarLength = mapScaleValue / (float) groundResolution;
|
||||||
|
if (scaleBarLength < (BITMAP_WIDTH - 10)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
redrawMapScaleBitmap(scaleBarLength, mapScaleValue);
|
||||||
|
mRedrawNeeded = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
709
src/org/mapsforge/android/MapView.java
Normal file
709
src/org/mapsforge/android/MapView.java
Normal file
@@ -0,0 +1,709 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010, 2011, 2012 mapsforge.org
|
||||||
|
*
|
||||||
|
* 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.mapsforge.android;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileNotFoundException;
|
||||||
|
|
||||||
|
import org.mapsforge.android.inputhandling.MapMover;
|
||||||
|
import org.mapsforge.android.inputhandling.TouchHandler;
|
||||||
|
import org.mapsforge.android.inputhandling.ZoomAnimator;
|
||||||
|
import org.mapsforge.android.mapgenerator.JobParameters;
|
||||||
|
import org.mapsforge.android.mapgenerator.JobQueue;
|
||||||
|
import org.mapsforge.android.mapgenerator.JobTheme;
|
||||||
|
import org.mapsforge.android.mapgenerator.MapDatabaseFactory;
|
||||||
|
import org.mapsforge.android.mapgenerator.MapDatabaseInternal;
|
||||||
|
import org.mapsforge.android.mapgenerator.MapGenerator;
|
||||||
|
import org.mapsforge.android.mapgenerator.MapGeneratorFactory;
|
||||||
|
import org.mapsforge.android.mapgenerator.MapWorker;
|
||||||
|
import org.mapsforge.android.rendertheme.ExternalRenderTheme;
|
||||||
|
import org.mapsforge.android.rendertheme.InternalRenderTheme;
|
||||||
|
import org.mapsforge.android.utils.GlConfigChooser;
|
||||||
|
import org.mapsforge.core.GeoPoint;
|
||||||
|
import org.mapsforge.core.MapPosition;
|
||||||
|
import org.mapsforge.mapdatabase.FileOpenResult;
|
||||||
|
import org.mapsforge.mapdatabase.IMapDatabase;
|
||||||
|
import org.mapsforge.mapdatabase.mapfile.MapDatabase;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.opengl.GLSurfaceView;
|
||||||
|
import android.util.AttributeSet;
|
||||||
|
import android.util.Log;
|
||||||
|
import android.view.KeyEvent;
|
||||||
|
import android.view.MotionEvent;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A MapView shows a map on the display of the device. It handles all user input and touch gestures to move and zoom the
|
||||||
|
* map. This MapView also includes a scale bar and zoom controls. The {@link #getController()} method returns a
|
||||||
|
* {@link MapController} to programmatically modify the position and zoom level of the map.
|
||||||
|
* <p>
|
||||||
|
* This implementation supports offline map rendering as well as downloading map images (tiles) over an Internet
|
||||||
|
* connection. The operation mode of a MapView can be set in the constructor and changed at runtime with the
|
||||||
|
* {@link #setMapGeneratorInternal(MapGenerator)} method. Some MapView parameters depend on the selected operation mode.
|
||||||
|
* <p>
|
||||||
|
* In offline rendering mode a special database file is required which contains the map data. Map files can be stored in
|
||||||
|
* any folder. The current map file is set by calling {@link #setMapFile(String)}. To retrieve the current
|
||||||
|
* {@link MapDatabase}, use the {@link #getMapDatabase()} method.
|
||||||
|
* <p>
|
||||||
|
*/
|
||||||
|
public class MapView extends GLSurfaceView {
|
||||||
|
|
||||||
|
final static String TAG = "MapView";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Default render theme of the MapView.
|
||||||
|
*/
|
||||||
|
public static final InternalRenderTheme DEFAULT_RENDER_THEME = InternalRenderTheme.OSMARENDER;
|
||||||
|
|
||||||
|
private static final float DEFAULT_TEXT_SCALE = 1;
|
||||||
|
|
||||||
|
private final MapController mMapController;
|
||||||
|
private final MapMover mMapMover;
|
||||||
|
private final MapScaleBar mMapScaleBar;
|
||||||
|
private final MapViewPosition mMapViewPosition;
|
||||||
|
|
||||||
|
private final MapZoomControls mMapZoomControls;
|
||||||
|
private final Projection mProjection;
|
||||||
|
private final TouchHandler mTouchEventHandler;
|
||||||
|
private final ZoomAnimator mZoomAnimator;
|
||||||
|
|
||||||
|
private IMapDatabase mMapDatabase;
|
||||||
|
private MapGenerator mMapGenerator;
|
||||||
|
private MapRenderer mMapRenderer;
|
||||||
|
private JobQueue mJobQueue;
|
||||||
|
private MapWorker mMapWorker;
|
||||||
|
private JobParameters mJobParameters;
|
||||||
|
private DebugSettings mDebugSettings;
|
||||||
|
private String mMapFile;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param context
|
||||||
|
* the enclosing MapActivity instance.
|
||||||
|
* @throws IllegalArgumentException
|
||||||
|
* if the context object is not an instance of {@link MapActivity} .
|
||||||
|
*/
|
||||||
|
public MapView(Context context) {
|
||||||
|
this(context, null, new org.mapsforge.android.glrenderer.DatabaseRenderer());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param context
|
||||||
|
* the enclosing MapActivity instance.
|
||||||
|
* @param attributeSet
|
||||||
|
* a set of attributes.
|
||||||
|
* @throws IllegalArgumentException
|
||||||
|
* if the context object is not an instance of {@link MapActivity} .
|
||||||
|
*/
|
||||||
|
public MapView(Context context, AttributeSet attributeSet) {
|
||||||
|
this(context, attributeSet, MapGeneratorFactory.createMapGenerator(attributeSet));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param context
|
||||||
|
* the enclosing MapActivity instance.
|
||||||
|
* @param mapGenerator
|
||||||
|
* the MapGenerator for this MapView.
|
||||||
|
* @throws IllegalArgumentException
|
||||||
|
* if the context object is not an instance of {@link MapActivity} .
|
||||||
|
*/
|
||||||
|
public MapView(Context context, MapGenerator mapGenerator) {
|
||||||
|
this(context, null, mapGenerator);
|
||||||
|
}
|
||||||
|
|
||||||
|
private MapView(Context context, AttributeSet attributeSet, MapGenerator mapGenerator) {
|
||||||
|
|
||||||
|
super(context, attributeSet);
|
||||||
|
|
||||||
|
if (!(context instanceof MapActivity)) {
|
||||||
|
throw new IllegalArgumentException("context is not an instance of MapActivity");
|
||||||
|
}
|
||||||
|
setWillNotDraw(true);
|
||||||
|
setWillNotCacheDrawing(true);
|
||||||
|
|
||||||
|
MapActivity mapActivity = (MapActivity) context;
|
||||||
|
|
||||||
|
mDebugSettings = new DebugSettings(false, false, false);
|
||||||
|
|
||||||
|
mJobParameters = new JobParameters(DEFAULT_RENDER_THEME, DEFAULT_TEXT_SCALE);
|
||||||
|
mMapController = new MapController(this);
|
||||||
|
|
||||||
|
// mMapDatabase = MapDatabaseFactory.createMapDatabase(MapDatabaseInternal.POSTGIS_READER);
|
||||||
|
mMapDatabase = MapDatabaseFactory.createMapDatabase(MapDatabaseInternal.MAP_READER);
|
||||||
|
|
||||||
|
mMapViewPosition = new MapViewPosition(this);
|
||||||
|
mMapScaleBar = new MapScaleBar(this);
|
||||||
|
mMapZoomControls = new MapZoomControls(mapActivity, this);
|
||||||
|
mProjection = new MapViewProjection(this);
|
||||||
|
mTouchEventHandler = new TouchHandler(mapActivity, this);
|
||||||
|
|
||||||
|
mJobQueue = new JobQueue(this);
|
||||||
|
mMapWorker = new MapWorker(this);
|
||||||
|
mMapWorker.start();
|
||||||
|
mMapMover = new MapMover(this);
|
||||||
|
mMapMover.start();
|
||||||
|
mZoomAnimator = new ZoomAnimator(this);
|
||||||
|
mZoomAnimator.start();
|
||||||
|
|
||||||
|
setMapGeneratorInternal(mapGenerator);
|
||||||
|
|
||||||
|
GeoPoint startPoint = mMapGenerator.getStartPoint();
|
||||||
|
if (startPoint != null) {
|
||||||
|
mMapViewPosition.setMapCenter(startPoint);
|
||||||
|
}
|
||||||
|
|
||||||
|
Byte startZoomLevel = mMapGenerator.getStartZoomLevel();
|
||||||
|
if (startZoomLevel != null) {
|
||||||
|
mMapViewPosition.setZoomLevel(startZoomLevel.byteValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
mapActivity.registerMapView(this);
|
||||||
|
|
||||||
|
setEGLConfigChooser(new GlConfigChooser());
|
||||||
|
setEGLContextClientVersion(2);
|
||||||
|
|
||||||
|
mMapRenderer = mMapGenerator.getMapRenderer(this);
|
||||||
|
setRenderer(mMapRenderer);
|
||||||
|
|
||||||
|
setRenderMode(GLSurfaceView.RENDERMODE_WHEN_DIRTY);
|
||||||
|
mMapWorker.setMapRenderer(mMapRenderer);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the MapController for this MapView.
|
||||||
|
*/
|
||||||
|
public MapController getController() {
|
||||||
|
return mMapController;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the debug settings which are used in this MapView.
|
||||||
|
*/
|
||||||
|
public DebugSettings getDebugSettings() {
|
||||||
|
return mDebugSettings;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the job queue which is used in this MapView.
|
||||||
|
*/
|
||||||
|
public JobQueue getJobQueue() {
|
||||||
|
return mJobQueue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the map database which is used for reading map files.
|
||||||
|
* @throws UnsupportedOperationException
|
||||||
|
* if the current MapGenerator works with an Internet connection.
|
||||||
|
*/
|
||||||
|
public IMapDatabase getMapDatabase() {
|
||||||
|
if (mMapGenerator.requiresInternetConnection()) {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
return mMapDatabase;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the currently used map file.
|
||||||
|
* @throws UnsupportedOperationException
|
||||||
|
* if the current MapGenerator mode works with an Internet connection.
|
||||||
|
*/
|
||||||
|
public String getMapFile() {
|
||||||
|
if (mMapGenerator.requiresInternetConnection()) {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
return mMapFile;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the currently used MapGenerator (may be null).
|
||||||
|
*/
|
||||||
|
public MapGenerator getMapGenerator() {
|
||||||
|
return mMapGenerator;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the MapMover which is used by this MapView.
|
||||||
|
*/
|
||||||
|
public MapMover getMapMover() {
|
||||||
|
return mMapMover;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the current position and zoom level of this MapView.
|
||||||
|
*/
|
||||||
|
public MapViewPosition getMapPosition() {
|
||||||
|
return mMapViewPosition;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the scale bar which is used in this MapView.
|
||||||
|
*/
|
||||||
|
public MapScaleBar getMapScaleBar() {
|
||||||
|
return mMapScaleBar;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the zoom controls instance which is used in this MapView.
|
||||||
|
*/
|
||||||
|
public MapZoomControls getMapZoomControls() {
|
||||||
|
return mMapZoomControls;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the currently used projection of the map. Do not keep this object for a longer time.
|
||||||
|
*/
|
||||||
|
public Projection getProjection() {
|
||||||
|
return mProjection;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return true if the ZoomAnimator is currently running, false otherwise.
|
||||||
|
*/
|
||||||
|
public boolean isZoomAnimatorRunning() {
|
||||||
|
return mZoomAnimator.isExecuting();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onKeyDown(int keyCode, KeyEvent keyEvent) {
|
||||||
|
return mMapMover.onKeyDown(keyCode, keyEvent);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onKeyUp(int keyCode, KeyEvent keyEvent) {
|
||||||
|
return mMapMover.onKeyUp(keyCode, keyEvent);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onTouchEvent(MotionEvent motionEvent) {
|
||||||
|
return mTouchEventHandler.handleMotionEvent(motionEvent);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onTrackballEvent(MotionEvent motionEvent) {
|
||||||
|
return mMapMover.onTrackballEvent(motionEvent);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calculates all necessary tiles and adds jobs accordingly.
|
||||||
|
*/
|
||||||
|
public synchronized void redrawTiles() {
|
||||||
|
if (getWidth() <= 0 || getHeight() <= 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
mMapRenderer.redrawTiles(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
void clearAndRedrawMapView() {
|
||||||
|
if (getWidth() <= 0 || getHeight() <= 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
mMapRenderer.redrawTiles(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the visibility of the zoom controls.
|
||||||
|
*
|
||||||
|
* @param showZoomControls
|
||||||
|
* true if the zoom controls should be visible, false otherwise.
|
||||||
|
*/
|
||||||
|
public void setBuiltInZoomControls(boolean showZoomControls) {
|
||||||
|
mMapZoomControls.setShowMapZoomControls(showZoomControls);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the center of the MapView and triggers a redraw.
|
||||||
|
*
|
||||||
|
* @param geoPoint
|
||||||
|
* the new center point of the map.
|
||||||
|
*/
|
||||||
|
public void setCenter(GeoPoint geoPoint) {
|
||||||
|
MapPosition mapPosition = new MapPosition(geoPoint, mMapViewPosition.getZoomLevel(), 1);
|
||||||
|
setCenterAndZoom(mapPosition);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param debugSettings
|
||||||
|
* the new DebugSettings for this MapView.
|
||||||
|
*/
|
||||||
|
public void setDebugSettings(DebugSettings debugSettings) {
|
||||||
|
mDebugSettings = debugSettings;
|
||||||
|
|
||||||
|
clearAndRedrawMapView();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the map file for this MapView.
|
||||||
|
*
|
||||||
|
* @param mapFile
|
||||||
|
* the path to the map file.
|
||||||
|
* @return true if the map file was set correctly, false otherwise.
|
||||||
|
* @throws UnsupportedOperationException
|
||||||
|
* if the current MapGenerator mode works with an Internet connection.
|
||||||
|
*/
|
||||||
|
public boolean setMapFile(String mapFile) {
|
||||||
|
if (mMapGenerator.requiresInternetConnection()) {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
Log.d(TAG, "set mapfile " + mapFile);
|
||||||
|
if (mapFile == null) {
|
||||||
|
// no map file specified
|
||||||
|
return false;
|
||||||
|
} else if (mapFile.equals(mMapFile)) {
|
||||||
|
// same map file as before
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
mZoomAnimator.pause();
|
||||||
|
mMapWorker.pause();
|
||||||
|
mMapMover.pause();
|
||||||
|
mZoomAnimator.awaitPausing();
|
||||||
|
mMapMover.awaitPausing();
|
||||||
|
mMapWorker.awaitPausing();
|
||||||
|
mMapMover.stopMove();
|
||||||
|
|
||||||
|
mZoomAnimator.proceed();
|
||||||
|
mMapWorker.proceed();
|
||||||
|
mMapMover.proceed();
|
||||||
|
|
||||||
|
mMapDatabase.closeFile();
|
||||||
|
FileOpenResult fileOpenResult = mMapDatabase.openFile(new File(mapFile));
|
||||||
|
if (fileOpenResult.isSuccess()) {
|
||||||
|
mMapFile = mapFile;
|
||||||
|
|
||||||
|
GeoPoint startPoint = mMapGenerator.getStartPoint();
|
||||||
|
if (startPoint != null) {
|
||||||
|
Log.d(TAG, "mapfile got startpoint");
|
||||||
|
mMapViewPosition.setMapCenter(startPoint);
|
||||||
|
}
|
||||||
|
|
||||||
|
Byte startZoomLevel = mMapGenerator.getStartZoomLevel();
|
||||||
|
if (startZoomLevel != null) {
|
||||||
|
Log.d(TAG, "mapfile got start zoomlevel");
|
||||||
|
mMapViewPosition.setZoomLevel(startZoomLevel.byteValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
clearAndRedrawMapView();
|
||||||
|
Log.d(TAG, "mapfile set");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
mMapFile = null;
|
||||||
|
clearAndRedrawMapView();
|
||||||
|
Log.d(TAG, "loading mapfile failed");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the MapGenerator for this MapView.
|
||||||
|
*
|
||||||
|
* @param mapGenerator
|
||||||
|
* the new MapGenerator.
|
||||||
|
*/
|
||||||
|
public void setMapGenerator(MapGenerator mapGenerator) {
|
||||||
|
|
||||||
|
if (mMapGenerator != mapGenerator) {
|
||||||
|
setMapGeneratorInternal(mapGenerator);
|
||||||
|
|
||||||
|
clearAndRedrawMapView();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setMapGeneratorInternal(MapGenerator mapGenerator) {
|
||||||
|
if (mapGenerator == null) {
|
||||||
|
throw new IllegalArgumentException("mapGenerator must not be null");
|
||||||
|
}
|
||||||
|
|
||||||
|
mapGenerator.setMapDatabase(mMapDatabase);
|
||||||
|
|
||||||
|
mMapGenerator = mapGenerator;
|
||||||
|
mMapWorker.setMapGenerator(mMapGenerator);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the MapDatabase for this MapView.
|
||||||
|
*
|
||||||
|
* @param mapDatabase
|
||||||
|
* the new MapDatabase.
|
||||||
|
*/
|
||||||
|
public void setMapDatabase(IMapDatabase mapDatabase) {
|
||||||
|
Log.d(TAG, "setMapDatabase " + mapDatabase.getClass());
|
||||||
|
if (mMapDatabase != mapDatabase) {
|
||||||
|
|
||||||
|
if (mMapDatabase != null)
|
||||||
|
mMapDatabase.closeFile();
|
||||||
|
|
||||||
|
setMapDatabaseInternal(mapDatabase);
|
||||||
|
|
||||||
|
// clearAndRedrawMapView();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setMapDatabaseInternal(IMapDatabase mapDatabase) {
|
||||||
|
if (mapDatabase == null) {
|
||||||
|
throw new IllegalArgumentException("MapDatabase must not be null");
|
||||||
|
}
|
||||||
|
// mMapWorker.pause();
|
||||||
|
// mMapWorker.awaitPausing();
|
||||||
|
|
||||||
|
mMapDatabase = mapDatabase;
|
||||||
|
mMapGenerator.setMapDatabase(mMapDatabase);
|
||||||
|
|
||||||
|
Log.d(TAG, "setMapDatabaseInternal " + mapDatabase.getClass());
|
||||||
|
// mMapWorker.proceed();
|
||||||
|
|
||||||
|
String mapFile = mMapFile;
|
||||||
|
mMapFile = null;
|
||||||
|
setMapFile(mapFile);
|
||||||
|
|
||||||
|
// mMapWorker.setMapDatabase(mMapDatabase);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the internal theme which is used for rendering the map.
|
||||||
|
*
|
||||||
|
* @param internalRenderTheme
|
||||||
|
* the internal rendering theme.
|
||||||
|
* @throws IllegalArgumentException
|
||||||
|
* if the supplied internalRenderTheme is null.
|
||||||
|
* @throws UnsupportedOperationException
|
||||||
|
* if the current MapGenerator does not support render themes.
|
||||||
|
*/
|
||||||
|
public void setRenderTheme(InternalRenderTheme internalRenderTheme) {
|
||||||
|
if (internalRenderTheme == null) {
|
||||||
|
throw new IllegalArgumentException("render theme must not be null");
|
||||||
|
} else if (mMapGenerator.requiresInternetConnection()) {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
Log.d(TAG, "set rendertheme " + internalRenderTheme);
|
||||||
|
mJobParameters = new JobParameters(internalRenderTheme, mJobParameters.textScale);
|
||||||
|
|
||||||
|
clearAndRedrawMapView();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the theme file which is used for rendering the map.
|
||||||
|
*
|
||||||
|
* @param renderThemePath
|
||||||
|
* the path to the XML file which defines the rendering theme.
|
||||||
|
* @throws IllegalArgumentException
|
||||||
|
* if the supplied internalRenderTheme is null.
|
||||||
|
* @throws UnsupportedOperationException
|
||||||
|
* if the current MapGenerator does not support render themes.
|
||||||
|
* @throws FileNotFoundException
|
||||||
|
* if the supplied file does not exist, is a directory or cannot be read.
|
||||||
|
*/
|
||||||
|
public void setRenderTheme(String renderThemePath) throws FileNotFoundException {
|
||||||
|
if (renderThemePath == null) {
|
||||||
|
throw new IllegalArgumentException("render theme path must not be null");
|
||||||
|
} else if (mMapGenerator.requiresInternetConnection()) {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
|
||||||
|
JobTheme jobTheme = new ExternalRenderTheme(renderThemePath);
|
||||||
|
mJobParameters = new JobParameters(jobTheme, mJobParameters.textScale);
|
||||||
|
|
||||||
|
clearAndRedrawMapView();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the text scale for the map rendering. Has no effect in downloading mode.
|
||||||
|
*
|
||||||
|
* @param textScale
|
||||||
|
* the new text scale for the map rendering.
|
||||||
|
*/
|
||||||
|
public void setTextScale(float textScale) {
|
||||||
|
mJobParameters = new JobParameters(mJobParameters.jobTheme, textScale);
|
||||||
|
clearAndRedrawMapView();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Zooms in or out by the given amount of zoom levels.
|
||||||
|
*
|
||||||
|
* @param zoomLevelDiff
|
||||||
|
* the difference to the current zoom level.
|
||||||
|
* @return true if the zoom level was changed, false otherwise.
|
||||||
|
*/
|
||||||
|
public boolean zoom(byte zoomLevelDiff) {
|
||||||
|
|
||||||
|
int z = mMapViewPosition.getZoomLevel() + zoomLevelDiff;
|
||||||
|
if (zoomLevelDiff > 0) {
|
||||||
|
// check if zoom in is possible
|
||||||
|
if (z > getMaximumPossibleZoomLevel()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
} else if (zoomLevelDiff < 0) {
|
||||||
|
// check if zoom out is possible
|
||||||
|
if (z < mMapZoomControls.getZoomLevelMin()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mMapViewPosition.setZoomLevel((byte) z);
|
||||||
|
|
||||||
|
redrawTiles();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
|
||||||
|
super.onLayout(changed, left, top, right, bottom);
|
||||||
|
// mMapZoomControls.onLayout(changed, left, top, right, bottom);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected final void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
|
||||||
|
// find out how big the zoom controls should be
|
||||||
|
mMapZoomControls.measure(
|
||||||
|
MeasureSpec.makeMeasureSpec(MeasureSpec.getSize(widthMeasureSpec), MeasureSpec.AT_MOST),
|
||||||
|
MeasureSpec.makeMeasureSpec(MeasureSpec.getSize(heightMeasureSpec), MeasureSpec.AT_MOST));
|
||||||
|
|
||||||
|
// make sure that MapView is big enough to display the zoom controls
|
||||||
|
setMeasuredDimension(Math.max(MeasureSpec.getSize(widthMeasureSpec), mMapZoomControls.getMeasuredWidth()),
|
||||||
|
Math.max(MeasureSpec.getSize(heightMeasureSpec), mMapZoomControls.getMeasuredHeight()));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected synchronized void onSizeChanged(int width, int height, int oldWidth, int oldHeight) {
|
||||||
|
mMapWorker.pause();
|
||||||
|
mMapWorker.awaitPausing();
|
||||||
|
super.onSizeChanged(width, height, oldWidth, oldHeight);
|
||||||
|
mMapWorker.proceed();
|
||||||
|
|
||||||
|
// redrawTiles();
|
||||||
|
}
|
||||||
|
|
||||||
|
void destroy() {
|
||||||
|
mMapMover.interrupt();
|
||||||
|
mMapWorker.interrupt();
|
||||||
|
mZoomAnimator.interrupt();
|
||||||
|
|
||||||
|
try {
|
||||||
|
mMapWorker.join();
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
// restore the interrupted status
|
||||||
|
Thread.currentThread().interrupt();
|
||||||
|
}
|
||||||
|
|
||||||
|
mMapScaleBar.destroy();
|
||||||
|
mMapDatabase.closeFile();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the maximum possible zoom level.
|
||||||
|
*/
|
||||||
|
byte getMaximumPossibleZoomLevel() {
|
||||||
|
return (byte) Math.min(mMapZoomControls.getZoomLevelMax(), mMapGenerator.getZoomLevelMax());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return true if the current center position of this MapView is valid, false otherwise.
|
||||||
|
*/
|
||||||
|
boolean hasValidCenter() {
|
||||||
|
if (!mMapViewPosition.isValid()) {
|
||||||
|
return false;
|
||||||
|
} else if (!mMapGenerator.requiresInternetConnection() &&
|
||||||
|
(!mMapDatabase.hasOpenFile() ||
|
||||||
|
!mMapDatabase.getMapFileInfo().boundingBox
|
||||||
|
.contains(getMapPosition().getMapCenter()))) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
byte limitZoomLevel(byte zoom) {
|
||||||
|
return (byte) Math.max(Math.min(zoom, getMaximumPossibleZoomLevel()), mMapZoomControls.getZoomLevelMin());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onPause() {
|
||||||
|
super.onPause();
|
||||||
|
mMapWorker.pause();
|
||||||
|
mMapMover.pause();
|
||||||
|
mZoomAnimator.pause();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onResume() {
|
||||||
|
super.onResume();
|
||||||
|
mMapWorker.proceed();
|
||||||
|
mMapMover.proceed();
|
||||||
|
mZoomAnimator.proceed();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the center and zoom level of this MapView and triggers a redraw.
|
||||||
|
*
|
||||||
|
* @param mapPosition
|
||||||
|
* the new map position of this MapView.
|
||||||
|
*/
|
||||||
|
void setCenterAndZoom(MapPosition mapPosition) {
|
||||||
|
|
||||||
|
// if (hasValidCenter()) {
|
||||||
|
// // calculate the distance between previous and current position
|
||||||
|
// MapPosition mapPositionOld = mapViewPosition.getMapPosition();
|
||||||
|
|
||||||
|
// GeoPoint geoPointOld = mapPositionOld.geoPoint;
|
||||||
|
// GeoPoint geoPointNew = mapPosition.geoPoint;
|
||||||
|
// double oldPixelX =
|
||||||
|
// MercatorProjection.longitudeToPixelX(geoPointOld.getLongitude(),
|
||||||
|
// mapPositionOld.zoomLevel);
|
||||||
|
// double newPixelX =
|
||||||
|
// MercatorProjection.longitudeToPixelX(geoPointNew.getLongitude(),
|
||||||
|
// mapPosition.zoomLevel);
|
||||||
|
//
|
||||||
|
// double oldPixelY =
|
||||||
|
// MercatorProjection.latitudeToPixelY(geoPointOld.getLatitude(),
|
||||||
|
// mapPositionOld.zoomLevel);
|
||||||
|
// double newPixelY =
|
||||||
|
// MercatorProjection.latitudeToPixelY(geoPointNew.getLatitude(),
|
||||||
|
// mapPosition.zoomLevel);
|
||||||
|
|
||||||
|
// float matrixTranslateX = (float) (oldPixelX - newPixelX);
|
||||||
|
// float matrixTranslateY = (float) (oldPixelY - newPixelY);
|
||||||
|
// frameBuffer.matrixPostTranslate(matrixTranslateX,
|
||||||
|
// matrixTranslateY);
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
mMapViewPosition.setMapCenterAndZoomLevel(mapPosition);
|
||||||
|
// mapZoomControls.onZoomLevelChange(mapViewPosition.getZoomLevel());
|
||||||
|
redrawTiles();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return MapPosition
|
||||||
|
*/
|
||||||
|
public MapViewPosition getMapViewPosition() {
|
||||||
|
return mMapViewPosition;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return current JobParameters
|
||||||
|
*/
|
||||||
|
public JobParameters getJobParameters() {
|
||||||
|
return mJobParameters;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return MapWorker
|
||||||
|
*/
|
||||||
|
public MapWorker getMapWorker() {
|
||||||
|
return mMapWorker;
|
||||||
|
}
|
||||||
|
}
|
||||||
230
src/org/mapsforge/android/MapViewPosition.java
Normal file
230
src/org/mapsforge/android/MapViewPosition.java
Normal file
@@ -0,0 +1,230 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010, 2011, 2012 mapsforge.org
|
||||||
|
*
|
||||||
|
* 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.mapsforge.android;
|
||||||
|
|
||||||
|
import org.mapsforge.core.GeoPoint;
|
||||||
|
import org.mapsforge.core.MapPosition;
|
||||||
|
import org.mapsforge.core.MercatorProjection;
|
||||||
|
|
||||||
|
import android.util.FloatMath;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A MapPosition stores the latitude and longitude coordinate of a MapView together with its zoom level.
|
||||||
|
*/
|
||||||
|
public class MapViewPosition {
|
||||||
|
private static float MAX_SCALE = 2.0f;
|
||||||
|
private static float MIN_SCALE = 1.0f;
|
||||||
|
|
||||||
|
private double mLatitude;
|
||||||
|
private double mLongitude;
|
||||||
|
private final MapView mMapView;
|
||||||
|
private byte mZoomLevel;
|
||||||
|
private float mScale;
|
||||||
|
|
||||||
|
// private float mRotation;
|
||||||
|
|
||||||
|
MapViewPosition(MapView mapView) {
|
||||||
|
mMapView = mapView;
|
||||||
|
|
||||||
|
mLatitude = Double.NaN;
|
||||||
|
mLongitude = Double.NaN;
|
||||||
|
mZoomLevel = -1;
|
||||||
|
mScale = 1;
|
||||||
|
// mRotation = 0.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the current center point of the MapView.
|
||||||
|
*/
|
||||||
|
public synchronized GeoPoint getMapCenter() {
|
||||||
|
return new GeoPoint(mLatitude, mLongitude);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return an immutable MapPosition or null, if this map position is not valid.
|
||||||
|
* @see #isValid()
|
||||||
|
*/
|
||||||
|
public synchronized MapPosition getMapPosition() {
|
||||||
|
if (!isValid()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
GeoPoint geoPoint = new GeoPoint(mLatitude, mLongitude);
|
||||||
|
return new MapPosition(geoPoint, mZoomLevel, mScale);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the current zoom level of the MapView.
|
||||||
|
*/
|
||||||
|
public synchronized byte getZoomLevel() {
|
||||||
|
return mZoomLevel;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the current scale of the MapView.
|
||||||
|
*/
|
||||||
|
public synchronized float getScale() {
|
||||||
|
return mScale;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return true if this MapViewPosition is valid, false otherwise.
|
||||||
|
*/
|
||||||
|
public synchronized boolean isValid() {
|
||||||
|
if (Double.isNaN(mLatitude)) {
|
||||||
|
return false;
|
||||||
|
} else if (mLatitude < MercatorProjection.LATITUDE_MIN) {
|
||||||
|
return false;
|
||||||
|
} else if (mLatitude > MercatorProjection.LATITUDE_MAX) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Double.isNaN(mLongitude)) {
|
||||||
|
return false;
|
||||||
|
} else if (mLongitude < MercatorProjection.LONGITUDE_MIN) {
|
||||||
|
return false;
|
||||||
|
} else if (mLongitude > MercatorProjection.LONGITUDE_MAX) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Moves this MapViewPosition by the given amount of pixels.
|
||||||
|
*
|
||||||
|
* @param moveHorizontal
|
||||||
|
* the amount of pixels to move the map horizontally.
|
||||||
|
* @param moveVertical
|
||||||
|
* the amount of pixels to move the map vertically.
|
||||||
|
*/
|
||||||
|
public synchronized void moveMap(float moveHorizontal, float moveVertical) {
|
||||||
|
double pixelX = MercatorProjection.longitudeToPixelX(mLongitude, mZoomLevel);
|
||||||
|
double pixelY = MercatorProjection.latitudeToPixelY(mLatitude, mZoomLevel);
|
||||||
|
|
||||||
|
mLatitude = MercatorProjection.pixelYToLatitude(pixelY - moveVertical / mScale,
|
||||||
|
mZoomLevel);
|
||||||
|
mLatitude = MercatorProjection.limitLatitude(mLatitude);
|
||||||
|
|
||||||
|
mLongitude = MercatorProjection.pixelXToLongitude(pixelX - moveHorizontal / mScale,
|
||||||
|
mZoomLevel);
|
||||||
|
mLongitude = MercatorProjection.limitLongitude(mLongitude);
|
||||||
|
}
|
||||||
|
|
||||||
|
// public synchronized void rotateMap(float angle) {
|
||||||
|
// mRotation = angle;
|
||||||
|
// }
|
||||||
|
|
||||||
|
synchronized void setMapCenter(GeoPoint geoPoint) {
|
||||||
|
mLatitude = MercatorProjection.limitLatitude(geoPoint.getLatitude());
|
||||||
|
mLongitude = MercatorProjection.limitLongitude(geoPoint.getLongitude());
|
||||||
|
}
|
||||||
|
|
||||||
|
synchronized void setMapCenterAndZoomLevel(MapPosition mapPosition) {
|
||||||
|
GeoPoint geoPoint = mapPosition.geoPoint;
|
||||||
|
mLatitude = MercatorProjection.limitLatitude(geoPoint.getLatitude());
|
||||||
|
mLongitude = MercatorProjection.limitLongitude(geoPoint.getLongitude());
|
||||||
|
mZoomLevel = mMapView.limitZoomLevel(mapPosition.zoomLevel);
|
||||||
|
}
|
||||||
|
|
||||||
|
synchronized void setZoomLevel(byte zoomLevel) {
|
||||||
|
mZoomLevel = mMapView.limitZoomLevel(zoomLevel);
|
||||||
|
}
|
||||||
|
|
||||||
|
synchronized void setScale(float scale) {
|
||||||
|
mScale = scale;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param scale
|
||||||
|
* ...
|
||||||
|
* @param pivotX
|
||||||
|
* ...
|
||||||
|
* @param pivotY
|
||||||
|
* ...
|
||||||
|
*/
|
||||||
|
public synchronized void scaleMap(float scale, float pivotX, float pivotY) {
|
||||||
|
moveMap(pivotX * (1.0f - scale),
|
||||||
|
pivotY * (1.0f - scale));
|
||||||
|
|
||||||
|
float s = mScale * scale;
|
||||||
|
|
||||||
|
if (s >= MAX_SCALE) {
|
||||||
|
|
||||||
|
byte z = (byte) FloatMath.sqrt(s);
|
||||||
|
mZoomLevel += z;
|
||||||
|
s *= 1.0f / (1 << z);
|
||||||
|
} else if (s < MIN_SCALE) {
|
||||||
|
byte z = (byte) FloatMath.sqrt(1 / s);
|
||||||
|
mZoomLevel -= z;
|
||||||
|
s *= 1 << z;
|
||||||
|
}
|
||||||
|
|
||||||
|
mScale = s;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Zooms in or out by the given amount of zoom levels.
|
||||||
|
*
|
||||||
|
* @param zoomLevelDiff
|
||||||
|
* the difference to the current zoom level.
|
||||||
|
* @param s
|
||||||
|
* scale between min/max zoom
|
||||||
|
* @return true if the zoom level was changed, false otherwise.
|
||||||
|
*/
|
||||||
|
// public boolean zoom(byte zoomLevelDiff, float s) {
|
||||||
|
// float scale = s;
|
||||||
|
//
|
||||||
|
// if (zoomLevelDiff > 0) {
|
||||||
|
// // check if zoom in is possible
|
||||||
|
// if (mMapViewPosition.getZoomLevel() + zoomLevelDiff > getMaximumPossibleZoomLevel()) {
|
||||||
|
// return false;
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// scale *= 1.0f / (1 << zoomLevelDiff);
|
||||||
|
// } else if (zoomLevelDiff < 0) {
|
||||||
|
// // check if zoom out is possible
|
||||||
|
// if (mMapViewPosition.getZoomLevel() + zoomLevelDiff < mMapZoomControls.getZoomLevelMin()) {
|
||||||
|
// return false;
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// scale *= 1 << -zoomLevelDiff;
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// if (scale == 0)
|
||||||
|
// scale = 1;
|
||||||
|
// // else
|
||||||
|
// // scale = Math.round(256.0f * scale) / 256.0f;
|
||||||
|
//
|
||||||
|
// mMapViewPosition.setZoomLevel((byte) (mMapViewPosition.getZoomLevel() + zoomLevelDiff));
|
||||||
|
//
|
||||||
|
// // mapZoomControls.onZoomLevelChange(mapViewPosition.getZoomLevel());
|
||||||
|
//
|
||||||
|
// // zoomAnimator.setParameters(zoomStart, matrixScaleFactor,
|
||||||
|
// // getWidth() >> 1, getHeight() >> 1);
|
||||||
|
// // zoomAnimator.startAnimation();
|
||||||
|
//
|
||||||
|
// // if (scale > MAX_ZOOM) {
|
||||||
|
// // scale = MAX_ZOOM;
|
||||||
|
// // }
|
||||||
|
//
|
||||||
|
// if (zoomLevelDiff != 0 || mZoomFactor != scale) {
|
||||||
|
// mZoomFactor = scale;
|
||||||
|
// redrawTiles();
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// return true;
|
||||||
|
// }
|
||||||
|
|
||||||
|
}
|
||||||
120
src/org/mapsforge/android/MapViewProjection.java
Normal file
120
src/org/mapsforge/android/MapViewProjection.java
Normal file
@@ -0,0 +1,120 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010, 2011, 2012 mapsforge.org
|
||||||
|
*
|
||||||
|
* 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.mapsforge.android;
|
||||||
|
|
||||||
|
import org.mapsforge.core.GeoPoint;
|
||||||
|
import org.mapsforge.core.MapPosition;
|
||||||
|
import org.mapsforge.core.MercatorProjection;
|
||||||
|
|
||||||
|
import android.graphics.Point;
|
||||||
|
|
||||||
|
class MapViewProjection implements Projection {
|
||||||
|
private static final String INVALID_MAP_VIEW_DIMENSIONS = "invalid MapView dimensions";
|
||||||
|
|
||||||
|
private final MapView mMapView;
|
||||||
|
|
||||||
|
MapViewProjection(MapView mapView) {
|
||||||
|
mMapView = mapView;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public GeoPoint fromPixels(int x, int y) {
|
||||||
|
if (mMapView.getWidth() <= 0 || mMapView.getHeight() <= 0) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
MapPosition mapPosition = mMapView.getMapPosition().getMapPosition();
|
||||||
|
|
||||||
|
// calculate the pixel coordinates of the top left corner
|
||||||
|
GeoPoint geoPoint = mapPosition.geoPoint;
|
||||||
|
double pixelX = MercatorProjection.longitudeToPixelX(geoPoint.getLongitude(), mapPosition.zoomLevel);
|
||||||
|
double pixelY = MercatorProjection.latitudeToPixelY(geoPoint.getLatitude(), mapPosition.zoomLevel);
|
||||||
|
pixelX -= mMapView.getWidth() >> 1;
|
||||||
|
pixelY -= mMapView.getHeight() >> 1;
|
||||||
|
|
||||||
|
// convert the pixel coordinates to a GeoPoint and return it
|
||||||
|
return new GeoPoint(MercatorProjection.pixelYToLatitude(pixelY + y, mapPosition.zoomLevel),
|
||||||
|
MercatorProjection.pixelXToLongitude(pixelX + x, mapPosition.zoomLevel));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getLatitudeSpan() {
|
||||||
|
if (mMapView.getWidth() > 0 && mMapView.getWidth() > 0) {
|
||||||
|
GeoPoint top = fromPixels(0, 0);
|
||||||
|
GeoPoint bottom = fromPixels(0, mMapView.getHeight());
|
||||||
|
return Math.abs(top.latitudeE6 - bottom.latitudeE6);
|
||||||
|
}
|
||||||
|
throw new IllegalStateException(INVALID_MAP_VIEW_DIMENSIONS);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getLongitudeSpan() {
|
||||||
|
if (mMapView.getWidth() > 0 && mMapView.getWidth() > 0) {
|
||||||
|
GeoPoint left = fromPixels(0, 0);
|
||||||
|
GeoPoint right = fromPixels(mMapView.getWidth(), 0);
|
||||||
|
return Math.abs(left.longitudeE6 - right.longitudeE6);
|
||||||
|
}
|
||||||
|
throw new IllegalStateException(INVALID_MAP_VIEW_DIMENSIONS);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public float metersToPixels(float meters, byte zoom) {
|
||||||
|
double latitude = mMapView.getMapPosition().getMapCenter().getLatitude();
|
||||||
|
double groundResolution = MercatorProjection.calculateGroundResolution(latitude, zoom);
|
||||||
|
return (float) (meters * (1 / groundResolution));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Point toPixels(GeoPoint in, Point out) {
|
||||||
|
if (mMapView.getWidth() <= 0 || mMapView.getHeight() <= 0) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
MapPosition mapPosition = mMapView.getMapPosition().getMapPosition();
|
||||||
|
|
||||||
|
// calculate the pixel coordinates of the top left corner
|
||||||
|
GeoPoint geoPoint = mapPosition.geoPoint;
|
||||||
|
double pixelX = MercatorProjection.longitudeToPixelX(geoPoint.getLongitude(), mapPosition.zoomLevel);
|
||||||
|
double pixelY = MercatorProjection.latitudeToPixelY(geoPoint.getLatitude(), mapPosition.zoomLevel);
|
||||||
|
pixelX -= mMapView.getWidth() >> 1;
|
||||||
|
pixelY -= mMapView.getHeight() >> 1;
|
||||||
|
|
||||||
|
if (out == null) {
|
||||||
|
// create a new point and return it
|
||||||
|
return new Point(
|
||||||
|
(int) (MercatorProjection.longitudeToPixelX(in.getLongitude(), mapPosition.zoomLevel) - pixelX),
|
||||||
|
(int) (MercatorProjection.latitudeToPixelY(in.getLatitude(), mapPosition.zoomLevel) - pixelY));
|
||||||
|
}
|
||||||
|
|
||||||
|
// reuse the existing point
|
||||||
|
out.x = (int) (MercatorProjection.longitudeToPixelX(in.getLongitude(), mapPosition.zoomLevel) - pixelX);
|
||||||
|
out.y = (int) (MercatorProjection.latitudeToPixelY(in.getLatitude(), mapPosition.zoomLevel) - pixelY);
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Point toPoint(GeoPoint in, Point out, byte zoom) {
|
||||||
|
if (out == null) {
|
||||||
|
// create a new point and return it
|
||||||
|
return new Point((int) MercatorProjection.longitudeToPixelX(in.getLongitude(), zoom),
|
||||||
|
(int) MercatorProjection.latitudeToPixelY(in.getLatitude(), zoom));
|
||||||
|
}
|
||||||
|
|
||||||
|
// reuse the existing point
|
||||||
|
out.x = (int) MercatorProjection.longitudeToPixelX(in.getLongitude(), zoom);
|
||||||
|
out.y = (int) MercatorProjection.latitudeToPixelY(in.getLatitude(), zoom);
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
}
|
||||||
309
src/org/mapsforge/android/MapZoomControls.java
Normal file
309
src/org/mapsforge/android/MapZoomControls.java
Normal file
@@ -0,0 +1,309 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010, 2011, 2012 mapsforge.org
|
||||||
|
*
|
||||||
|
* 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.mapsforge.android;
|
||||||
|
|
||||||
|
import org.mapsforge.android.mapgenerator.MapGenerator;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.os.Handler;
|
||||||
|
import android.os.Message;
|
||||||
|
import android.view.Gravity;
|
||||||
|
import android.view.MotionEvent;
|
||||||
|
import android.view.View;
|
||||||
|
import android.view.ViewConfiguration;
|
||||||
|
import android.widget.ZoomControls;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A MapZoomControls instance displays buttons for zooming in and out in a map.
|
||||||
|
*/
|
||||||
|
public class MapZoomControls {
|
||||||
|
private static class ZoomControlsHideHandler extends Handler {
|
||||||
|
private final ZoomControls mZoomControls;
|
||||||
|
|
||||||
|
ZoomControlsHideHandler(ZoomControls zoomControls) {
|
||||||
|
super();
|
||||||
|
mZoomControls = zoomControls;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void handleMessage(Message message) {
|
||||||
|
mZoomControls.hide();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class ZoomInClickListener implements View.OnClickListener {
|
||||||
|
private final MapView mMapView;
|
||||||
|
|
||||||
|
ZoomInClickListener(MapView mapView) {
|
||||||
|
mMapView = mapView;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onClick(View view) {
|
||||||
|
mMapView.zoom((byte) 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class ZoomOutClickListener implements View.OnClickListener {
|
||||||
|
private final MapView mMapView;
|
||||||
|
|
||||||
|
ZoomOutClickListener(MapView mapView) {
|
||||||
|
mMapView = mapView;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onClick(View view) {
|
||||||
|
mMapView.zoom((byte) -1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Default {@link Gravity} of the zoom controls.
|
||||||
|
*/
|
||||||
|
private static final int DEFAULT_ZOOM_CONTROLS_GRAVITY = Gravity.BOTTOM | Gravity.RIGHT;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Default maximum zoom level.
|
||||||
|
*/
|
||||||
|
private static final byte DEFAULT_ZOOM_LEVEL_MAX = 22;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Default minimum zoom level.
|
||||||
|
*/
|
||||||
|
private static final byte DEFAULT_ZOOM_LEVEL_MIN = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Message code for the handler to hide the zoom controls.
|
||||||
|
*/
|
||||||
|
private static final int MSG_ZOOM_CONTROLS_HIDE = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Horizontal padding for the zoom controls.
|
||||||
|
*/
|
||||||
|
private static final int ZOOM_CONTROLS_HORIZONTAL_PADDING = 5;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Delay in milliseconds after which the zoom controls disappear.
|
||||||
|
*/
|
||||||
|
private static final long ZOOM_CONTROLS_TIMEOUT = ViewConfiguration.getZoomControlsTimeout();
|
||||||
|
|
||||||
|
private boolean mGravityChanged;
|
||||||
|
private boolean mShowMapZoomControls;
|
||||||
|
private final ZoomControls mZoomControls;
|
||||||
|
private int mZoomControlsGravity;
|
||||||
|
private final Handler mZoomControlsHideHandler;
|
||||||
|
private byte mZoomLevelMax;
|
||||||
|
private byte mZoomLevelMin;
|
||||||
|
|
||||||
|
MapZoomControls(Context context, final MapView mapView) {
|
||||||
|
mZoomControls = new ZoomControls(context);
|
||||||
|
mShowMapZoomControls = true;
|
||||||
|
mZoomLevelMax = DEFAULT_ZOOM_LEVEL_MAX;
|
||||||
|
mZoomLevelMin = DEFAULT_ZOOM_LEVEL_MIN;
|
||||||
|
mZoomControls.setVisibility(View.GONE);
|
||||||
|
mZoomControlsGravity = DEFAULT_ZOOM_CONTROLS_GRAVITY;
|
||||||
|
|
||||||
|
mZoomControls.setOnZoomInClickListener(new ZoomInClickListener(mapView));
|
||||||
|
mZoomControls.setOnZoomOutClickListener(new ZoomOutClickListener(mapView));
|
||||||
|
mZoomControlsHideHandler = new ZoomControlsHideHandler(mZoomControls);
|
||||||
|
|
||||||
|
// int wrapContent = android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
|
||||||
|
// LayoutParams layoutParams = new LayoutParams(wrapContent, wrapContent);
|
||||||
|
// mapView.addView(zoomControls, layoutParams);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the current gravity for the placing of the zoom controls.
|
||||||
|
* @see Gravity
|
||||||
|
*/
|
||||||
|
public int getZoomControlsGravity() {
|
||||||
|
return mZoomControlsGravity;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the maximum zoom level of the map.
|
||||||
|
*/
|
||||||
|
public byte getZoomLevelMax() {
|
||||||
|
return mZoomLevelMax;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the minimum zoom level of the map.
|
||||||
|
*/
|
||||||
|
public byte getZoomLevelMin() {
|
||||||
|
return mZoomLevelMin;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return true if the zoom controls are visible, false otherwise.
|
||||||
|
*/
|
||||||
|
public boolean isShowMapZoomControls() {
|
||||||
|
return mShowMapZoomControls;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param showMapZoomControls
|
||||||
|
* true if the zoom controls should be visible, false otherwise.
|
||||||
|
*/
|
||||||
|
public void setShowMapZoomControls(boolean showMapZoomControls) {
|
||||||
|
mShowMapZoomControls = false; // showMapZoomControls;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the gravity for the placing of the zoom controls. Supported values are {@link Gravity#TOP},
|
||||||
|
* {@link Gravity#CENTER_VERTICAL}, {@link Gravity#BOTTOM}, {@link Gravity#LEFT}, {@link Gravity#CENTER_HORIZONTAL}
|
||||||
|
* and {@link Gravity#RIGHT}.
|
||||||
|
*
|
||||||
|
* @param zoomControlsGravity
|
||||||
|
* a combination of {@link Gravity} constants describing the desired placement.
|
||||||
|
*/
|
||||||
|
public void setZoomControlsGravity(int zoomControlsGravity) {
|
||||||
|
if (mZoomControlsGravity != zoomControlsGravity) {
|
||||||
|
mZoomControlsGravity = zoomControlsGravity;
|
||||||
|
mGravityChanged = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the maximum zoom level of the map.
|
||||||
|
* <p>
|
||||||
|
* The maximum possible zoom level of the MapView depends also on the current {@link MapGenerator}. For example,
|
||||||
|
* downloading map tiles may only be possible up to a certain zoom level. Setting a higher maximum zoom level has no
|
||||||
|
* effect in this case.
|
||||||
|
*
|
||||||
|
* @param zoomLevelMax
|
||||||
|
* the maximum zoom level.
|
||||||
|
* @throws IllegalArgumentException
|
||||||
|
* if the maximum zoom level is smaller than the current minimum zoom level.
|
||||||
|
*/
|
||||||
|
public void setZoomLevelMax(byte zoomLevelMax) {
|
||||||
|
if (zoomLevelMax < mZoomLevelMin) {
|
||||||
|
throw new IllegalArgumentException();
|
||||||
|
}
|
||||||
|
mZoomLevelMax = zoomLevelMax;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the minimum zoom level of the map.
|
||||||
|
*
|
||||||
|
* @param zoomLevelMin
|
||||||
|
* the minimum zoom level.
|
||||||
|
* @throws IllegalArgumentException
|
||||||
|
* if the minimum zoom level is larger than the current maximum zoom level.
|
||||||
|
*/
|
||||||
|
public void setZoomLevelMin(byte zoomLevelMin) {
|
||||||
|
if (zoomLevelMin > mZoomLevelMax) {
|
||||||
|
throw new IllegalArgumentException();
|
||||||
|
}
|
||||||
|
mZoomLevelMin = zoomLevelMin;
|
||||||
|
}
|
||||||
|
|
||||||
|
private int calculatePositionLeft(int left, int right, int zoomControlsWidth) {
|
||||||
|
int gravity = mZoomControlsGravity & Gravity.HORIZONTAL_GRAVITY_MASK;
|
||||||
|
switch (gravity) {
|
||||||
|
case Gravity.LEFT:
|
||||||
|
return ZOOM_CONTROLS_HORIZONTAL_PADDING;
|
||||||
|
|
||||||
|
case Gravity.CENTER_HORIZONTAL:
|
||||||
|
return (right - left - zoomControlsWidth) / 2;
|
||||||
|
|
||||||
|
case Gravity.RIGHT:
|
||||||
|
return right - left - zoomControlsWidth - ZOOM_CONTROLS_HORIZONTAL_PADDING;
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new IllegalArgumentException("unknown horizontal gravity: " + gravity);
|
||||||
|
}
|
||||||
|
|
||||||
|
private int calculatePositionTop(int top, int bottom, int zoomControlsHeight) {
|
||||||
|
int gravity = mZoomControlsGravity & Gravity.VERTICAL_GRAVITY_MASK;
|
||||||
|
switch (gravity) {
|
||||||
|
case Gravity.TOP:
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
case Gravity.CENTER_VERTICAL:
|
||||||
|
return (bottom - top - zoomControlsHeight) / 2;
|
||||||
|
|
||||||
|
case Gravity.BOTTOM:
|
||||||
|
return bottom - top - zoomControlsHeight;
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new IllegalArgumentException("unknown vertical gravity: " + gravity);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void showZoomControls() {
|
||||||
|
mZoomControlsHideHandler.removeMessages(MSG_ZOOM_CONTROLS_HIDE);
|
||||||
|
if (mZoomControls.getVisibility() != View.VISIBLE) {
|
||||||
|
mZoomControls.show();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void showZoomControlsWithTimeout() {
|
||||||
|
showZoomControls();
|
||||||
|
mZoomControlsHideHandler.sendEmptyMessageDelayed(MSG_ZOOM_CONTROLS_HIDE, ZOOM_CONTROLS_TIMEOUT);
|
||||||
|
}
|
||||||
|
|
||||||
|
int getMeasuredHeight() {
|
||||||
|
return mZoomControls.getMeasuredHeight();
|
||||||
|
}
|
||||||
|
|
||||||
|
int getMeasuredWidth() {
|
||||||
|
return mZoomControls.getMeasuredWidth();
|
||||||
|
}
|
||||||
|
|
||||||
|
void measure(int widthMeasureSpec, int heightMeasureSpec) {
|
||||||
|
mZoomControls.measure(widthMeasureSpec, heightMeasureSpec);
|
||||||
|
}
|
||||||
|
|
||||||
|
void onLayout(boolean changed, int left, int top, int right, int bottom) {
|
||||||
|
if (!changed && !mGravityChanged) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int zoomControlsWidth = mZoomControls.getMeasuredWidth();
|
||||||
|
int zoomControlsHeight = mZoomControls.getMeasuredHeight();
|
||||||
|
|
||||||
|
int positionLeft = calculatePositionLeft(left, right, zoomControlsWidth);
|
||||||
|
int positionTop = calculatePositionTop(top, bottom, zoomControlsHeight);
|
||||||
|
int positionRight = positionLeft + zoomControlsWidth;
|
||||||
|
int positionBottom = positionTop + zoomControlsHeight;
|
||||||
|
|
||||||
|
mZoomControls.layout(positionLeft, positionTop, positionRight, positionBottom);
|
||||||
|
mGravityChanged = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void onMapViewTouchEvent(int action) {
|
||||||
|
if (mShowMapZoomControls) {
|
||||||
|
switch (action) {
|
||||||
|
case MotionEvent.ACTION_DOWN:
|
||||||
|
showZoomControls();
|
||||||
|
break;
|
||||||
|
case MotionEvent.ACTION_CANCEL:
|
||||||
|
showZoomControlsWithTimeout();
|
||||||
|
break;
|
||||||
|
case MotionEvent.ACTION_UP:
|
||||||
|
showZoomControlsWithTimeout();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void onZoomLevelChange(int zoomLevel) {
|
||||||
|
boolean zoomInEnabled = zoomLevel < mZoomLevelMax;
|
||||||
|
boolean zoomOutEnabled = zoomLevel > mZoomLevelMin;
|
||||||
|
|
||||||
|
mZoomControls.setIsZoomInEnabled(zoomInEnabled);
|
||||||
|
mZoomControls.setIsZoomOutEnabled(zoomOutEnabled);
|
||||||
|
}
|
||||||
|
}
|
||||||
91
src/org/mapsforge/android/Projection.java
Normal file
91
src/org/mapsforge/android/Projection.java
Normal file
@@ -0,0 +1,91 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010, 2011, 2012 mapsforge.org
|
||||||
|
*
|
||||||
|
* 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.mapsforge.android;
|
||||||
|
|
||||||
|
import org.mapsforge.core.GeoPoint;
|
||||||
|
|
||||||
|
import android.graphics.Point;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A Projection translates between the pixel coordinate system on the screen and geographical points on the earth. To
|
||||||
|
* retrieve the currently used Projection for a given MapView, call the {@link MapView#getProjection()} method.
|
||||||
|
*/
|
||||||
|
public interface Projection {
|
||||||
|
/**
|
||||||
|
* Translates the given screen coordinates to a {@link GeoPoint}. If the corresponding MapView has no valid
|
||||||
|
* dimensions (width and height > 0), null is returned.
|
||||||
|
*
|
||||||
|
* @param x
|
||||||
|
* the pixel x coordinate on the screen.
|
||||||
|
* @param y
|
||||||
|
* the pixel y coordinate on the screen.
|
||||||
|
* @return a new {@link GeoPoint} or null, if the corresponding MapView has no valid dimensions.
|
||||||
|
*/
|
||||||
|
GeoPoint fromPixels(int x, int y);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the latitude span from the top to the bottom of the map in microdegrees (degrees * 10^6).
|
||||||
|
* @throws IllegalStateException
|
||||||
|
* if the MapView dimensions are not valid (width and height > 0).
|
||||||
|
*/
|
||||||
|
int getLatitudeSpan();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the longitude span from the left to the right of the map in microdegrees (degrees * 10^6).
|
||||||
|
* @throws IllegalStateException
|
||||||
|
* if the MapView dimensions are not valid (width and height > 0).
|
||||||
|
*/
|
||||||
|
int getLongitudeSpan();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts the given distance in meters at the given zoom level to the corresponding number of horizontal pixels.
|
||||||
|
* The calculation is carried out at the current latitude coordinate.
|
||||||
|
*
|
||||||
|
* @param meters
|
||||||
|
* the distance in meters.
|
||||||
|
* @param zoomLevel
|
||||||
|
* the zoom level at which the distance should be calculated.
|
||||||
|
* @return the number of pixels at the current map position and the given zoom level.
|
||||||
|
*/
|
||||||
|
float metersToPixels(float meters, byte zoomLevel);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Translates the given {@link GeoPoint} to relative pixel coordinates on the screen. If the corresponding MapView
|
||||||
|
* has no valid dimensions (width and height > 0), null is returned.
|
||||||
|
*
|
||||||
|
* @param in
|
||||||
|
* the geographical point to convert.
|
||||||
|
* @param out
|
||||||
|
* an already existing object to use for the output. If this parameter is null, a new Point object will
|
||||||
|
* be created and returned.
|
||||||
|
* @return a Point which is relative to the top-left of the MapView or null, if the corresponding MapView has no
|
||||||
|
* valid dimensions.
|
||||||
|
*/
|
||||||
|
Point toPixels(GeoPoint in, Point out);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Translates the given {@link GeoPoint} to absolute pixel coordinates on the world map.
|
||||||
|
*
|
||||||
|
* @param in
|
||||||
|
* the geographical point to convert.
|
||||||
|
* @param out
|
||||||
|
* an already existing object to use for the output. If this parameter is null, a new Point object will
|
||||||
|
* be created and returned.
|
||||||
|
* @param zoomLevel
|
||||||
|
* the zoom level at which the point should be converted.
|
||||||
|
* @return a Point which is relative to the top-left of the world map.
|
||||||
|
*/
|
||||||
|
Point toPoint(GeoPoint in, Point out, byte zoomLevel);
|
||||||
|
}
|
||||||
491
src/org/mapsforge/android/glrenderer/DatabaseRenderer.java
Normal file
491
src/org/mapsforge/android/glrenderer/DatabaseRenderer.java
Normal file
@@ -0,0 +1,491 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2012 Hannes Janetzek
|
||||||
|
*
|
||||||
|
* 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.mapsforge.android.glrenderer;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
|
||||||
|
import javax.xml.parsers.ParserConfigurationException;
|
||||||
|
|
||||||
|
import org.mapsforge.android.MapView;
|
||||||
|
import org.mapsforge.android.mapgenerator.JobTheme;
|
||||||
|
import org.mapsforge.android.mapgenerator.MapGenerator;
|
||||||
|
import org.mapsforge.android.mapgenerator.MapGeneratorJob;
|
||||||
|
import org.mapsforge.android.rendertheme.RenderCallback;
|
||||||
|
import org.mapsforge.android.rendertheme.RenderTheme;
|
||||||
|
import org.mapsforge.android.rendertheme.RenderThemeHandler;
|
||||||
|
import org.mapsforge.android.rendertheme.renderinstruction.Area;
|
||||||
|
import org.mapsforge.android.rendertheme.renderinstruction.Line;
|
||||||
|
import org.mapsforge.core.GeoPoint;
|
||||||
|
import org.mapsforge.core.SphericalMercator;
|
||||||
|
import org.mapsforge.core.Tag;
|
||||||
|
import org.mapsforge.core.Tile;
|
||||||
|
import org.mapsforge.mapdatabase.IMapDatabase;
|
||||||
|
import org.mapsforge.mapdatabase.IMapDatabaseCallback;
|
||||||
|
import org.mapsforge.mapdatabase.MapFileInfo;
|
||||||
|
import org.xml.sax.SAXException;
|
||||||
|
|
||||||
|
import android.graphics.Bitmap;
|
||||||
|
import android.graphics.Color;
|
||||||
|
import android.graphics.Paint;
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class DatabaseRenderer implements MapGenerator, RenderCallback, IMapDatabaseCallback {
|
||||||
|
private static String TAG = DatabaseRenderer.class.getName();
|
||||||
|
|
||||||
|
private static final byte ZOOM_MAX = 22;
|
||||||
|
private static final Byte DEFAULT_START_ZOOM_LEVEL = Byte.valueOf((byte) 16);
|
||||||
|
private static final double PI180 = (Math.PI / 180) / 1000000.0;
|
||||||
|
private static final double PIx4 = Math.PI * 4;
|
||||||
|
private static final double STROKE_INCREASE = 1.5;
|
||||||
|
private static final byte STROKE_MIN_ZOOM_LEVEL = 12;
|
||||||
|
private static final byte LAYERS = 11;
|
||||||
|
|
||||||
|
private static RenderTheme renderTheme;
|
||||||
|
|
||||||
|
private IMapDatabase mMapDatabase;
|
||||||
|
|
||||||
|
private JobTheme mPreviousJobTheme;
|
||||||
|
// private float mPreviousTextScale;
|
||||||
|
private byte mPreviousZoomLevel;
|
||||||
|
|
||||||
|
private GLMapTile mCurrentTile;
|
||||||
|
|
||||||
|
private float[] mWayNodes;
|
||||||
|
private int[] mWays;
|
||||||
|
|
||||||
|
private ArrayList<float[]> mCurrentLines;
|
||||||
|
|
||||||
|
private LineLayers mLineLayers;
|
||||||
|
private PolygonLayers mPolyLayers;
|
||||||
|
|
||||||
|
private int mDrawingLayer;
|
||||||
|
private int mLevels;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public DatabaseRenderer() {
|
||||||
|
Log.d(TAG, "init DatabaseRenderer");
|
||||||
|
mCurrentLines = new ArrayList<float[]>();
|
||||||
|
|
||||||
|
LayerPool.init();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void renderPointOfInterest(byte layer, int latitude, int longitude, Tag[] tags) {
|
||||||
|
// TODO Auto-generated method stub
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void renderWaterBackground() {
|
||||||
|
// TODO Auto-generated method stub
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean mProjected;
|
||||||
|
private boolean mProjectedResult;
|
||||||
|
private float mSimplify;
|
||||||
|
private static final double f900913 = 20037508.342789244;
|
||||||
|
|
||||||
|
private boolean projectToTile(boolean area) {
|
||||||
|
if (mProjected)
|
||||||
|
return mProjectedResult;
|
||||||
|
|
||||||
|
float minx = Float.MAX_VALUE, miny = Float.MAX_VALUE, maxx = Float.MIN_VALUE, maxy = Float.MIN_VALUE;
|
||||||
|
|
||||||
|
float[] coords = mWayNodes;
|
||||||
|
|
||||||
|
long x = mCurrentTile.x;
|
||||||
|
long y = mCurrentTile.y;
|
||||||
|
long z = Tile.TILE_SIZE << mCurrentTile.zoomLevel;
|
||||||
|
float min = mSimplify;
|
||||||
|
|
||||||
|
double divx, divy;
|
||||||
|
long dx = (x - (z >> 1));
|
||||||
|
long dy = (y - (z >> 1));
|
||||||
|
|
||||||
|
if (!useSphericalMercator) {
|
||||||
|
divx = 180000000.0 / (z >> 1);
|
||||||
|
divy = z / PIx4;
|
||||||
|
} else {
|
||||||
|
divx = f900913 / (z >> 1);
|
||||||
|
divy = f900913 / (z >> 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int pos = 0, outPos = 0, i = 0, m = mWays.length; i < m; i++) {
|
||||||
|
int len = mWays[i];
|
||||||
|
int cnt = 0;
|
||||||
|
float lat, lon, prevLon = 0, prevLat = 0;
|
||||||
|
|
||||||
|
for (int end = pos + len; pos < end; pos += 2) {
|
||||||
|
|
||||||
|
if (useSphericalMercator) {
|
||||||
|
lon = (float) (coords[pos] / divx - dx);
|
||||||
|
lat = (float) (coords[pos + 1] / divy + dy);
|
||||||
|
} else {
|
||||||
|
lon = (float) ((coords[pos]) / divx - dx);
|
||||||
|
double sinLat = Math.sin(coords[pos + 1] * PI180);
|
||||||
|
lat = (float) (Math.log((1.0 + sinLat) / (1.0 - sinLat)) * divy + dy);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (area && i == 0) {
|
||||||
|
if (lon < minx)
|
||||||
|
minx = lon;
|
||||||
|
if (lon > maxx)
|
||||||
|
maxx = lon;
|
||||||
|
if (lat < miny)
|
||||||
|
miny = lat;
|
||||||
|
if (lat > maxy)
|
||||||
|
maxy = lat;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cnt != 0) {
|
||||||
|
// drop small distance intermediate nodes
|
||||||
|
|
||||||
|
if (lat == prevLat && lon == prevLon)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if ((pos != end - 2) &&
|
||||||
|
!((lat > prevLat + min || lat < prevLat - min) ||
|
||||||
|
(lon > prevLon + min || lon < prevLon - min)))
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
coords[outPos++] = prevLon = lon;
|
||||||
|
coords[outPos++] = prevLat = lat;
|
||||||
|
|
||||||
|
cnt += 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (area) {
|
||||||
|
// Log.d(TAG, "area:" + (maxx - minx) * (maxy - miny));
|
||||||
|
if ((maxx - minx) * (maxy - miny) < 2000 / mCurrentTile.zoomLevel) {
|
||||||
|
mProjected = true;
|
||||||
|
mProjectedResult = false;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mWays[i] = cnt;
|
||||||
|
}
|
||||||
|
mProjected = true;
|
||||||
|
mProjectedResult = true;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean firstMatch;
|
||||||
|
private boolean prevClosed;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void renderWay(byte layer, Tag[] tags, float[] wayNodes, int[] wayLength, boolean changed) {
|
||||||
|
|
||||||
|
mProjected = false;
|
||||||
|
mDrawingLayer = getValidLayer(layer) * mLevels;
|
||||||
|
|
||||||
|
int len = wayLength[0];
|
||||||
|
boolean closed = (wayNodes[0] == wayNodes[len - 2] &&
|
||||||
|
wayNodes[1] == wayNodes[len - 1]);
|
||||||
|
|
||||||
|
mSimplify = 2.5f;
|
||||||
|
|
||||||
|
if (closed) {
|
||||||
|
if (mCurrentTile.zoomLevel < 14)
|
||||||
|
mSimplify = 1.5f;
|
||||||
|
else
|
||||||
|
mSimplify = 0.5f;
|
||||||
|
|
||||||
|
if (tags.length == 1 && "water".equals(tags[0].value))
|
||||||
|
mSimplify = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
mCurrentLines.clear();
|
||||||
|
mWayNodes = wayNodes;
|
||||||
|
mWays = wayLength;
|
||||||
|
|
||||||
|
if (!firstMatch && prevClosed == closed && !changed) {
|
||||||
|
DatabaseRenderer.renderTheme.matchWay(this, tags, mCurrentTile.zoomLevel, closed, false);
|
||||||
|
} else {
|
||||||
|
prevClosed = closed;
|
||||||
|
DatabaseRenderer.renderTheme.matchWay(this, tags, mCurrentTile.zoomLevel, closed, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
firstMatch = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void renderAreaCaption(String caption, float verticalOffset, Paint paint, Paint stroke) {
|
||||||
|
// TODO Auto-generated method stub
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void renderAreaSymbol(Bitmap symbol) {
|
||||||
|
// TODO Auto-generated method stub
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void renderPointOfInterestCaption(String caption, float verticalOffset, Paint paint, Paint stroke) {
|
||||||
|
// TODO Auto-generated method stub
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void renderPointOfInterestCircle(float radius, Paint fill, int level) {
|
||||||
|
// TODO Auto-generated method stub
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void renderPointOfInterestSymbol(Bitmap symbol) {
|
||||||
|
// TODO Auto-generated method stub
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void renderWay(Line line) {
|
||||||
|
|
||||||
|
projectToTile(false);
|
||||||
|
|
||||||
|
LineLayer outlineLayer = null;
|
||||||
|
LineLayer l = mLineLayers.getLayer(mDrawingLayer + line.level, line.color, false, line.fixed);
|
||||||
|
|
||||||
|
float w = line.strokeWidth;
|
||||||
|
|
||||||
|
if (!line.fixed)
|
||||||
|
w *= mStrokeScale / 1.5f;
|
||||||
|
|
||||||
|
if (line.outline != -1) {
|
||||||
|
Line outline = DatabaseRenderer.renderTheme.getOutline(line.outline);
|
||||||
|
if (outline != null) {
|
||||||
|
outlineLayer = mLineLayers.getLayer(mDrawingLayer + outline.level, outline.color, true, false);
|
||||||
|
outlineLayer.addOutline(l);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0, pos = 0, n = mWays.length; i < n; i++) {
|
||||||
|
int length = mWays[i];
|
||||||
|
|
||||||
|
// need at least two points
|
||||||
|
if (length >= 4)
|
||||||
|
l.addLine(mWayNodes, pos, length, w, line.round);
|
||||||
|
|
||||||
|
pos += length;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void renderArea(Area area) {
|
||||||
|
if (!mDebugDrawPolygons)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// if (!projectToTile(mCurrentTile.zoomLevel < 13))
|
||||||
|
if (!projectToTile(false))
|
||||||
|
return;
|
||||||
|
|
||||||
|
PolygonLayer l = mPolyLayers.getLayer(mDrawingLayer + area.level, area.color, area.fade);
|
||||||
|
|
||||||
|
for (int i = 0, pos = 0, n = mWays.length; i < n; i++) {
|
||||||
|
int length = mWays[i];
|
||||||
|
// need at least three points
|
||||||
|
if (length >= 6)
|
||||||
|
l.addPolygon(mWayNodes, pos, length);
|
||||||
|
|
||||||
|
pos += length;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void renderWaySymbol(Bitmap symbol, boolean alignCenter, boolean repeat) {
|
||||||
|
// TODO Auto-generated method stub
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void renderWayText(String text, Paint paint, Paint stroke) {
|
||||||
|
// TODO Auto-generated method stub
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void cleanup() {
|
||||||
|
// TODO Auto-generated method stub
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean mDebugDrawPolygons;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean executeJob(MapGeneratorJob mapGeneratorJob) {
|
||||||
|
// Log.d(TAG, "load " + mCurrentTile);
|
||||||
|
|
||||||
|
if (!(mapGeneratorJob.tile instanceof GLMapTile))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (mMapDatabase == null)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
mCurrentTile = (GLMapTile) mapGeneratorJob.tile;
|
||||||
|
mDebugDrawPolygons = !mapGeneratorJob.debugSettings.mDisablePolygons;
|
||||||
|
|
||||||
|
// FIXME still chance of concurrency with maprenderer updateVisibleList ?
|
||||||
|
if (mCurrentTile.isLoading || mCurrentTile.isDrawn)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
mCurrentTile.isLoading = true;
|
||||||
|
|
||||||
|
JobTheme jobTheme = mapGeneratorJob.jobParameters.jobTheme;
|
||||||
|
|
||||||
|
if (jobTheme != mPreviousJobTheme) {
|
||||||
|
if (!setRenderTheme(jobTheme)) {
|
||||||
|
mPreviousJobTheme = null;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
mPreviousJobTheme = jobTheme;
|
||||||
|
mPreviousZoomLevel = Byte.MIN_VALUE;
|
||||||
|
mLevels = DatabaseRenderer.renderTheme.getLevels();
|
||||||
|
}
|
||||||
|
|
||||||
|
byte zoomLevel = mCurrentTile.zoomLevel;
|
||||||
|
if (zoomLevel != mPreviousZoomLevel) {
|
||||||
|
setScaleStrokeWidth(zoomLevel);
|
||||||
|
mPreviousZoomLevel = zoomLevel;
|
||||||
|
}
|
||||||
|
|
||||||
|
mLineLayers = new LineLayers();
|
||||||
|
mPolyLayers = new PolygonLayers();
|
||||||
|
mCurrentTile.lineLayers = mLineLayers;
|
||||||
|
mCurrentTile.polygonLayers = mPolyLayers;
|
||||||
|
|
||||||
|
firstMatch = true;
|
||||||
|
mMapDatabase.executeQuery(mCurrentTile, this);
|
||||||
|
|
||||||
|
// Log.d(TAG, "loaded " + mCurrentTile);
|
||||||
|
|
||||||
|
if (mapGeneratorJob.debugSettings.mDrawTileFrames) {
|
||||||
|
float[] coords = { 0, 0, 0, Tile.TILE_SIZE, Tile.TILE_SIZE, Tile.TILE_SIZE, Tile.TILE_SIZE, 0, 0, 0 };
|
||||||
|
LineLayer ll = mLineLayers.getLayer(Integer.MAX_VALUE, Color.BLACK, false, true);
|
||||||
|
ll.addLine(coords, 0, coords.length, 1.0f, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
mCurrentTile.newData = true;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public GeoPoint getStartPoint() {
|
||||||
|
useSphericalMercator = false;
|
||||||
|
|
||||||
|
if (mMapDatabase != null && mMapDatabase.hasOpenFile()) {
|
||||||
|
MapFileInfo mapFileInfo = mMapDatabase.getMapFileInfo();
|
||||||
|
|
||||||
|
if (SphericalMercator.NAME.equals(mapFileInfo.projectionName)) {
|
||||||
|
Log.d(TAG, "using Spherical Mercator");
|
||||||
|
|
||||||
|
useSphericalMercator = true;
|
||||||
|
}
|
||||||
|
if (mapFileInfo.startPosition != null) {
|
||||||
|
return mapFileInfo.startPosition;
|
||||||
|
} else if (mapFileInfo.mapCenter != null) {
|
||||||
|
return mapFileInfo.mapCenter;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Byte getStartZoomLevel() {
|
||||||
|
return DEFAULT_START_ZOOM_LEVEL;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public byte getZoomLevelMax() {
|
||||||
|
return ZOOM_MAX;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean requiresInternetConnection() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean setRenderTheme(JobTheme jobTheme) {
|
||||||
|
InputStream inputStream = null;
|
||||||
|
try {
|
||||||
|
inputStream = jobTheme.getRenderThemeAsStream();
|
||||||
|
DatabaseRenderer.renderTheme = RenderThemeHandler.getRenderTheme(inputStream);
|
||||||
|
return true;
|
||||||
|
} catch (ParserConfigurationException e) {
|
||||||
|
Log.e(TAG, e.getMessage());
|
||||||
|
} catch (SAXException e) {
|
||||||
|
Log.e(TAG, e.getMessage());
|
||||||
|
} catch (IOException e) {
|
||||||
|
Log.e(TAG, e.getMessage());
|
||||||
|
} finally {
|
||||||
|
try {
|
||||||
|
if (inputStream != null) {
|
||||||
|
inputStream.close();
|
||||||
|
}
|
||||||
|
} catch (IOException e) {
|
||||||
|
Log.e(TAG, e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static byte getValidLayer(byte layer) {
|
||||||
|
if (layer < 0) {
|
||||||
|
return 0;
|
||||||
|
} else if (layer >= LAYERS) {
|
||||||
|
return LAYERS - 1;
|
||||||
|
} else {
|
||||||
|
return layer;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public MapRenderer getMapRenderer(MapView mapView) {
|
||||||
|
return new MapRenderer(mapView);
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean useSphericalMercator = false;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setMapDatabase(IMapDatabase mapDatabase) {
|
||||||
|
mMapDatabase = mapDatabase;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static float mStrokeScale = 1.0f;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the scale stroke factor for the given zoom level.
|
||||||
|
*
|
||||||
|
* @param zoomLevel
|
||||||
|
* the zoom level for which the scale stroke factor should be set.
|
||||||
|
*/
|
||||||
|
private static void setScaleStrokeWidth(byte zoomLevel) {
|
||||||
|
int zoomLevelDiff = Math.max(zoomLevel - STROKE_MIN_ZOOM_LEVEL, 0);
|
||||||
|
mStrokeScale = (float) Math.pow(STROKE_INCREASE, zoomLevelDiff);
|
||||||
|
if (mStrokeScale < 1)
|
||||||
|
mStrokeScale = 1;
|
||||||
|
// DatabaseRenderer.renderTheme.scaleStrokeWidth(mStrokeScale);
|
||||||
|
}
|
||||||
|
}
|
||||||
48
src/org/mapsforge/android/glrenderer/GLMapTile.java
Normal file
48
src/org/mapsforge/android/glrenderer/GLMapTile.java
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2012 Hannes Janetzek
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify it under the
|
||||||
|
* terms of the GNU Lesser General 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 License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General License along with
|
||||||
|
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
package org.mapsforge.android.glrenderer;
|
||||||
|
|
||||||
|
import org.mapsforge.android.mapgenerator.MapTile;
|
||||||
|
import org.mapsforge.core.Tile;
|
||||||
|
|
||||||
|
class GLMapTile extends MapTile {
|
||||||
|
|
||||||
|
VertexBufferObject lineVBO;
|
||||||
|
VertexBufferObject polygonVBO;
|
||||||
|
|
||||||
|
LineLayers lineLayers;
|
||||||
|
PolygonLayers polygonLayers;
|
||||||
|
|
||||||
|
boolean newData;
|
||||||
|
boolean loading;
|
||||||
|
|
||||||
|
// pixel coordinates (y-flipped)
|
||||||
|
final long x;
|
||||||
|
final long y;
|
||||||
|
|
||||||
|
// scissor coordinates
|
||||||
|
int sx, sy, sw, sh;
|
||||||
|
|
||||||
|
final GLMapTile[] child = { null, null, null, null };
|
||||||
|
GLMapTile parent;
|
||||||
|
|
||||||
|
GLMapTile(long tileX, long tileY, byte zoomLevel) {
|
||||||
|
super(tileX, tileY, zoomLevel);
|
||||||
|
|
||||||
|
x = pixelX;
|
||||||
|
y = pixelY + Tile.TILE_SIZE;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
41
src/org/mapsforge/android/glrenderer/Layer.java
Normal file
41
src/org/mapsforge/android/glrenderer/Layer.java
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2012 Hannes Janetzek
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify it under the
|
||||||
|
* terms of the GNU Lesser General 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 License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General License along with
|
||||||
|
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
package org.mapsforge.android.glrenderer;
|
||||||
|
|
||||||
|
import java.util.LinkedList;
|
||||||
|
|
||||||
|
class Layer {
|
||||||
|
LinkedList<PoolItem> pool;
|
||||||
|
protected PoolItem curItem;
|
||||||
|
|
||||||
|
int verticesCnt;
|
||||||
|
int offset;
|
||||||
|
|
||||||
|
final int layer;
|
||||||
|
final int color;
|
||||||
|
|
||||||
|
Layer(int l, int c) {
|
||||||
|
color = c;
|
||||||
|
layer = l;
|
||||||
|
verticesCnt = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
float[] getNextItem() {
|
||||||
|
curItem.used = PoolItem.SIZE;
|
||||||
|
curItem = LayerPool.get();
|
||||||
|
pool.add(curItem);
|
||||||
|
return curItem.vertices;
|
||||||
|
}
|
||||||
|
}
|
||||||
52
src/org/mapsforge/android/glrenderer/LayerPool.java
Normal file
52
src/org/mapsforge/android/glrenderer/LayerPool.java
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2012 Hannes Janetzek
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify it under the
|
||||||
|
* terms of the GNU Lesser General 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 License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General License along with
|
||||||
|
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.mapsforge.android.glrenderer;
|
||||||
|
|
||||||
|
import java.util.LinkedList;
|
||||||
|
|
||||||
|
class LayerPool {
|
||||||
|
static private LinkedList<PoolItem> pool;
|
||||||
|
static private int count;
|
||||||
|
|
||||||
|
static void init() {
|
||||||
|
pool = new LinkedList<PoolItem>();
|
||||||
|
count = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static PoolItem get() {
|
||||||
|
if (count == 0)
|
||||||
|
return new PoolItem();
|
||||||
|
|
||||||
|
PoolItem it;
|
||||||
|
synchronized (pool) {
|
||||||
|
count--;
|
||||||
|
it = pool.pop();
|
||||||
|
it.used = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return it;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void add(LinkedList<PoolItem> items) {
|
||||||
|
int size = items.size();
|
||||||
|
synchronized (pool) {
|
||||||
|
while (count < 4096 && size-- > 0) {
|
||||||
|
count++;
|
||||||
|
pool.add(items.pop());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
397
src/org/mapsforge/android/glrenderer/LineLayer.java
Normal file
397
src/org/mapsforge/android/glrenderer/LineLayer.java
Normal file
@@ -0,0 +1,397 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2012 Hannes Janetzek
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify it under the
|
||||||
|
* terms of the GNU Lesser General 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 License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General License along with
|
||||||
|
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
package org.mapsforge.android.glrenderer;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.LinkedList;
|
||||||
|
|
||||||
|
import org.mapsforge.core.Tile;
|
||||||
|
|
||||||
|
class LineLayer extends Layer {
|
||||||
|
ArrayList<LineLayer> outlines;
|
||||||
|
float[] colors;
|
||||||
|
boolean isOutline;
|
||||||
|
boolean isFixed;
|
||||||
|
float width;
|
||||||
|
|
||||||
|
LineLayer(int layer, int color, boolean outline, boolean fixed) {
|
||||||
|
super(layer, color);
|
||||||
|
isOutline = outline;
|
||||||
|
isFixed = fixed;
|
||||||
|
if (outline) {
|
||||||
|
outlines = new ArrayList<LineLayer>();
|
||||||
|
} else {
|
||||||
|
curItem = LayerPool.get();
|
||||||
|
|
||||||
|
pool = new LinkedList<PoolItem>();
|
||||||
|
pool.add(curItem);
|
||||||
|
}
|
||||||
|
|
||||||
|
colors = new float[4];
|
||||||
|
|
||||||
|
float a = (color >> 24 & 0xff) / 255.0f;
|
||||||
|
|
||||||
|
colors[0] = (color >> 16 & 0xff) / 255.0f * a;
|
||||||
|
colors[1] = (color >> 8 & 0xff) / 255.0f * a;
|
||||||
|
colors[2] = (color >> 0 & 0xff) / 255.0f * a;
|
||||||
|
colors[3] = a;
|
||||||
|
}
|
||||||
|
|
||||||
|
void addOutline(LineLayer link) {
|
||||||
|
if (!outlines.contains(link))
|
||||||
|
outlines.add(link);
|
||||||
|
}
|
||||||
|
|
||||||
|
// private void addVertex(float x, float y, byte tex, byte[] c){
|
||||||
|
// //
|
||||||
|
// }
|
||||||
|
|
||||||
|
void addLine(float[] pointArray, int pos, int length, float w, boolean capRound) {
|
||||||
|
float x, y, nextX, nextY, prevX, prevY, ux, uy, vx, vy, wx, wy;
|
||||||
|
double a;
|
||||||
|
int pointPos = pos;
|
||||||
|
boolean rounded = capRound;
|
||||||
|
width = w;
|
||||||
|
if (w < 0.5)
|
||||||
|
rounded = false;
|
||||||
|
|
||||||
|
// amount of vertices used
|
||||||
|
verticesCnt += length + (rounded ? 6 : 2);
|
||||||
|
|
||||||
|
float[] curVertices = curItem.vertices;
|
||||||
|
int vertexPos = curItem.used;
|
||||||
|
|
||||||
|
if (vertexPos == PoolItem.SIZE) {
|
||||||
|
curVertices = getNextItem();
|
||||||
|
vertexPos = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
x = pointArray[pointPos++];
|
||||||
|
y = pointArray[pointPos++];
|
||||||
|
|
||||||
|
nextX = pointArray[pointPos++];
|
||||||
|
nextY = pointArray[pointPos++];
|
||||||
|
|
||||||
|
// Calculate triangle corners for the given width
|
||||||
|
vx = nextX - x;
|
||||||
|
vy = nextY - y;
|
||||||
|
|
||||||
|
a = Math.sqrt(vx * vx + vy * vy);
|
||||||
|
|
||||||
|
vx = (float) (vx / a);
|
||||||
|
vy = (float) (vy / a);
|
||||||
|
|
||||||
|
ux = -vy;
|
||||||
|
uy = vx;
|
||||||
|
|
||||||
|
float uxw = ux * w;
|
||||||
|
float uyw = uy * w;
|
||||||
|
|
||||||
|
float vxw = vx * w;
|
||||||
|
float vyw = vy * w;
|
||||||
|
|
||||||
|
boolean outside = (x <= 0 || x >= Tile.TILE_SIZE || y <= 0 || y >= Tile.TILE_SIZE)
|
||||||
|
&& (x - vxw <= 0 || x - vxw >= Tile.TILE_SIZE || y - vyw <= 0 || y - vyw >= Tile.TILE_SIZE);
|
||||||
|
|
||||||
|
if (rounded && !outside) {
|
||||||
|
|
||||||
|
// Add the first point twice to be able to draw with GL_TRIANGLE_STRIP
|
||||||
|
|
||||||
|
curVertices[vertexPos++] = x + uxw - vxw;
|
||||||
|
curVertices[vertexPos++] = y + uyw - vyw;
|
||||||
|
curVertices[vertexPos++] = -1.0f;
|
||||||
|
curVertices[vertexPos++] = 1.0f;
|
||||||
|
|
||||||
|
if (vertexPos == PoolItem.SIZE) {
|
||||||
|
curVertices = getNextItem();
|
||||||
|
vertexPos = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
curVertices[vertexPos++] = x + uxw - vxw;
|
||||||
|
curVertices[vertexPos++] = y + uyw - vyw;
|
||||||
|
curVertices[vertexPos++] = -1.0f;
|
||||||
|
curVertices[vertexPos++] = 1.0f;
|
||||||
|
|
||||||
|
if (vertexPos == PoolItem.SIZE) {
|
||||||
|
curVertices = getNextItem();
|
||||||
|
vertexPos = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
curVertices[vertexPos++] = x - uxw - vxw;
|
||||||
|
curVertices[vertexPos++] = y - uyw - vyw;
|
||||||
|
curVertices[vertexPos++] = 1.0f;
|
||||||
|
curVertices[vertexPos++] = 1.0f;
|
||||||
|
|
||||||
|
if (vertexPos == PoolItem.SIZE) {
|
||||||
|
curVertices = getNextItem();
|
||||||
|
vertexPos = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Start of line
|
||||||
|
curVertices[vertexPos++] = x + uxw;
|
||||||
|
curVertices[vertexPos++] = y + uyw;
|
||||||
|
curVertices[vertexPos++] = -1.0f;
|
||||||
|
curVertices[vertexPos++] = 0.0f;
|
||||||
|
|
||||||
|
if (vertexPos == PoolItem.SIZE) {
|
||||||
|
curVertices = getNextItem();
|
||||||
|
vertexPos = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
curVertices[vertexPos++] = x - uxw;
|
||||||
|
curVertices[vertexPos++] = y - uyw;
|
||||||
|
curVertices[vertexPos++] = 1.0f;
|
||||||
|
curVertices[vertexPos++] = 0.0f;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
// outside means line is probably clipped
|
||||||
|
// TODO should align ending with tile boundary
|
||||||
|
// for now, just extend the line a little
|
||||||
|
if (!outside) {
|
||||||
|
vxw *= 0.5;
|
||||||
|
vyw *= 0.5;
|
||||||
|
}
|
||||||
|
if (rounded) {
|
||||||
|
verticesCnt -= 2;
|
||||||
|
}
|
||||||
|
// Add the first point twice to be able to draw with GL_TRIANGLE_STRIP
|
||||||
|
curVertices[vertexPos++] = x + uxw - vxw;
|
||||||
|
curVertices[vertexPos++] = y + uyw - vyw;
|
||||||
|
curVertices[vertexPos++] = -1.0f;
|
||||||
|
curVertices[vertexPos++] = 0.0f;
|
||||||
|
|
||||||
|
if (vertexPos == PoolItem.SIZE) {
|
||||||
|
curVertices = getNextItem();
|
||||||
|
vertexPos = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
curVertices[vertexPos++] = x + uxw - vxw;
|
||||||
|
curVertices[vertexPos++] = y + uyw - vyw;
|
||||||
|
curVertices[vertexPos++] = -1.0f;
|
||||||
|
curVertices[vertexPos++] = 0.0f;
|
||||||
|
|
||||||
|
if (vertexPos == PoolItem.SIZE) {
|
||||||
|
curVertices = getNextItem();
|
||||||
|
vertexPos = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
curVertices[vertexPos++] = x - uxw - vxw;
|
||||||
|
curVertices[vertexPos++] = y - uyw - vyw;
|
||||||
|
curVertices[vertexPos++] = 1.0f;
|
||||||
|
curVertices[vertexPos++] = 0.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
prevX = x;
|
||||||
|
prevY = y;
|
||||||
|
x = nextX;
|
||||||
|
y = nextY;
|
||||||
|
// boolean flipped = false;
|
||||||
|
|
||||||
|
for (; pointPos < pos + length;) {
|
||||||
|
nextX = pointArray[pointPos++];
|
||||||
|
nextY = pointArray[pointPos++];
|
||||||
|
|
||||||
|
// Unit vector pointing back to previous node
|
||||||
|
vx = prevX - x;
|
||||||
|
vy = prevY - y;
|
||||||
|
a = Math.sqrt(vx * vx + vy * vy);
|
||||||
|
vx = (float) (vx / a);
|
||||||
|
vy = (float) (vy / a);
|
||||||
|
|
||||||
|
// Unit vector pointing forward to next node
|
||||||
|
wx = nextX - x;
|
||||||
|
wy = nextY - y;
|
||||||
|
a = Math.sqrt(wx * wx + wy * wy);
|
||||||
|
wx = (float) (wx / a);
|
||||||
|
wy = (float) (wy / a);
|
||||||
|
|
||||||
|
// Sum of these two vectors points
|
||||||
|
ux = vx + wx;
|
||||||
|
uy = vy + wy;
|
||||||
|
a = -wy * ux + wx * uy;
|
||||||
|
|
||||||
|
if ((a < 0.1 && a > -0.1)) {
|
||||||
|
// Almost straight, use normal vector
|
||||||
|
ux = -wy;
|
||||||
|
uy = wx;
|
||||||
|
} else {
|
||||||
|
ux = (float) (ux / a);
|
||||||
|
uy = (float) (uy / a);
|
||||||
|
|
||||||
|
if (ux > 2 || uy > 2 || ux < -2 || uy < -2) {
|
||||||
|
ux = -wy;
|
||||||
|
uy = wx;
|
||||||
|
|
||||||
|
// ux = vx + wx;
|
||||||
|
// uy = vy + wy;
|
||||||
|
// // Normalize u, and project normal vector onto this
|
||||||
|
// double c = Math.sqrt(ux * ux + uy * uy);
|
||||||
|
// if (a < 0) {
|
||||||
|
// ux = (float) -(ux / c);
|
||||||
|
// uy = (float) -(uy / c);
|
||||||
|
// }
|
||||||
|
// else {
|
||||||
|
// ux = (float) (ux / c);
|
||||||
|
// uy = (float) (uy / c);
|
||||||
|
// }
|
||||||
|
// flipped = flipped ? false : true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uxw = ux * w;
|
||||||
|
uyw = uy * w;
|
||||||
|
|
||||||
|
if (vertexPos == PoolItem.SIZE) {
|
||||||
|
curVertices = getNextItem();
|
||||||
|
vertexPos = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
curVertices[vertexPos++] = x + uxw;
|
||||||
|
curVertices[vertexPos++] = y + uyw;
|
||||||
|
curVertices[vertexPos++] = -1.0f;
|
||||||
|
curVertices[vertexPos++] = 0.0f;
|
||||||
|
|
||||||
|
if (vertexPos == PoolItem.SIZE) {
|
||||||
|
curVertices = getNextItem();
|
||||||
|
vertexPos = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
curVertices[vertexPos++] = x - uxw;
|
||||||
|
curVertices[vertexPos++] = y - uyw;
|
||||||
|
curVertices[vertexPos++] = 1.0f;
|
||||||
|
curVertices[vertexPos++] = 0.0f;
|
||||||
|
|
||||||
|
prevX = x;
|
||||||
|
prevY = y;
|
||||||
|
x = nextX;
|
||||||
|
y = nextY;
|
||||||
|
}
|
||||||
|
|
||||||
|
vx = prevX - x;
|
||||||
|
vy = prevY - y;
|
||||||
|
|
||||||
|
a = Math.sqrt(vx * vx + vy * vy);
|
||||||
|
|
||||||
|
vx = (float) (vx / a);
|
||||||
|
vy = (float) (vy / a);
|
||||||
|
|
||||||
|
ux = vy;
|
||||||
|
uy = -vx;
|
||||||
|
|
||||||
|
uxw = ux * w;
|
||||||
|
uyw = uy * w;
|
||||||
|
|
||||||
|
vxw = vx * w;
|
||||||
|
vyw = vy * w;
|
||||||
|
|
||||||
|
outside = (x <= 0 || x >= Tile.TILE_SIZE || y <= 0 || y >= Tile.TILE_SIZE)
|
||||||
|
&& (x - vxw <= 0 || x - vxw >= Tile.TILE_SIZE || y - vyw <= 0 || y - vyw >= Tile.TILE_SIZE);
|
||||||
|
|
||||||
|
if (vertexPos == PoolItem.SIZE) {
|
||||||
|
curItem.used = vertexPos;
|
||||||
|
curItem = LayerPool.get();
|
||||||
|
pool.add(curItem);
|
||||||
|
curVertices = curItem.vertices;
|
||||||
|
vertexPos = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rounded && !outside) {
|
||||||
|
curVertices[vertexPos++] = x + uxw;
|
||||||
|
curVertices[vertexPos++] = y + uyw;
|
||||||
|
curVertices[vertexPos++] = -1.0f;
|
||||||
|
curVertices[vertexPos++] = 0.0f;
|
||||||
|
|
||||||
|
if (vertexPos == PoolItem.SIZE) {
|
||||||
|
curVertices = getNextItem();
|
||||||
|
vertexPos = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
curVertices[vertexPos++] = x - uxw;
|
||||||
|
curVertices[vertexPos++] = y - uyw;
|
||||||
|
curVertices[vertexPos++] = 1.0f;
|
||||||
|
curVertices[vertexPos++] = 0.0f;
|
||||||
|
|
||||||
|
if (vertexPos == PoolItem.SIZE) {
|
||||||
|
curVertices = getNextItem();
|
||||||
|
vertexPos = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// For rounded line edges
|
||||||
|
curVertices[vertexPos++] = x + uxw - vxw;
|
||||||
|
curVertices[vertexPos++] = y + uyw - vyw;
|
||||||
|
curVertices[vertexPos++] = -1.0f;
|
||||||
|
curVertices[vertexPos++] = -1.0f;
|
||||||
|
|
||||||
|
if (vertexPos == PoolItem.SIZE) {
|
||||||
|
curVertices = getNextItem();
|
||||||
|
vertexPos = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add the last vertex twice to be able to draw with GL_TRIANGLE_STRIP
|
||||||
|
curVertices[vertexPos++] = x - uxw - vxw;
|
||||||
|
curVertices[vertexPos++] = y - uyw - vyw;
|
||||||
|
curVertices[vertexPos++] = 1.0f;
|
||||||
|
curVertices[vertexPos++] = -1.0f;
|
||||||
|
|
||||||
|
if (vertexPos == PoolItem.SIZE) {
|
||||||
|
curVertices = getNextItem();
|
||||||
|
vertexPos = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
curVertices[vertexPos++] = x - uxw - vxw;
|
||||||
|
curVertices[vertexPos++] = y - uyw - vyw;
|
||||||
|
curVertices[vertexPos++] = 1.0f;
|
||||||
|
curVertices[vertexPos++] = -1.0f;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
if (!outside) {
|
||||||
|
vxw *= 0.5;
|
||||||
|
vyw *= 0.5;
|
||||||
|
}
|
||||||
|
if (rounded) {
|
||||||
|
verticesCnt -= 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
curVertices[vertexPos++] = x + uxw;
|
||||||
|
curVertices[vertexPos++] = y + uyw;
|
||||||
|
curVertices[vertexPos++] = -1.0f;
|
||||||
|
curVertices[vertexPos++] = 0.0f;
|
||||||
|
|
||||||
|
if (vertexPos == PoolItem.SIZE) {
|
||||||
|
curVertices = getNextItem();
|
||||||
|
vertexPos = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add the last vertex twice to be able to draw with GL_TRIANGLE_STRIP
|
||||||
|
curVertices[vertexPos++] = x - uxw - vxw;
|
||||||
|
curVertices[vertexPos++] = y - uyw - vyw;
|
||||||
|
curVertices[vertexPos++] = 1.0f;
|
||||||
|
curVertices[vertexPos++] = 0.0f;
|
||||||
|
|
||||||
|
if (vertexPos == PoolItem.SIZE) {
|
||||||
|
curVertices = getNextItem();
|
||||||
|
vertexPos = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
curVertices[vertexPos++] = x - uxw - vxw;
|
||||||
|
curVertices[vertexPos++] = y - uyw - vyw;
|
||||||
|
curVertices[vertexPos++] = 1.0f;
|
||||||
|
curVertices[vertexPos++] = 0.0f;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
curItem.used = vertexPos;
|
||||||
|
}
|
||||||
|
}
|
||||||
135
src/org/mapsforge/android/glrenderer/LineLayers.java
Normal file
135
src/org/mapsforge/android/glrenderer/LineLayers.java
Normal file
@@ -0,0 +1,135 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2012 Hannes Janetzek
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify it under the
|
||||||
|
* terms of the GNU Lesser General 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 License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General License along with
|
||||||
|
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
package org.mapsforge.android.glrenderer;
|
||||||
|
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
import java.nio.ByteOrder;
|
||||||
|
import java.nio.FloatBuffer;
|
||||||
|
|
||||||
|
import android.util.SparseArray;
|
||||||
|
|
||||||
|
class LineLayers {
|
||||||
|
private static int NUM_VERTEX_FLOATS = 4;
|
||||||
|
|
||||||
|
private SparseArray<LineLayer> layers;
|
||||||
|
|
||||||
|
LineLayer[] array = null;
|
||||||
|
int size = 0;
|
||||||
|
|
||||||
|
LineLayers() {
|
||||||
|
layers = new SparseArray<LineLayer>(10);
|
||||||
|
}
|
||||||
|
|
||||||
|
LineLayer getLayer(int layer, int color, boolean outline, boolean fixed) {
|
||||||
|
LineLayer l = layers.get(layer);
|
||||||
|
if (l != null) {
|
||||||
|
return l;
|
||||||
|
}
|
||||||
|
|
||||||
|
l = new LineLayer(layer, color, outline, fixed);
|
||||||
|
layers.put(layer, l);
|
||||||
|
|
||||||
|
return l;
|
||||||
|
}
|
||||||
|
|
||||||
|
FloatBuffer compileLayerData(FloatBuffer buf) {
|
||||||
|
FloatBuffer fbuf = buf;
|
||||||
|
|
||||||
|
array = new LineLayer[layers.size()];
|
||||||
|
|
||||||
|
for (int i = 0, n = layers.size(); i < n; i++) {
|
||||||
|
LineLayer l = layers.valueAt(i);
|
||||||
|
array[i] = l;
|
||||||
|
size += l.verticesCnt * NUM_VERTEX_FLOATS;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (buf == null || buf.capacity() < size) {
|
||||||
|
ByteBuffer bbuf = ByteBuffer.allocateDirect(size * 4).order(ByteOrder.nativeOrder());
|
||||||
|
fbuf = bbuf.asFloatBuffer();
|
||||||
|
} else {
|
||||||
|
fbuf.position(0);
|
||||||
|
}
|
||||||
|
int pos = 0;
|
||||||
|
|
||||||
|
for (int i = 0, n = array.length; i < n; i++) {
|
||||||
|
LineLayer l = array[i];
|
||||||
|
if (l.isOutline)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
for (PoolItem item : l.pool) {
|
||||||
|
fbuf.put(item.vertices, 0, item.used);
|
||||||
|
}
|
||||||
|
|
||||||
|
l.offset = pos;
|
||||||
|
pos += l.verticesCnt;
|
||||||
|
|
||||||
|
LayerPool.add(l.pool);
|
||||||
|
l.pool = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
fbuf.position(0);
|
||||||
|
|
||||||
|
// not needed for drawing
|
||||||
|
layers = null;
|
||||||
|
|
||||||
|
return fbuf;
|
||||||
|
}
|
||||||
|
|
||||||
|
ByteBuffer compileLayerData(ByteBuffer buf) {
|
||||||
|
ByteBuffer sbuf = buf;
|
||||||
|
|
||||||
|
array = new LineLayer[layers.size()];
|
||||||
|
|
||||||
|
for (int i = 0, n = layers.size(); i < n; i++) {
|
||||||
|
LineLayer l = layers.valueAt(i);
|
||||||
|
array[i] = l;
|
||||||
|
size += l.verticesCnt * NUM_VERTEX_FLOATS;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (buf == null || buf.capacity() < size * 2) {
|
||||||
|
sbuf = ByteBuffer.allocateDirect(size * 2).order(ByteOrder.nativeOrder());
|
||||||
|
} else {
|
||||||
|
sbuf.position(0);
|
||||||
|
}
|
||||||
|
int pos = 0;
|
||||||
|
|
||||||
|
byte[] data = new byte[PoolItem.SIZE * 2];
|
||||||
|
|
||||||
|
for (int i = 0, n = array.length; i < n; i++) {
|
||||||
|
LineLayer l = array[i];
|
||||||
|
if (l.isOutline)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
for (int k = 0, m = l.pool.size(); k < m; k++) {
|
||||||
|
PoolItem item = l.pool.get(k);
|
||||||
|
PoolItem.toHalfFloat(item, data);
|
||||||
|
sbuf.put(data, 0, item.used * 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
l.offset = pos;
|
||||||
|
pos += l.verticesCnt;
|
||||||
|
|
||||||
|
LayerPool.add(l.pool);
|
||||||
|
l.pool = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
sbuf.position(0);
|
||||||
|
|
||||||
|
// not needed for drawing
|
||||||
|
layers = null;
|
||||||
|
|
||||||
|
return sbuf;
|
||||||
|
}
|
||||||
|
}
|
||||||
1057
src/org/mapsforge/android/glrenderer/MapRenderer.java
Normal file
1057
src/org/mapsforge/android/glrenderer/MapRenderer.java
Normal file
File diff suppressed because it is too large
Load Diff
83
src/org/mapsforge/android/glrenderer/PolygonLayer.java
Normal file
83
src/org/mapsforge/android/glrenderer/PolygonLayer.java
Normal file
@@ -0,0 +1,83 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2012 Hannes Janetzek
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify it under the
|
||||||
|
* terms of the GNU Lesser General 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 License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General License along with
|
||||||
|
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
package org.mapsforge.android.glrenderer;
|
||||||
|
|
||||||
|
import java.util.LinkedList;
|
||||||
|
|
||||||
|
class PolygonLayer extends Layer {
|
||||||
|
int fadeLevel;
|
||||||
|
private boolean first = true;
|
||||||
|
private float originX;
|
||||||
|
private float originY;
|
||||||
|
|
||||||
|
PolygonLayer(int layer, int color, int fade) {
|
||||||
|
super(layer, color);
|
||||||
|
fadeLevel = fade;
|
||||||
|
curItem = LayerPool.get();
|
||||||
|
pool = new LinkedList<PoolItem>();
|
||||||
|
pool.add(curItem);
|
||||||
|
}
|
||||||
|
|
||||||
|
void addPolygon(float[] points, int pos, int length) {
|
||||||
|
|
||||||
|
verticesCnt += length / 2 + 2;
|
||||||
|
|
||||||
|
if (first) {
|
||||||
|
first = false;
|
||||||
|
originX = points[pos];
|
||||||
|
originY = points[pos + 1];
|
||||||
|
}
|
||||||
|
|
||||||
|
float[] curVertices = curItem.vertices;
|
||||||
|
int outPos = curItem.used;
|
||||||
|
|
||||||
|
if (outPos == PoolItem.SIZE) {
|
||||||
|
curVertices = getNextItem();
|
||||||
|
outPos = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
curVertices[outPos++] = originX;
|
||||||
|
curVertices[outPos++] = originY;
|
||||||
|
|
||||||
|
int remaining = length;
|
||||||
|
int inPos = pos;
|
||||||
|
while (remaining > 0) {
|
||||||
|
|
||||||
|
if (outPos == PoolItem.SIZE) {
|
||||||
|
curVertices = getNextItem();
|
||||||
|
outPos = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int len = remaining;
|
||||||
|
if (len > (PoolItem.SIZE) - outPos)
|
||||||
|
len = (PoolItem.SIZE) - outPos;
|
||||||
|
|
||||||
|
System.arraycopy(points, inPos, curVertices, outPos, len);
|
||||||
|
outPos += len;
|
||||||
|
inPos += len;
|
||||||
|
remaining -= len;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (outPos == PoolItem.SIZE) {
|
||||||
|
curVertices = getNextItem();
|
||||||
|
outPos = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
curVertices[outPos++] = points[pos + 0];
|
||||||
|
curVertices[outPos++] = points[pos + 1];
|
||||||
|
|
||||||
|
curItem.used = outPos;
|
||||||
|
}
|
||||||
|
}
|
||||||
162
src/org/mapsforge/android/glrenderer/PolygonLayers.java
Normal file
162
src/org/mapsforge/android/glrenderer/PolygonLayers.java
Normal file
@@ -0,0 +1,162 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2012 Hannes Janetzek
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify it under the
|
||||||
|
* terms of the GNU Lesser General 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 License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General License along with
|
||||||
|
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
package org.mapsforge.android.glrenderer;
|
||||||
|
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
import java.nio.ByteOrder;
|
||||||
|
import java.nio.FloatBuffer;
|
||||||
|
|
||||||
|
import org.mapsforge.android.utils.FastMath;
|
||||||
|
import org.mapsforge.core.Tile;
|
||||||
|
|
||||||
|
import android.util.SparseArray;
|
||||||
|
|
||||||
|
class PolygonLayers {
|
||||||
|
private static final int NUM_VERTEX_FLOATS = 2;
|
||||||
|
private static final float[] mFillCoords = { -2, Tile.TILE_SIZE + 1, Tile.TILE_SIZE + 1, Tile.TILE_SIZE + 1, -2,
|
||||||
|
-2, Tile.TILE_SIZE + 1, -2 };
|
||||||
|
|
||||||
|
private static byte[] mByteFillCoords = null;
|
||||||
|
|
||||||
|
private SparseArray<PolygonLayer> layers;
|
||||||
|
|
||||||
|
PolygonLayer[] array = null;
|
||||||
|
int size;
|
||||||
|
|
||||||
|
PolygonLayers() {
|
||||||
|
layers = new SparseArray<PolygonLayer>(10);
|
||||||
|
size = 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
PolygonLayer getLayer(int layer, int color, int fade) {
|
||||||
|
PolygonLayer l = layers.get(layer);
|
||||||
|
if (l != null) {
|
||||||
|
if (color == l.color)
|
||||||
|
return l;
|
||||||
|
|
||||||
|
return getLayer(layer + 1, color, fade);
|
||||||
|
}
|
||||||
|
|
||||||
|
l = new PolygonLayer(layer, color, fade);
|
||||||
|
layers.put(layer, l);
|
||||||
|
return l;
|
||||||
|
}
|
||||||
|
|
||||||
|
FloatBuffer compileLayerData(FloatBuffer buf) {
|
||||||
|
FloatBuffer fbuf = buf;
|
||||||
|
|
||||||
|
array = new PolygonLayer[layers.size()];
|
||||||
|
|
||||||
|
for (int i = 0, n = layers.size(); i < n; i++) {
|
||||||
|
PolygonLayer l = layers.valueAt(i);
|
||||||
|
array[i] = l;
|
||||||
|
size += l.verticesCnt;
|
||||||
|
}
|
||||||
|
|
||||||
|
size *= NUM_VERTEX_FLOATS;
|
||||||
|
|
||||||
|
if (buf == null || buf.capacity() < size) {
|
||||||
|
ByteBuffer bbuf = ByteBuffer.allocateDirect(size * 4).order(ByteOrder.nativeOrder());
|
||||||
|
// Log.d("GLMap", "allocate buffer " + size);
|
||||||
|
fbuf = bbuf.asFloatBuffer();
|
||||||
|
} else {
|
||||||
|
fbuf.position(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
fbuf.put(mFillCoords, 0, 8);
|
||||||
|
int pos = 4;
|
||||||
|
|
||||||
|
for (int i = 0, n = array.length; i < n; i++) {
|
||||||
|
PolygonLayer l = array[i];
|
||||||
|
|
||||||
|
for (PoolItem item : l.pool) {
|
||||||
|
fbuf.put(item.vertices, 0, item.used);
|
||||||
|
}
|
||||||
|
|
||||||
|
l.offset = pos;
|
||||||
|
pos += l.verticesCnt;
|
||||||
|
|
||||||
|
LayerPool.add(l.pool);
|
||||||
|
l.pool = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
fbuf.position(0);
|
||||||
|
|
||||||
|
// not needed for drawing
|
||||||
|
layers = null;
|
||||||
|
|
||||||
|
return fbuf;
|
||||||
|
}
|
||||||
|
|
||||||
|
ByteBuffer compileLayerData(ByteBuffer buf) {
|
||||||
|
ByteBuffer bbuf = buf;
|
||||||
|
|
||||||
|
array = new PolygonLayer[layers.size()];
|
||||||
|
|
||||||
|
for (int i = 0, n = layers.size(); i < n; i++) {
|
||||||
|
PolygonLayer l = layers.valueAt(i);
|
||||||
|
array[i] = l;
|
||||||
|
size += l.verticesCnt;
|
||||||
|
}
|
||||||
|
|
||||||
|
size *= NUM_VERTEX_FLOATS;
|
||||||
|
|
||||||
|
if (buf == null || buf.capacity() < size * 2) {
|
||||||
|
bbuf = ByteBuffer.allocateDirect(size * 2).order(ByteOrder.nativeOrder());
|
||||||
|
} else {
|
||||||
|
bbuf.position(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
byte[] data = new byte[PoolItem.SIZE * 2];
|
||||||
|
|
||||||
|
if (mByteFillCoords == null) {
|
||||||
|
mByteFillCoords = new byte[16];
|
||||||
|
FastMath.convertFloatToHalf(mFillCoords[0], mByteFillCoords, 0);
|
||||||
|
FastMath.convertFloatToHalf(mFillCoords[1], mByteFillCoords, 2);
|
||||||
|
FastMath.convertFloatToHalf(mFillCoords[2], mByteFillCoords, 4);
|
||||||
|
FastMath.convertFloatToHalf(mFillCoords[3], mByteFillCoords, 6);
|
||||||
|
FastMath.convertFloatToHalf(mFillCoords[4], mByteFillCoords, 8);
|
||||||
|
FastMath.convertFloatToHalf(mFillCoords[5], mByteFillCoords, 10);
|
||||||
|
FastMath.convertFloatToHalf(mFillCoords[6], mByteFillCoords, 12);
|
||||||
|
FastMath.convertFloatToHalf(mFillCoords[7], mByteFillCoords, 14);
|
||||||
|
}
|
||||||
|
|
||||||
|
bbuf.put(mByteFillCoords, 0, 16);
|
||||||
|
int pos = 4;
|
||||||
|
|
||||||
|
for (int i = 0, n = array.length; i < n; i++) {
|
||||||
|
PolygonLayer l = array[i];
|
||||||
|
|
||||||
|
for (int k = 0, m = l.pool.size(); k < m; k++) {
|
||||||
|
PoolItem item = l.pool.get(k);
|
||||||
|
PoolItem.toHalfFloat(item, data);
|
||||||
|
bbuf.put(data, 0, item.used * 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
l.offset = pos;
|
||||||
|
pos += l.verticesCnt;
|
||||||
|
|
||||||
|
LayerPool.add(l.pool);
|
||||||
|
l.pool = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
bbuf.position(0);
|
||||||
|
|
||||||
|
// not needed for drawing
|
||||||
|
layers = null;
|
||||||
|
|
||||||
|
return bbuf;
|
||||||
|
}
|
||||||
|
}
|
||||||
89
src/org/mapsforge/android/glrenderer/PoolItem.java
Normal file
89
src/org/mapsforge/android/glrenderer/PoolItem.java
Normal file
@@ -0,0 +1,89 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2012 Hannes Janetzek
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify it under the
|
||||||
|
* terms of the GNU Lesser General 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 License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General License along with
|
||||||
|
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.mapsforge.android.glrenderer;
|
||||||
|
|
||||||
|
// TODO use byte[] for half-float, not converting on compilation (in glThread)
|
||||||
|
|
||||||
|
class PoolItem {
|
||||||
|
final float[] vertices;
|
||||||
|
// final byte[] vertices;
|
||||||
|
int used;
|
||||||
|
|
||||||
|
PoolItem() {
|
||||||
|
vertices = new float[SIZE];
|
||||||
|
// vertices = new byte[SIZE];
|
||||||
|
used = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int SIZE = 256;
|
||||||
|
|
||||||
|
private static final byte b0x7c = (byte) 0x7c;
|
||||||
|
private static final byte b0x00 = (byte) 0x00;
|
||||||
|
private static final byte b0x01 = (byte) 0x01;
|
||||||
|
private static final byte b0xfc = (byte) 0xfc;
|
||||||
|
private static final byte b0x80 = (byte) 0x80;
|
||||||
|
private static final byte b0x7b = (byte) 0x7b;
|
||||||
|
private static final byte b0xff = (byte) 0xff;
|
||||||
|
private static final byte b0xfb = (byte) 0xfb;
|
||||||
|
private static final float FLOAT_HALF_PREC = 5.96046E-8f;
|
||||||
|
private static final float FLOAT_HALF_MAX = 65504f;
|
||||||
|
|
||||||
|
static void toHalfFloat(PoolItem item, byte[] data) {
|
||||||
|
int out = 0;
|
||||||
|
for (int j = 0; j < item.used; j++) {
|
||||||
|
float flt = item.vertices[j];
|
||||||
|
|
||||||
|
if (flt == 0f) {
|
||||||
|
data[out++] = b0x00;
|
||||||
|
data[out++] = b0x00;
|
||||||
|
} else if (flt == -0f) {
|
||||||
|
data[out++] = b0x00;
|
||||||
|
data[out++] = b0x80;
|
||||||
|
} else if (flt > FLOAT_HALF_MAX) {
|
||||||
|
if (flt == Float.POSITIVE_INFINITY) {
|
||||||
|
data[out++] = b0x00;
|
||||||
|
data[out++] = b0x7c;
|
||||||
|
} else {
|
||||||
|
data[out++] = b0xff;
|
||||||
|
data[out++] = b0x7b;
|
||||||
|
}
|
||||||
|
} else if (flt < -FLOAT_HALF_MAX) {
|
||||||
|
if (flt == Float.NEGATIVE_INFINITY) {
|
||||||
|
data[out++] = b0x00;
|
||||||
|
data[out++] = b0xfc;
|
||||||
|
} else {
|
||||||
|
data[out++] = b0xff;
|
||||||
|
data[out++] = b0xfb;
|
||||||
|
}
|
||||||
|
} else if (flt > 0f && flt < FLOAT_HALF_PREC) {
|
||||||
|
data[out++] = b0x01;
|
||||||
|
data[out++] = b0x00;
|
||||||
|
} else if (flt < 0f && flt > -FLOAT_HALF_PREC) {
|
||||||
|
data[out++] = b0x01;
|
||||||
|
data[out++] = b0x80;
|
||||||
|
} else {
|
||||||
|
int f = Float.floatToIntBits(flt);
|
||||||
|
|
||||||
|
if (f == 0x7fc00000)
|
||||||
|
throw new UnsupportedOperationException("NaN to half conversion not supported!");
|
||||||
|
|
||||||
|
data[out++] = (byte) ((f >> 13) & 0xff);
|
||||||
|
|
||||||
|
data[out++] = (byte) (((f >> 24) & 0x80) | ((((f & 0x7f800000) - 0x38000000) >> 21) & 0x7c) | ((f >> 21) & 0x03));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
63
src/org/mapsforge/android/glrenderer/Shaders.java
Normal file
63
src/org/mapsforge/android/glrenderer/Shaders.java
Normal file
@@ -0,0 +1,63 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2012 Hannes Janetzek
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify it under the
|
||||||
|
* terms of the GNU Lesser General 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 License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General License along with
|
||||||
|
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.mapsforge.android.glrenderer;
|
||||||
|
|
||||||
|
class Shaders {
|
||||||
|
final static String gLineVertexShader = "" + "precision mediump float; \n" + "uniform mat4 u_center;"
|
||||||
|
+ "uniform float u_width;" + "attribute vec4 a_position;" + "attribute vec2 a_st;" + "varying vec2 v_st;"
|
||||||
|
+ "void main() {" + " gl_Position = u_center * a_position;" + " v_st = a_st;" + "}";
|
||||||
|
|
||||||
|
final static String gLineFragmentShader = "" + "#extension GL_OES_standard_derivatives : enable\n"
|
||||||
|
+ "precision mediump float;" + "uniform float u_width;" + "uniform int u_mode;" + "uniform vec4 u_color;"
|
||||||
|
+ "const float zero = 0.0;" + "const int standard = 0;" + "const int fixed_width = 2;"
|
||||||
|
+ "varying vec2 v_st;" + "void main() {" + " gl_FragColor = u_color;" + " float fuzz = fwidth(v_st.s);"
|
||||||
|
+ " float len = abs(v_st.s) - u_width;" + " if (u_mode != fixed_width) {"
|
||||||
|
+ " if (v_st.t != zero){ " + " fuzz = max(fuzz, fwidth(v_st.t));"
|
||||||
|
+ " len = length(v_st) - u_width;" + " } " +
|
||||||
|
// branching is not recommended...
|
||||||
|
// " if (- fuzz > len) " +
|
||||||
|
// " gl_FragColor = u_color;" +
|
||||||
|
// " if (len < -fuzz)" +
|
||||||
|
// " discard;" +
|
||||||
|
// " else " +
|
||||||
|
" if (len > -fuzz)" + " gl_FragColor *= smoothstep(fuzz , -fuzz , len);" + " } else { " +
|
||||||
|
// just guesswork.. looks ok for fixed line width >= 0.5
|
||||||
|
" if (len > -fuzz)" + " gl_FragColor *= smoothstep(fuzz*0.5, -fuzz, len);" + " }" + "}";
|
||||||
|
|
||||||
|
// final static String gLineFragmentShader = "" +
|
||||||
|
// "#extension GL_OES_standard_derivatives : enable\n" +
|
||||||
|
// "precision mediump float;" +
|
||||||
|
// "uniform float u_width;" +
|
||||||
|
// "uniform int u_mode;" +
|
||||||
|
// "uniform vec4 u_color;" +
|
||||||
|
// "varying vec2 v_st;" +
|
||||||
|
// "void main() {" +
|
||||||
|
// " gl_FragColor = u_color;" +
|
||||||
|
// "}";
|
||||||
|
|
||||||
|
final static String gLineFragmentShaderSimple = "" + "precision mediump float;" + "uniform vec4 u_color;"
|
||||||
|
+ "uniform float u_width;" + "varying vec2 v_st;" + "void main() {" + " vec4 color = u_color;"
|
||||||
|
+ " float len;" + " if (v_st.t == 0.0) " + " len = abs(v_st.s);" + " else "
|
||||||
|
+ " len = length(v_st);" + " if (len > 0.4) {"
|
||||||
|
+ " color = u_color * (smoothstep(0.2, 1.0, (u_width + 0.3) - len));" + "}" + " gl_FragColor = color;"
|
||||||
|
+ "}";
|
||||||
|
|
||||||
|
final static String gPolygonVertexShader = "" + "precision mediump float; \n" + "uniform mat4 u_center;\n"
|
||||||
|
+ "attribute vec4 a_position;" + "void main() {" + " gl_Position = u_center * a_position;" + "}";
|
||||||
|
|
||||||
|
final static String gPolygonFragmentShader = "" + "precision mediump float;" + "uniform vec4 u_color;"
|
||||||
|
+ "void main() {" + " gl_FragColor = u_color;" + "}";
|
||||||
|
}
|
||||||
26
src/org/mapsforge/android/glrenderer/VertexBufferObject.java
Normal file
26
src/org/mapsforge/android/glrenderer/VertexBufferObject.java
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2012 Hannes Janetzek
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify it under the
|
||||||
|
* terms of the GNU Lesser General 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 License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General License along with
|
||||||
|
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.mapsforge.android.glrenderer;
|
||||||
|
|
||||||
|
class VertexBufferObject {
|
||||||
|
final int id;
|
||||||
|
int size;
|
||||||
|
|
||||||
|
VertexBufferObject(int id) {
|
||||||
|
this.id = id;
|
||||||
|
size = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
240
src/org/mapsforge/android/inputhandling/MapMover.java
Normal file
240
src/org/mapsforge/android/inputhandling/MapMover.java
Normal file
@@ -0,0 +1,240 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010, 2011, 2012 mapsforge.org
|
||||||
|
*
|
||||||
|
* 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.mapsforge.android.inputhandling;
|
||||||
|
|
||||||
|
import org.mapsforge.android.MapView;
|
||||||
|
import org.mapsforge.android.utils.PausableThread;
|
||||||
|
|
||||||
|
import android.os.SystemClock;
|
||||||
|
import android.view.KeyEvent;
|
||||||
|
import android.view.MotionEvent;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A MapMover moves the map horizontally and vertically at a configurable speed. It runs in a separate thread to avoid
|
||||||
|
* blocking the UI thread.
|
||||||
|
*/
|
||||||
|
public class MapMover extends PausableThread implements KeyEvent.Callback {
|
||||||
|
|
||||||
|
private static final int DEFAULT_MOVE_SPEED_FACTOR = 10;
|
||||||
|
private static final int FRAME_LENGTH_IN_MS = 15;
|
||||||
|
private static final float MOVE_SPEED = 0.2f;
|
||||||
|
private static final String THREAD_NAME = "MapMover";
|
||||||
|
private static final float TRACKBALL_MOVE_SPEED_FACTOR = 40;
|
||||||
|
|
||||||
|
private final MapView mMapView;
|
||||||
|
private float mMoveSpeedFactor;
|
||||||
|
private float mMoveX;
|
||||||
|
private float mMoveY;
|
||||||
|
private long mTimePrevious;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param mapView
|
||||||
|
* the MapView which should be moved by this MapMover.
|
||||||
|
*/
|
||||||
|
public MapMover(MapView mapView) {
|
||||||
|
super();
|
||||||
|
mMapView = mapView;
|
||||||
|
mMoveSpeedFactor = DEFAULT_MOVE_SPEED_FACTOR;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the move speed factor, used for trackball and keyboard events.
|
||||||
|
*/
|
||||||
|
public float getMoveSpeedFactor() {
|
||||||
|
return mMoveSpeedFactor;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onKeyDown(int keyCode, KeyEvent keyEvent) {
|
||||||
|
if (!mMapView.isClickable()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (keyCode == KeyEvent.KEYCODE_DPAD_LEFT) {
|
||||||
|
moveLeft();
|
||||||
|
return true;
|
||||||
|
} else if (keyCode == KeyEvent.KEYCODE_DPAD_RIGHT) {
|
||||||
|
moveRight();
|
||||||
|
return true;
|
||||||
|
} else if (keyCode == KeyEvent.KEYCODE_DPAD_UP) {
|
||||||
|
moveUp();
|
||||||
|
return true;
|
||||||
|
} else if (keyCode == KeyEvent.KEYCODE_DPAD_DOWN) {
|
||||||
|
moveDown();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onKeyLongPress(int keyCode, KeyEvent keyEvent) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onKeyMultiple(int keyCode, int count, KeyEvent keyEvent) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onKeyUp(int keyCode, KeyEvent keyEvent) {
|
||||||
|
if (!mMapView.isClickable()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (keyCode == KeyEvent.KEYCODE_DPAD_LEFT || keyCode == KeyEvent.KEYCODE_DPAD_RIGHT) {
|
||||||
|
mMoveX = 0;
|
||||||
|
return true;
|
||||||
|
} else if (keyCode == KeyEvent.KEYCODE_DPAD_UP || keyCode == KeyEvent.KEYCODE_DPAD_DOWN) {
|
||||||
|
mMoveY = 0;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param motionEvent
|
||||||
|
* a trackball event which should be handled.
|
||||||
|
* @return true if the event was handled, false otherwise.
|
||||||
|
*/
|
||||||
|
public boolean onTrackballEvent(MotionEvent motionEvent) {
|
||||||
|
if (!mMapView.isClickable()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (motionEvent.getAction() == MotionEvent.ACTION_MOVE) {
|
||||||
|
float mapMoveX = motionEvent.getX() * TRACKBALL_MOVE_SPEED_FACTOR * getMoveSpeedFactor();
|
||||||
|
float mapMoveY = motionEvent.getY() * TRACKBALL_MOVE_SPEED_FACTOR * getMoveSpeedFactor();
|
||||||
|
|
||||||
|
// mapView.getFrameBuffer().matrixPostTranslate(mapMoveX,
|
||||||
|
// mapMoveY);
|
||||||
|
mMapView.getMapPosition().moveMap(mapMoveX, mapMoveY);
|
||||||
|
mMapView.redrawTiles();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the move speed factor of the map, used for trackball and keyboard events.
|
||||||
|
*
|
||||||
|
* @param moveSpeedFactor
|
||||||
|
* the factor by which the move speed of the map will be multiplied.
|
||||||
|
* @throws IllegalArgumentException
|
||||||
|
* if the new move speed factor is negative.
|
||||||
|
*/
|
||||||
|
public void setMoveSpeedFactor(float moveSpeedFactor) {
|
||||||
|
if (moveSpeedFactor < 0) {
|
||||||
|
throw new IllegalArgumentException();
|
||||||
|
}
|
||||||
|
mMoveSpeedFactor = moveSpeedFactor;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stops moving the map completely.
|
||||||
|
*/
|
||||||
|
public void stopMove() {
|
||||||
|
mMoveX = 0;
|
||||||
|
mMoveY = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void moveDown() {
|
||||||
|
if (mMoveY > 0) {
|
||||||
|
// stop moving the map vertically
|
||||||
|
mMoveY = 0;
|
||||||
|
} else if (mMoveY == 0) {
|
||||||
|
// start moving the map
|
||||||
|
mMoveY = -MOVE_SPEED * mMoveSpeedFactor;
|
||||||
|
mTimePrevious = SystemClock.uptimeMillis();
|
||||||
|
synchronized (this) {
|
||||||
|
notify();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void moveLeft() {
|
||||||
|
if (mMoveX < 0) {
|
||||||
|
// stop moving the map horizontally
|
||||||
|
mMoveX = 0;
|
||||||
|
} else if (mMoveX == 0) {
|
||||||
|
// start moving the map
|
||||||
|
mMoveX = MOVE_SPEED * mMoveSpeedFactor;
|
||||||
|
mTimePrevious = SystemClock.uptimeMillis();
|
||||||
|
synchronized (this) {
|
||||||
|
notify();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void moveRight() {
|
||||||
|
if (mMoveX > 0) {
|
||||||
|
// stop moving the map horizontally
|
||||||
|
mMoveX = 0;
|
||||||
|
} else if (mMoveX == 0) {
|
||||||
|
// start moving the map
|
||||||
|
mMoveX = -MOVE_SPEED * mMoveSpeedFactor;
|
||||||
|
mTimePrevious = SystemClock.uptimeMillis();
|
||||||
|
synchronized (this) {
|
||||||
|
notify();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void moveUp() {
|
||||||
|
if (mMoveY < 0) {
|
||||||
|
// stop moving the map vertically
|
||||||
|
mMoveY = 0;
|
||||||
|
} else if (mMoveY == 0) {
|
||||||
|
// start moving the map
|
||||||
|
mMoveY = MOVE_SPEED * mMoveSpeedFactor;
|
||||||
|
mTimePrevious = SystemClock.uptimeMillis();
|
||||||
|
synchronized (this) {
|
||||||
|
notify();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void afterPause() {
|
||||||
|
mTimePrevious = SystemClock.uptimeMillis();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void doWork() throws InterruptedException {
|
||||||
|
// calculate the time difference to previous call
|
||||||
|
long timeCurrent = SystemClock.uptimeMillis();
|
||||||
|
long timeElapsed = timeCurrent - mTimePrevious;
|
||||||
|
mTimePrevious = timeCurrent;
|
||||||
|
|
||||||
|
// add the movement to the transformation matrices
|
||||||
|
// mapView.getFrameBuffer().matrixPostTranslate(timeElapsed *
|
||||||
|
// moveX, timeElapsed * moveY);
|
||||||
|
|
||||||
|
// move the map and the overlays
|
||||||
|
mMapView.getMapPosition().moveMap(timeElapsed * mMoveX, timeElapsed * mMoveY);
|
||||||
|
mMapView.redrawTiles();
|
||||||
|
sleep(FRAME_LENGTH_IN_MS);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected String getThreadName() {
|
||||||
|
return THREAD_NAME;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected boolean hasWork() {
|
||||||
|
return mMoveX != 0 || mMoveY != 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
64
src/org/mapsforge/android/inputhandling/ScaleListener.java
Normal file
64
src/org/mapsforge/android/inputhandling/ScaleListener.java
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010, 2011, 2012 mapsforge.org
|
||||||
|
*
|
||||||
|
* 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.mapsforge.android.inputhandling;
|
||||||
|
|
||||||
|
import org.mapsforge.android.MapView;
|
||||||
|
import org.mapsforge.android.MapViewPosition;
|
||||||
|
|
||||||
|
import android.view.ScaleGestureDetector;
|
||||||
|
|
||||||
|
class ScaleListener implements ScaleGestureDetector.OnScaleGestureListener {
|
||||||
|
private final MapView mMapView;
|
||||||
|
private float mFocusX;
|
||||||
|
private float mFocusY;
|
||||||
|
private MapViewPosition mMapPosition;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new ScaleListener for the given MapView.
|
||||||
|
*
|
||||||
|
* @param mapView
|
||||||
|
* the MapView which should be scaled.
|
||||||
|
*/
|
||||||
|
ScaleListener(MapView mapView) {
|
||||||
|
mMapView = mapView;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onScale(ScaleGestureDetector scaleGestureDetector) {
|
||||||
|
float scaleFactor = scaleGestureDetector.getScaleFactor();
|
||||||
|
|
||||||
|
mMapPosition.scaleMap(scaleFactor, mFocusX, mFocusY);
|
||||||
|
mMapView.redrawTiles();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onScaleBegin(ScaleGestureDetector scaleGestureDetector) {
|
||||||
|
mFocusX = scaleGestureDetector.getFocusX();
|
||||||
|
mFocusY = scaleGestureDetector.getFocusY();
|
||||||
|
|
||||||
|
mFocusX -= ((mMapView.getWidth() >> 1));
|
||||||
|
mFocusY -= ((mMapView.getHeight() >> 1));
|
||||||
|
mMapPosition = mMapView.getMapPosition();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onScaleEnd(ScaleGestureDetector scaleGestureDetector) {
|
||||||
|
// do nothing
|
||||||
|
}
|
||||||
|
}
|
||||||
300
src/org/mapsforge/android/inputhandling/TouchHandler.java
Normal file
300
src/org/mapsforge/android/inputhandling/TouchHandler.java
Normal file
@@ -0,0 +1,300 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010, 2011, 2012 mapsforge.org
|
||||||
|
*
|
||||||
|
* 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.mapsforge.android.inputhandling;
|
||||||
|
|
||||||
|
import org.mapsforge.android.MapView;
|
||||||
|
import org.mapsforge.core.Tile;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.os.CountDownTimer;
|
||||||
|
import android.util.Log;
|
||||||
|
import android.view.GestureDetector;
|
||||||
|
import android.view.GestureDetector.SimpleOnGestureListener;
|
||||||
|
import android.view.MotionEvent;
|
||||||
|
import android.view.ScaleGestureDetector;
|
||||||
|
import android.view.ViewConfiguration;
|
||||||
|
import android.view.animation.DecelerateInterpolator;
|
||||||
|
import android.widget.Scroller;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Implementation for multi-touch capable devices.
|
||||||
|
*/
|
||||||
|
public class TouchHandler {
|
||||||
|
private static final int INVALID_POINTER_ID = -1;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* is pritected correct? share MapView with inner class
|
||||||
|
*/
|
||||||
|
protected final MapView mMapView;
|
||||||
|
|
||||||
|
private final float mMapMoveDelta;
|
||||||
|
private boolean mMoveThresholdReached;
|
||||||
|
private float mPreviousPositionX;
|
||||||
|
private float mPreviousPositionY;
|
||||||
|
private int mActivePointerId;
|
||||||
|
|
||||||
|
private final ScaleGestureDetector mScaleGestureDetector;
|
||||||
|
private final GestureDetector mGestureDetector;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param context
|
||||||
|
* the Context
|
||||||
|
* @param mapView
|
||||||
|
* the MapView
|
||||||
|
*/
|
||||||
|
public TouchHandler(Context context, MapView mapView) {
|
||||||
|
ViewConfiguration viewConfiguration = ViewConfiguration.get(context);
|
||||||
|
mMapView = mapView;
|
||||||
|
mMapMoveDelta = viewConfiguration.getScaledTouchSlop();
|
||||||
|
mActivePointerId = INVALID_POINTER_ID;
|
||||||
|
mScaleGestureDetector = new ScaleGestureDetector(context, new ScaleListener(mMapView));
|
||||||
|
mGestureDetector = new GestureDetector(new MapGestureDetector(mMapView));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int getAction(MotionEvent motionEvent) {
|
||||||
|
return motionEvent.getAction() & MotionEvent.ACTION_MASK;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean onActionCancel() {
|
||||||
|
mActivePointerId = INVALID_POINTER_ID;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean onActionDown(MotionEvent motionEvent) {
|
||||||
|
mPreviousPositionX = motionEvent.getX();
|
||||||
|
mPreviousPositionY = motionEvent.getY();
|
||||||
|
mMoveThresholdReached = false;
|
||||||
|
// save the ID of the pointer
|
||||||
|
mActivePointerId = motionEvent.getPointerId(0);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean onActionMove(MotionEvent motionEvent) {
|
||||||
|
int pointerIndex = motionEvent.findPointerIndex(mActivePointerId);
|
||||||
|
|
||||||
|
// calculate the distance between previous and current position
|
||||||
|
float moveX = motionEvent.getX(pointerIndex) - mPreviousPositionX;
|
||||||
|
float moveY = motionEvent.getY(pointerIndex) - mPreviousPositionY;
|
||||||
|
boolean scaling = mScaleGestureDetector.isInProgress();
|
||||||
|
if (!scaling && !mMoveThresholdReached) {
|
||||||
|
|
||||||
|
if (Math.abs(moveX) > 3 * mMapMoveDelta || Math.abs(moveY) > 3 * mMapMoveDelta) {
|
||||||
|
// the map movement threshold has been reached
|
||||||
|
// longPressDetector.pressStop();
|
||||||
|
mMoveThresholdReached = true;
|
||||||
|
|
||||||
|
// save the position of the event
|
||||||
|
mPreviousPositionX = motionEvent.getX(pointerIndex);
|
||||||
|
mPreviousPositionY = motionEvent.getY(pointerIndex);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// save the position of the event
|
||||||
|
mPreviousPositionX = motionEvent.getX(pointerIndex);
|
||||||
|
mPreviousPositionY = motionEvent.getY(pointerIndex);
|
||||||
|
|
||||||
|
if (scaling) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
mMapView.getMapPosition().moveMap(moveX, moveY);
|
||||||
|
mMapView.redrawTiles();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// private boolean onActionPointerDown(MotionEvent motionEvent) {
|
||||||
|
// longPressDetector.pressStop();
|
||||||
|
// multiTouchDownTime = motionEvent.getEventTime();
|
||||||
|
// return true;
|
||||||
|
// }
|
||||||
|
|
||||||
|
private boolean onActionPointerUp(MotionEvent motionEvent) {
|
||||||
|
|
||||||
|
// extract the index of the pointer that left the touch sensor
|
||||||
|
int pointerIndex = (motionEvent.getAction() & MotionEvent.ACTION_POINTER_INDEX_MASK) >> MotionEvent.ACTION_POINTER_INDEX_SHIFT;
|
||||||
|
if (motionEvent.getPointerId(pointerIndex) == mActivePointerId) {
|
||||||
|
// the active pointer has gone up, choose a new one
|
||||||
|
if (pointerIndex == 0) {
|
||||||
|
pointerIndex = 1;
|
||||||
|
} else {
|
||||||
|
pointerIndex = 0;
|
||||||
|
}
|
||||||
|
// save the position of the event
|
||||||
|
mPreviousPositionX = motionEvent.getX(pointerIndex);
|
||||||
|
mPreviousPositionY = motionEvent.getY(pointerIndex);
|
||||||
|
mActivePointerId = motionEvent.getPointerId(pointerIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
// calculate the time difference since the pointer has gone down
|
||||||
|
// long multiTouchTime = motionEvent.getEventTime() -
|
||||||
|
// multiTouchDownTime;
|
||||||
|
// if (multiTouchTime < doubleTapTimeout) {
|
||||||
|
// // multi-touch tap event, zoom out
|
||||||
|
// previousEventTap = false;
|
||||||
|
// mapView.zoom((byte) -1);
|
||||||
|
// }
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param motionEvent
|
||||||
|
* ...
|
||||||
|
* @return ...
|
||||||
|
*/
|
||||||
|
private boolean onActionUp(MotionEvent motionEvent) {
|
||||||
|
// longPressDetector.pressStop();
|
||||||
|
// int pointerIndex = motionEvent.findPointerIndex(mActivePointerId);
|
||||||
|
|
||||||
|
mActivePointerId = INVALID_POINTER_ID;
|
||||||
|
// if (mMoveThresholdReached // || longPressDetector.isEventHandled()
|
||||||
|
// ) {
|
||||||
|
// mPreviousEventTap = false;
|
||||||
|
// } else {
|
||||||
|
// if (mPreviousEventTap) {
|
||||||
|
//
|
||||||
|
// } else {
|
||||||
|
// mPreviousEventTap = true;
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// // store the position and the time of this tap event
|
||||||
|
// mPreviousTapX = motionEvent.getX(pointerIndex);
|
||||||
|
// mPreviousTapY = motionEvent.getY(pointerIndex);
|
||||||
|
// mPreviousTapTime = motionEvent.getEventTime();
|
||||||
|
//
|
||||||
|
// }
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param motionEvent
|
||||||
|
* ...
|
||||||
|
* @return ...
|
||||||
|
*/
|
||||||
|
public boolean handleMotionEvent(MotionEvent motionEvent) {
|
||||||
|
// workaround for a bug in the ScaleGestureDetector, see Android issue
|
||||||
|
// #12976
|
||||||
|
if (motionEvent.getAction() != MotionEvent.ACTION_MOVE || motionEvent.getPointerCount() > 1) {
|
||||||
|
mScaleGestureDetector.onTouchEvent(motionEvent);
|
||||||
|
}
|
||||||
|
|
||||||
|
mGestureDetector.onTouchEvent(motionEvent);
|
||||||
|
// if () {
|
||||||
|
// // mActivePointerId = INVALID_POINTER_ID;
|
||||||
|
// // return true;
|
||||||
|
// }
|
||||||
|
int action = getAction(motionEvent);
|
||||||
|
|
||||||
|
if (action == MotionEvent.ACTION_DOWN) {
|
||||||
|
return onActionDown(motionEvent);
|
||||||
|
} else if (action == MotionEvent.ACTION_MOVE) {
|
||||||
|
return onActionMove(motionEvent);
|
||||||
|
} else if (action == MotionEvent.ACTION_UP) {
|
||||||
|
return onActionUp(motionEvent);
|
||||||
|
} else if (action == MotionEvent.ACTION_CANCEL) {
|
||||||
|
return onActionCancel();
|
||||||
|
// } else if (action == MotionEvent.ACTION_POINTER_DOWN) {
|
||||||
|
// return onActionPointerDown(motionEvent);
|
||||||
|
} else if (action == MotionEvent.ACTION_POINTER_UP) {
|
||||||
|
return onActionPointerUp(motionEvent);
|
||||||
|
}
|
||||||
|
|
||||||
|
// the event was not handled
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
class MapGestureDetector extends SimpleOnGestureListener {
|
||||||
|
private Scroller mScroller;
|
||||||
|
private float mPrevX, mPrevY;
|
||||||
|
private CountDownTimer mTimer = null;
|
||||||
|
|
||||||
|
public MapGestureDetector(MapView mapView) {
|
||||||
|
mScroller = new Scroller(mapView.getContext(), new DecelerateInterpolator());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onDown(MotionEvent e) {
|
||||||
|
mScroller.forceFinished(true);
|
||||||
|
|
||||||
|
if (mTimer != null) {
|
||||||
|
mTimer.cancel();
|
||||||
|
mTimer = null;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean scroll() {
|
||||||
|
if (mScroller.isFinished()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
mScroller.computeScrollOffset();
|
||||||
|
float moveX = mScroller.getCurrX() - mPrevX;
|
||||||
|
float moveY = mScroller.getCurrY() - mPrevY;
|
||||||
|
|
||||||
|
if (moveX >= 1 || moveY >= 1 || moveX <= -1 || moveY <= -1) {
|
||||||
|
mMapView.getMapPosition().moveMap(moveX, moveY);
|
||||||
|
mMapView.redrawTiles();
|
||||||
|
mPrevX = mScroller.getCurrX();
|
||||||
|
mPrevY = mScroller.getCurrY();
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
|
||||||
|
int w = Tile.TILE_SIZE * 20;
|
||||||
|
int h = Tile.TILE_SIZE * 20;
|
||||||
|
mPrevX = 0;
|
||||||
|
mPrevY = 0;
|
||||||
|
|
||||||
|
if (mTimer != null) {
|
||||||
|
mTimer.cancel();
|
||||||
|
mTimer = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
mScroller.fling(0, 0, Math.round(velocityX) / 2, Math.round(velocityY) / 2, -w, w, -h, h);
|
||||||
|
// animate for two seconds
|
||||||
|
mTimer = new CountDownTimer(2000, 20) {
|
||||||
|
@Override
|
||||||
|
public void onTick(long tick) {
|
||||||
|
if (!scroll())
|
||||||
|
cancel();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onFinish() {
|
||||||
|
// do nothing
|
||||||
|
}
|
||||||
|
}.start();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onLongPress(MotionEvent e) {
|
||||||
|
// mMapView.zoom((byte) 1);
|
||||||
|
Log.d("mapsforge", "long press");
|
||||||
|
// return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onDoubleTap(MotionEvent e) {
|
||||||
|
mMapView.zoom((byte) 1);
|
||||||
|
Log.d("mapsforge", "double tap");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
121
src/org/mapsforge/android/inputhandling/ZoomAnimator.java
Normal file
121
src/org/mapsforge/android/inputhandling/ZoomAnimator.java
Normal file
@@ -0,0 +1,121 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010, 2011, 2012 mapsforge.org
|
||||||
|
*
|
||||||
|
* 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.mapsforge.android.inputhandling;
|
||||||
|
|
||||||
|
import org.mapsforge.android.MapView;
|
||||||
|
import org.mapsforge.android.utils.PausableThread;
|
||||||
|
|
||||||
|
import android.os.SystemClock;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A ZoomAnimator handles the zoom-in and zoom-out animations of the corresponding MapView. It runs in a separate thread
|
||||||
|
* to avoid blocking the UI thread.
|
||||||
|
*/
|
||||||
|
public class ZoomAnimator extends PausableThread {
|
||||||
|
private static final int DEFAULT_DURATION = 250;
|
||||||
|
private static final int FRAME_LENGTH_IN_MS = 15;
|
||||||
|
private static final String THREAD_NAME = "ZoomAnimator";
|
||||||
|
|
||||||
|
private boolean mExecuteAnimation;
|
||||||
|
private final MapView mMapView;
|
||||||
|
// private float mPivotX;
|
||||||
|
// private float mPivotY;
|
||||||
|
private float mScaleFactorApplied;
|
||||||
|
private long mTimeStart;
|
||||||
|
private float mZoomDifference;
|
||||||
|
private float mZoomEnd;
|
||||||
|
private float mZoomStart;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param mapView
|
||||||
|
* the MapView whose zoom level changes should be animated.
|
||||||
|
*/
|
||||||
|
public ZoomAnimator(MapView mapView) {
|
||||||
|
super();
|
||||||
|
mMapView = mapView;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return true if the ZoomAnimator is working, false otherwise.
|
||||||
|
*/
|
||||||
|
public boolean isExecuting() {
|
||||||
|
return mExecuteAnimation;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the parameters for the zoom animation.
|
||||||
|
*
|
||||||
|
* @param zoomStart
|
||||||
|
* the zoom factor at the begin of the animation.
|
||||||
|
* @param zoomEnd
|
||||||
|
* the zoom factor at the end of the animation.
|
||||||
|
* @param pivotX
|
||||||
|
* the x coordinate of the animation center.
|
||||||
|
* @param pivotY
|
||||||
|
* the y coordinate of the animation center.
|
||||||
|
*/
|
||||||
|
public void setParameters(float zoomStart, float zoomEnd, float pivotX, float pivotY) {
|
||||||
|
mZoomStart = zoomStart;
|
||||||
|
mZoomEnd = zoomEnd;
|
||||||
|
// mPivotX = pivotX;
|
||||||
|
// mPivotY = pivotY;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Starts a zoom animation with the current parameters.
|
||||||
|
*/
|
||||||
|
public void startAnimation() {
|
||||||
|
mZoomDifference = mZoomEnd - mZoomStart;
|
||||||
|
mScaleFactorApplied = mZoomStart;
|
||||||
|
mExecuteAnimation = true;
|
||||||
|
mTimeStart = SystemClock.uptimeMillis();
|
||||||
|
synchronized (this) {
|
||||||
|
notify();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void doWork() throws InterruptedException {
|
||||||
|
// calculate the elapsed time
|
||||||
|
long timeElapsed = SystemClock.uptimeMillis() - mTimeStart;
|
||||||
|
float timeElapsedPercent = Math.min(1, timeElapsed / (float) DEFAULT_DURATION);
|
||||||
|
|
||||||
|
// calculate the zoom and scale values at the current moment
|
||||||
|
float currentZoom = mZoomStart + timeElapsedPercent * mZoomDifference;
|
||||||
|
float scaleFactor = currentZoom / mScaleFactorApplied;
|
||||||
|
mScaleFactorApplied *= scaleFactor;
|
||||||
|
// mapView.getFrameBuffer().matrixPostScale(scaleFactor, scaleFactor,
|
||||||
|
// pivotX, pivotY);
|
||||||
|
|
||||||
|
// check if the animation time is over
|
||||||
|
if (timeElapsed >= DEFAULT_DURATION) {
|
||||||
|
mExecuteAnimation = false;
|
||||||
|
mMapView.redrawTiles();
|
||||||
|
} else {
|
||||||
|
mMapView.postInvalidate();
|
||||||
|
sleep(FRAME_LENGTH_IN_MS);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected String getThreadName() {
|
||||||
|
return THREAD_NAME;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected boolean hasWork() {
|
||||||
|
return mExecuteAnimation;
|
||||||
|
}
|
||||||
|
}
|
||||||
85
src/org/mapsforge/android/mapgenerator/JobParameters.java
Normal file
85
src/org/mapsforge/android/mapgenerator/JobParameters.java
Normal file
@@ -0,0 +1,85 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010, 2011, 2012 mapsforge.org
|
||||||
|
*
|
||||||
|
* 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.mapsforge.android.mapgenerator;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A JobParameters instance is a simple DTO to store the rendering parameters for a job.
|
||||||
|
*/
|
||||||
|
public class JobParameters implements Serializable {
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The render theme which should be used.
|
||||||
|
*/
|
||||||
|
public final JobTheme jobTheme;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The text scale factor which should applied to the render theme.
|
||||||
|
*/
|
||||||
|
public final float textScale;
|
||||||
|
|
||||||
|
private final int mHashCodeValue;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param jobTheme
|
||||||
|
* render theme which should be used.
|
||||||
|
* @param textScale
|
||||||
|
* the text scale factor which should applied to the render theme.
|
||||||
|
*/
|
||||||
|
public JobParameters(JobTheme jobTheme, float textScale) {
|
||||||
|
this.jobTheme = jobTheme;
|
||||||
|
this.textScale = textScale;
|
||||||
|
mHashCodeValue = calculateHashCode();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object obj) {
|
||||||
|
if (this == obj) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (!(obj instanceof JobParameters)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
JobParameters other = (JobParameters) obj;
|
||||||
|
if (jobTheme == null) {
|
||||||
|
if (other.jobTheme != null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} else if (!jobTheme.equals(other.jobTheme)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (Float.floatToIntBits(textScale) != Float.floatToIntBits(other.textScale)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return mHashCodeValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the hash code of this object.
|
||||||
|
*/
|
||||||
|
private int calculateHashCode() {
|
||||||
|
int result = 7;
|
||||||
|
result = 31 * result + ((jobTheme == null) ? 0 : jobTheme.hashCode());
|
||||||
|
result = 31 * result + Float.floatToIntBits(textScale);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
121
src/org/mapsforge/android/mapgenerator/JobQueue.java
Normal file
121
src/org/mapsforge/android/mapgenerator/JobQueue.java
Normal file
@@ -0,0 +1,121 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010, 2011, 2012 mapsforge.org
|
||||||
|
*
|
||||||
|
* 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.mapsforge.android.mapgenerator;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.PriorityQueue;
|
||||||
|
|
||||||
|
import org.mapsforge.android.MapView;
|
||||||
|
|
||||||
|
import android.os.SystemClock;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A JobQueue keeps the list of pending jobs for a MapView and prioritizes them.
|
||||||
|
*/
|
||||||
|
public class JobQueue {
|
||||||
|
private static final int INITIAL_CAPACITY = 128;
|
||||||
|
|
||||||
|
private final MapView mMapView;
|
||||||
|
private PriorityQueue<MapGeneratorJob> mPriorityQueue;
|
||||||
|
private boolean mScheduleNeeded;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param mapView
|
||||||
|
* the MapView whose jobs should be organized.
|
||||||
|
*/
|
||||||
|
public JobQueue(MapView mapView) {
|
||||||
|
mMapView = mapView;
|
||||||
|
mPriorityQueue = new PriorityQueue<MapGeneratorJob>(INITIAL_CAPACITY);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds the given job to this queue. Does nothing if the given job is already in this queue.
|
||||||
|
*
|
||||||
|
* @param mapGeneratorJob
|
||||||
|
* the job to be added to this queue.
|
||||||
|
*/
|
||||||
|
public synchronized void addJob(MapGeneratorJob mapGeneratorJob) {
|
||||||
|
if (!mPriorityQueue.contains(mapGeneratorJob))
|
||||||
|
// priorityQueue.remove(mapGeneratorJob);
|
||||||
|
{
|
||||||
|
mapGeneratorJob.tile.isLoading = true;
|
||||||
|
mPriorityQueue.offer(mapGeneratorJob);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param jobs
|
||||||
|
* the job to be added to this queue.
|
||||||
|
*/
|
||||||
|
public synchronized void setJobs(ArrayList<MapGeneratorJob> jobs) {
|
||||||
|
mPriorityQueue.clear();
|
||||||
|
for (MapGeneratorJob job : jobs)
|
||||||
|
mPriorityQueue.offer(job);
|
||||||
|
// priorityQueue.addAll(jobs);
|
||||||
|
mScheduleNeeded = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes all jobs from this queue.
|
||||||
|
*/
|
||||||
|
public synchronized void clear() {
|
||||||
|
mPriorityQueue.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return true if this queue contains no jobs, false otherwise.
|
||||||
|
*/
|
||||||
|
public synchronized boolean isEmpty() {
|
||||||
|
return mPriorityQueue.isEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the most important job from this queue or null, if empty.
|
||||||
|
*/
|
||||||
|
public synchronized MapGeneratorJob poll() {
|
||||||
|
if (mScheduleNeeded) {
|
||||||
|
mScheduleNeeded = false;
|
||||||
|
schedule();
|
||||||
|
}
|
||||||
|
return mPriorityQueue.poll();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Request a scheduling of all jobs that are currently in this queue.
|
||||||
|
*/
|
||||||
|
public synchronized void requestSchedule() {
|
||||||
|
mScheduleNeeded = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Schedules all jobs in this queue.
|
||||||
|
*/
|
||||||
|
private void schedule() {
|
||||||
|
PriorityQueue<MapGeneratorJob> tempJobQueue = new PriorityQueue<MapGeneratorJob>(INITIAL_CAPACITY);
|
||||||
|
|
||||||
|
TileScheduler.time = SystemClock.uptimeMillis();
|
||||||
|
TileScheduler.mapPosition = mMapView.getMapPosition().getMapPosition();
|
||||||
|
|
||||||
|
while (!mPriorityQueue.isEmpty()) {
|
||||||
|
MapGeneratorJob mapGeneratorJob = mPriorityQueue.poll();
|
||||||
|
double priority = TileScheduler.getPriority(mapGeneratorJob, mMapView);
|
||||||
|
mapGeneratorJob.setPriority(priority);
|
||||||
|
tempJobQueue.offer(mapGeneratorJob);
|
||||||
|
}
|
||||||
|
|
||||||
|
mPriorityQueue = tempJobQueue;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
31
src/org/mapsforge/android/mapgenerator/JobTheme.java
Normal file
31
src/org/mapsforge/android/mapgenerator/JobTheme.java
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010, 2011, 2012 mapsforge.org
|
||||||
|
*
|
||||||
|
* 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.mapsforge.android.mapgenerator;
|
||||||
|
|
||||||
|
import java.io.FileNotFoundException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.io.Serializable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A JobTheme defines the render theme which is used for a {@link MapGeneratorJob}.
|
||||||
|
*/
|
||||||
|
public interface JobTheme extends Serializable {
|
||||||
|
/**
|
||||||
|
* @return an InputStream to read the render theme data from.
|
||||||
|
* @throws FileNotFoundException
|
||||||
|
* if the render theme file cannot be found.
|
||||||
|
*/
|
||||||
|
InputStream getRenderThemeAsStream() throws FileNotFoundException;
|
||||||
|
}
|
||||||
@@ -0,0 +1,65 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010, 2011, 2012 mapsforge.org
|
||||||
|
*
|
||||||
|
* 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.mapsforge.android.mapgenerator;
|
||||||
|
|
||||||
|
import org.mapsforge.mapdatabase.IMapDatabase;
|
||||||
|
|
||||||
|
import android.util.AttributeSet;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public final class MapDatabaseFactory {
|
||||||
|
private static final String MAP_DATABASE_ATTRIBUTE_NAME = "mapDatabase";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param attributeSet
|
||||||
|
* A collection of attributes which includes the desired MapGenerator.
|
||||||
|
* @return a new MapGenerator instance.
|
||||||
|
*/
|
||||||
|
public static IMapDatabase createMapDatabase(AttributeSet attributeSet) {
|
||||||
|
String mapDatabaseName = attributeSet.getAttributeValue(null, MAP_DATABASE_ATTRIBUTE_NAME);
|
||||||
|
if (mapDatabaseName == null) {
|
||||||
|
return new org.mapsforge.mapdatabase.mapfile.MapDatabase();
|
||||||
|
}
|
||||||
|
|
||||||
|
MapDatabaseInternal mapDatabaseInternal = MapDatabaseInternal.valueOf(mapDatabaseName);
|
||||||
|
return MapDatabaseFactory.createMapDatabase(mapDatabaseInternal);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param mapDatabaseInternal
|
||||||
|
* the internal MapDatabase implementation.
|
||||||
|
* @return a new MapGenerator instance.
|
||||||
|
*/
|
||||||
|
public static IMapDatabase createMapDatabase(MapDatabaseInternal mapDatabaseInternal) {
|
||||||
|
switch (mapDatabaseInternal) {
|
||||||
|
case MAP_READER:
|
||||||
|
return new org.mapsforge.mapdatabase.mapfile.MapDatabase();
|
||||||
|
case JSON_READER:
|
||||||
|
return new org.mapsforge.mapdatabase.json.MapDatabase();
|
||||||
|
case POSTGIS_READER:
|
||||||
|
return new org.mapsforge.mapdatabase.postgis.MapDatabase();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new IllegalArgumentException("unknown enum value: " + mapDatabaseInternal);
|
||||||
|
}
|
||||||
|
|
||||||
|
private MapDatabaseFactory() {
|
||||||
|
throw new IllegalStateException();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,36 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010, 2011, 2012 mapsforge.org
|
||||||
|
*
|
||||||
|
* 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.mapsforge.android.mapgenerator;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* MapDatabase Implementations
|
||||||
|
*/
|
||||||
|
public enum MapDatabaseInternal {
|
||||||
|
/**
|
||||||
|
* ...
|
||||||
|
*/
|
||||||
|
MAP_READER,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ...
|
||||||
|
*/
|
||||||
|
JSON_READER,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ...
|
||||||
|
*/
|
||||||
|
POSTGIS_READER,
|
||||||
|
|
||||||
|
}
|
||||||
72
src/org/mapsforge/android/mapgenerator/MapGenerator.java
Normal file
72
src/org/mapsforge/android/mapgenerator/MapGenerator.java
Normal file
@@ -0,0 +1,72 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010, 2011, 2012 mapsforge.org
|
||||||
|
*
|
||||||
|
* 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.mapsforge.android.mapgenerator;
|
||||||
|
|
||||||
|
import org.mapsforge.android.MapRenderer;
|
||||||
|
import org.mapsforge.android.MapView;
|
||||||
|
import org.mapsforge.core.GeoPoint;
|
||||||
|
import org.mapsforge.mapdatabase.IMapDatabase;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A MapGenerator provides map tiles either by downloading or rendering them.
|
||||||
|
*/
|
||||||
|
public interface MapGenerator {
|
||||||
|
/**
|
||||||
|
* Called once at the end of the MapGenerator lifecycle.
|
||||||
|
*/
|
||||||
|
void cleanup();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called when a job needs to be executed.
|
||||||
|
*
|
||||||
|
* @param mapGeneratorJob
|
||||||
|
* the job that should be executed.
|
||||||
|
* @return true if the job was executed successfully, false otherwise.
|
||||||
|
*/
|
||||||
|
boolean executeJob(MapGeneratorJob mapGeneratorJob);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the start point of this MapGenerator (may be null).
|
||||||
|
*/
|
||||||
|
GeoPoint getStartPoint();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the start zoom level of this MapGenerator (may be null).
|
||||||
|
*/
|
||||||
|
Byte getStartZoomLevel();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the maximum zoom level that this MapGenerator supports.
|
||||||
|
*/
|
||||||
|
byte getZoomLevelMax();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return true if this MapGenerator requires an Internet connection, false otherwise.
|
||||||
|
*/
|
||||||
|
boolean requiresInternetConnection();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param mapView
|
||||||
|
* the MapView
|
||||||
|
* @return GLSurfaceView Renderer
|
||||||
|
*/
|
||||||
|
MapRenderer getMapRenderer(MapView mapView);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param mapDatabase
|
||||||
|
* the MapDatabase from which the map data will be read.
|
||||||
|
*/
|
||||||
|
void setMapDatabase(IMapDatabase mapDatabase);
|
||||||
|
}
|
||||||
@@ -0,0 +1,59 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010, 2011, 2012 mapsforge.org
|
||||||
|
*
|
||||||
|
* 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.mapsforge.android.mapgenerator;
|
||||||
|
|
||||||
|
import android.util.AttributeSet;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A factory for the internal MapGenerator implementations.
|
||||||
|
*/
|
||||||
|
public final class MapGeneratorFactory {
|
||||||
|
private static final String MAP_GENERATOR_ATTRIBUTE_NAME = "mapGenerator";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param attributeSet
|
||||||
|
* A collection of attributes which includes the desired MapGenerator.
|
||||||
|
* @return a new MapGenerator instance.
|
||||||
|
*/
|
||||||
|
public static MapGenerator createMapGenerator(AttributeSet attributeSet) {
|
||||||
|
String mapGeneratorName = attributeSet.getAttributeValue(null, MAP_GENERATOR_ATTRIBUTE_NAME);
|
||||||
|
if (mapGeneratorName == null) {
|
||||||
|
return new org.mapsforge.android.glrenderer.DatabaseRenderer();
|
||||||
|
}
|
||||||
|
|
||||||
|
MapGeneratorInternal mapGeneratorInternal = MapGeneratorInternal.valueOf(mapGeneratorName);
|
||||||
|
return MapGeneratorFactory.createMapGenerator(mapGeneratorInternal);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param mapGeneratorInternal
|
||||||
|
* the internal MapGenerator implementation.
|
||||||
|
* @return a new MapGenerator instance.
|
||||||
|
*/
|
||||||
|
public static MapGenerator createMapGenerator(MapGeneratorInternal mapGeneratorInternal) {
|
||||||
|
switch (mapGeneratorInternal) {
|
||||||
|
case SW_RENDERER:
|
||||||
|
return new org.mapsforge.android.swrenderer.DatabaseRenderer();
|
||||||
|
case GL_RENDERER:
|
||||||
|
return new org.mapsforge.android.glrenderer.DatabaseRenderer();
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new IllegalArgumentException("unknown enum value: " + mapGeneratorInternal);
|
||||||
|
}
|
||||||
|
|
||||||
|
private MapGeneratorFactory() {
|
||||||
|
throw new IllegalStateException();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010, 2011, 2012 mapsforge.org
|
||||||
|
*
|
||||||
|
* 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.mapsforge.android.mapgenerator;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Enumeration of all internal MapGenerator implementations.
|
||||||
|
*/
|
||||||
|
public enum MapGeneratorInternal {
|
||||||
|
/**
|
||||||
|
* texture renderer.
|
||||||
|
*/
|
||||||
|
SW_RENDERER,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* opengl renderer.
|
||||||
|
*/
|
||||||
|
GL_RENDERER
|
||||||
|
}
|
||||||
188
src/org/mapsforge/android/mapgenerator/MapGeneratorJob.java
Normal file
188
src/org/mapsforge/android/mapgenerator/MapGeneratorJob.java
Normal file
@@ -0,0 +1,188 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010, 2011, 2012 mapsforge.org
|
||||||
|
*
|
||||||
|
* 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.mapsforge.android.mapgenerator;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.ObjectInputStream;
|
||||||
|
import java.io.Serializable;
|
||||||
|
|
||||||
|
import org.mapsforge.android.DebugSettings;
|
||||||
|
|
||||||
|
import android.graphics.Bitmap;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A MapGeneratorJob holds all immutable rendering parameters for a single map image together with a mutable priority
|
||||||
|
* field, which indicates the importance of this job.
|
||||||
|
*/
|
||||||
|
public class MapGeneratorJob implements Comparable<MapGeneratorJob>, Serializable {
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The debug settings for this job.
|
||||||
|
*/
|
||||||
|
public final DebugSettings debugSettings;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The rendering parameters for this job.
|
||||||
|
*/
|
||||||
|
public final JobParameters jobParameters;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The tile which should be generated.
|
||||||
|
*/
|
||||||
|
public final MapTile tile;
|
||||||
|
|
||||||
|
private transient int mHashCodeValue;
|
||||||
|
private final MapGenerator mMapGenerator;
|
||||||
|
private transient double mPriority;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* bitmap passed to renderer
|
||||||
|
*/
|
||||||
|
private Bitmap mBitmap;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return ...
|
||||||
|
*/
|
||||||
|
public Bitmap getBitmap() {
|
||||||
|
return mBitmap;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param bitmap
|
||||||
|
* ..
|
||||||
|
*/
|
||||||
|
public void setBitmap(Bitmap bitmap) {
|
||||||
|
mBitmap = bitmap;
|
||||||
|
}
|
||||||
|
|
||||||
|
private float mScale;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return scale the tile is rendered with
|
||||||
|
*/
|
||||||
|
public float getScale() {
|
||||||
|
return mScale;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param _scale
|
||||||
|
* for the tile to be rendered
|
||||||
|
*/
|
||||||
|
public void setScale(float _scale) {
|
||||||
|
mScale = _scale;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new job for a MapGenerator with the given parameters.
|
||||||
|
*
|
||||||
|
* @param _tile
|
||||||
|
* the tile which should be generated.
|
||||||
|
* @param mapGenerator
|
||||||
|
* the MapGenerator for this job.
|
||||||
|
* @param _jobParameters
|
||||||
|
* the rendering parameters for this job.
|
||||||
|
* @param _debugSettings
|
||||||
|
* the debug settings for this job.
|
||||||
|
*/
|
||||||
|
public MapGeneratorJob(MapTile _tile, MapGenerator mapGenerator,
|
||||||
|
JobParameters _jobParameters, DebugSettings _debugSettings) {
|
||||||
|
tile = _tile;
|
||||||
|
mMapGenerator = mapGenerator;
|
||||||
|
jobParameters = _jobParameters;
|
||||||
|
debugSettings = _debugSettings;
|
||||||
|
calculateTransientValues();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int compareTo(MapGeneratorJob o) {
|
||||||
|
if (mPriority < o.mPriority) {
|
||||||
|
return -1;
|
||||||
|
} else if (mPriority > o.mPriority) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object obj) {
|
||||||
|
if (this == obj) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (!(obj instanceof MapGeneratorJob)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
MapGeneratorJob other = (MapGeneratorJob) obj;
|
||||||
|
|
||||||
|
if (debugSettings == null) {
|
||||||
|
if (other.debugSettings != null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} else if (!debugSettings.equals(other.debugSettings)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (jobParameters == null) {
|
||||||
|
if (other.jobParameters != null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} else if (!jobParameters.equals(other.jobParameters)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (mMapGenerator != other.mMapGenerator) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (tile == null) {
|
||||||
|
if (other.tile != null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} else if (!tile.equals(other.tile)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return mHashCodeValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the hash code of this object.
|
||||||
|
*/
|
||||||
|
private int calculateHashCode() {
|
||||||
|
int result = 1;
|
||||||
|
result = 31 * result + ((debugSettings == null) ? 0 : debugSettings.hashCode());
|
||||||
|
result = 31 * result + ((jobParameters == null) ? 0 : jobParameters.hashCode());
|
||||||
|
result = 31 * result + ((mMapGenerator == null) ? 0 : mMapGenerator.hashCode());
|
||||||
|
result = 31 * result + ((tile == null) ? 0 : tile.hashCode());
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calculates the values of some transient variables.
|
||||||
|
*/
|
||||||
|
private void calculateTransientValues() {
|
||||||
|
mHashCodeValue = calculateHashCode();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void readObject(ObjectInputStream objectInputStream) throws IOException, ClassNotFoundException {
|
||||||
|
objectInputStream.defaultReadObject();
|
||||||
|
calculateTransientValues();
|
||||||
|
}
|
||||||
|
|
||||||
|
void setPriority(double priority) {
|
||||||
|
mPriority = priority;
|
||||||
|
}
|
||||||
|
}
|
||||||
59
src/org/mapsforge/android/mapgenerator/MapTile.java
Normal file
59
src/org/mapsforge/android/mapgenerator/MapTile.java
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2012 Hannes Janetzek
|
||||||
|
*
|
||||||
|
* 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.mapsforge.android.mapgenerator;
|
||||||
|
|
||||||
|
import org.mapsforge.core.Tile;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class MapTile extends Tile {
|
||||||
|
/**
|
||||||
|
* tile is loaded and ready for drawing. (set and used by render thread).
|
||||||
|
*/
|
||||||
|
public boolean isDrawn;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* tile is removed from JobQueue and loading in DatabaseRenderer. set by MapWorker.
|
||||||
|
*/
|
||||||
|
public boolean isLoading;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* tile is in view region. (set and used by render thread)
|
||||||
|
*/
|
||||||
|
public boolean isVisible;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* tile is used by render thread. set by updateVisibleList (main thread).
|
||||||
|
*/
|
||||||
|
public boolean isActive;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* distance from center, used in TileScheduler set by updateVisibleList.
|
||||||
|
*/
|
||||||
|
public long distance;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param tileX
|
||||||
|
* ...
|
||||||
|
* @param tileY
|
||||||
|
* ...
|
||||||
|
* @param zoomLevel
|
||||||
|
* ..
|
||||||
|
*/
|
||||||
|
public MapTile(long tileX, long tileY, byte zoomLevel) {
|
||||||
|
super(tileX, tileY, zoomLevel);
|
||||||
|
}
|
||||||
|
}
|
||||||
90
src/org/mapsforge/android/mapgenerator/MapWorker.java
Normal file
90
src/org/mapsforge/android/mapgenerator/MapWorker.java
Normal file
@@ -0,0 +1,90 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010, 2011, 2012 mapsforge.org
|
||||||
|
*
|
||||||
|
* 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.mapsforge.android.mapgenerator;
|
||||||
|
|
||||||
|
import org.mapsforge.android.MapRenderer;
|
||||||
|
import org.mapsforge.android.MapView;
|
||||||
|
import org.mapsforge.android.utils.PausableThread;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A MapWorker uses a {@link MapGenerator} to generate map tiles. It runs in a separate thread to avoid blocking the UI
|
||||||
|
* thread.
|
||||||
|
*/
|
||||||
|
public class MapWorker extends PausableThread {
|
||||||
|
private static final String THREAD_NAME = "MapWorker";
|
||||||
|
|
||||||
|
private final JobQueue mJobQueue;
|
||||||
|
private MapGenerator mMapGenerator;
|
||||||
|
private MapRenderer mMapRenderer;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param mapView
|
||||||
|
* the MapView for which this MapWorker generates map tiles.
|
||||||
|
*/
|
||||||
|
public MapWorker(MapView mapView) {
|
||||||
|
super();
|
||||||
|
mJobQueue = mapView.getJobQueue();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param mapGenerator
|
||||||
|
* the MapGenerator which this MapWorker should use.
|
||||||
|
*/
|
||||||
|
public void setMapGenerator(MapGenerator mapGenerator) {
|
||||||
|
mMapGenerator = mapGenerator;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param mapRenderer
|
||||||
|
* the MapRenderer
|
||||||
|
*/
|
||||||
|
public void setMapRenderer(MapRenderer mapRenderer) {
|
||||||
|
mMapRenderer = mapRenderer;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void afterRun() {
|
||||||
|
// empty
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void doWork() {
|
||||||
|
MapGeneratorJob mapGeneratorJob = mJobQueue.poll();
|
||||||
|
|
||||||
|
if (mMapGenerator == null || mapGeneratorJob == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
boolean success = mMapGenerator.executeJob(mapGeneratorJob);
|
||||||
|
|
||||||
|
if (!isInterrupted() && success) {
|
||||||
|
mMapRenderer.passTile(mapGeneratorJob);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected String getThreadName() {
|
||||||
|
return THREAD_NAME;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected int getThreadPriority() {
|
||||||
|
return (Thread.NORM_PRIORITY + Thread.MIN_PRIORITY) / 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected boolean hasWork() {
|
||||||
|
return !mJobQueue.isEmpty() && mMapRenderer.processedTile();
|
||||||
|
}
|
||||||
|
}
|
||||||
84
src/org/mapsforge/android/mapgenerator/TileCacheKey.java
Normal file
84
src/org/mapsforge/android/mapgenerator/TileCacheKey.java
Normal file
@@ -0,0 +1,84 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010, 2011, 2012 mapsforge.org
|
||||||
|
*
|
||||||
|
* 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.mapsforge.android.mapgenerator;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author jeff
|
||||||
|
*/
|
||||||
|
public class TileCacheKey {
|
||||||
|
long x, y;
|
||||||
|
byte z;
|
||||||
|
int hash;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public TileCacheKey() {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param key
|
||||||
|
* create new TileCacheKey for key
|
||||||
|
*/
|
||||||
|
public TileCacheKey(TileCacheKey key) {
|
||||||
|
this.x = key.x;
|
||||||
|
this.y = key.y;
|
||||||
|
this.z = key.z;
|
||||||
|
this.hash = key.hash;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param x
|
||||||
|
* Position
|
||||||
|
* @param y
|
||||||
|
* Position
|
||||||
|
* @param z
|
||||||
|
* Position
|
||||||
|
*/
|
||||||
|
public TileCacheKey(long x, long y, byte z) {
|
||||||
|
this.x = x;
|
||||||
|
this.y = y;
|
||||||
|
this.z = z;
|
||||||
|
hash = 7 * z + 31 * ((int) (x ^ (x >>> 32)) + 31 * (int) (y ^ (y >>> 32)));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param x
|
||||||
|
* Position
|
||||||
|
* @param y
|
||||||
|
* Position
|
||||||
|
* @param z
|
||||||
|
* Position
|
||||||
|
* @return self
|
||||||
|
*/
|
||||||
|
public TileCacheKey set(long x, long y, byte z) {
|
||||||
|
this.x = x;
|
||||||
|
this.y = y;
|
||||||
|
this.z = z;
|
||||||
|
hash = 7 * z + 31 * ((int) (x ^ (x >>> 32)) + 31 * (int) (y ^ (y >>> 32)));
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object obj) {
|
||||||
|
TileCacheKey other = (TileCacheKey) obj;
|
||||||
|
return (x == other.x && y == other.y && z == other.z);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return hash;
|
||||||
|
}
|
||||||
|
}
|
||||||
32
src/org/mapsforge/android/mapgenerator/TileDistanceSort.java
Normal file
32
src/org/mapsforge/android/mapgenerator/TileDistanceSort.java
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010, 2011, 2012 mapsforge.org
|
||||||
|
*
|
||||||
|
* 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.mapsforge.android.mapgenerator;
|
||||||
|
|
||||||
|
import java.util.Comparator;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class TileDistanceSort implements Comparator<MapTile> {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int compare(MapTile tile1, MapTile tile2) {
|
||||||
|
if (tile1.distance == tile2.distance)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
return tile1.distance > tile2.distance ? 1 : -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
68
src/org/mapsforge/android/mapgenerator/TileScheduler.java
Normal file
68
src/org/mapsforge/android/mapgenerator/TileScheduler.java
Normal file
@@ -0,0 +1,68 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010, 2011, 2012 mapsforge.org
|
||||||
|
*
|
||||||
|
* 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.mapsforge.android.mapgenerator;
|
||||||
|
|
||||||
|
import org.mapsforge.android.MapView;
|
||||||
|
import org.mapsforge.core.MapPosition;
|
||||||
|
|
||||||
|
final class TileScheduler {
|
||||||
|
|
||||||
|
static long time;
|
||||||
|
static MapPosition mapPosition;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calculates the priority for the given tile based on the current position and zoom level of the supplied MapView.
|
||||||
|
* The smaller the distance from the tile center to the MapView center, the higher its priority. If the zoom level
|
||||||
|
* of a tile differs from the zoom level of the MapView, its priority decreases.
|
||||||
|
*
|
||||||
|
* @param mapGeneratorJob
|
||||||
|
* the tile whose priority should be calculated.
|
||||||
|
* @param mapView
|
||||||
|
* the MapView whose current position and zoom level define the priority of the tile.
|
||||||
|
* @return the current priority of the tile. A smaller number means a higher priority.
|
||||||
|
*/
|
||||||
|
static double getPriority(MapGeneratorJob mapGeneratorJob, MapView mapView) {
|
||||||
|
MapTile tile = mapGeneratorJob.tile;
|
||||||
|
|
||||||
|
// if (tile.isDrawn) {
|
||||||
|
// long diff = time - tile.loadTime;
|
||||||
|
//
|
||||||
|
// // check.. just in case
|
||||||
|
// if (diff > 0.0) {
|
||||||
|
// return (10000.0f / diff) * (tile.isVisible ? 1 : 5); // * tile.distance;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// // calculate the center coordinates of the tile
|
||||||
|
// double tileCenterLongitude = MercatorProjection.pixelXToLongitude(tile.getCenterX(), tileZoomLevel);
|
||||||
|
// double tileCenterLatitude = MercatorProjection.pixelYToLatitude(tile.getCenterY(), tileZoomLevel);
|
||||||
|
//
|
||||||
|
// // calculate the Euclidian distance from the MapView center to the tile
|
||||||
|
// // center
|
||||||
|
// GeoPoint geoPoint = mapPosition.geoPoint;
|
||||||
|
// double longitudeDiff = geoPoint.getLongitude() - tileCenterLongitude;
|
||||||
|
// double latitudeDiff = geoPoint.getLatitude() - tileCenterLatitude;
|
||||||
|
//
|
||||||
|
// return Math.sqrt(longitudeDiff * longitudeDiff + latitudeDiff * latitudeDiff)
|
||||||
|
// * (tile.visible ? 1.0 : 1000.0);
|
||||||
|
// }
|
||||||
|
|
||||||
|
return tile.distance / 1000.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
private TileScheduler() {
|
||||||
|
throw new IllegalStateException();
|
||||||
|
}
|
||||||
|
}
|
||||||
31
src/org/mapsforge/android/package-info.java
Normal file
31
src/org/mapsforge/android/package-info.java
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010, 2011, 2012 mapsforge.org
|
||||||
|
*
|
||||||
|
* 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/>.
|
||||||
|
*/
|
||||||
|
/**
|
||||||
|
* The mapsforge-map library allows applications to render and display a map without Internet connection. It can
|
||||||
|
* be used on all Android devices running version 1.5 or higher. An application needs to extend the
|
||||||
|
* {@link org.mapsforge.android.MapActivity} class in order to use a
|
||||||
|
* {@link org.mapsforge.android.MapView}. More than one MapView instance may be used simultaneously.
|
||||||
|
* <p>
|
||||||
|
* The most important classes and methods from the <a href="http://code.google.com/android/add-ons/google-apis/"
|
||||||
|
* target="_top">Google APIs Add-On</a> are implemented. However, no API key is required and no abstract methods
|
||||||
|
* must be overridden.
|
||||||
|
* <p>
|
||||||
|
* This software is a part of the <a href="http://mapsforge.org/" target="_top">mapsforge</a> project and
|
||||||
|
* distributed under the <a href="http://www.gnu.org/licenses/lgpl.html" target="_top">LGPL3 license</a>. All
|
||||||
|
* map data (c) <a href="http://www.openstreetmap.org/" target="_top">OpenStreetMap</a> contributors, <a
|
||||||
|
* href="http://creativecommons.org/licenses/by-sa/2.0/" target="_top">CC-BY-SA license</a>.
|
||||||
|
*/
|
||||||
|
package org.mapsforge.android;
|
||||||
|
|
||||||
62
src/org/mapsforge/android/rendertheme/AnyMatcher.java
Normal file
62
src/org/mapsforge/android/rendertheme/AnyMatcher.java
Normal file
@@ -0,0 +1,62 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010, 2011, 2012 mapsforge.org
|
||||||
|
*
|
||||||
|
* 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.mapsforge.android.rendertheme;
|
||||||
|
|
||||||
|
import org.mapsforge.core.Tag;
|
||||||
|
|
||||||
|
final class AnyMatcher implements ElementMatcher, AttributeMatcher, ClosedMatcher {
|
||||||
|
private static final AnyMatcher INSTANCE = new AnyMatcher();
|
||||||
|
|
||||||
|
static AnyMatcher getInstance() {
|
||||||
|
return INSTANCE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Private constructor to prevent instantiation from other classes.
|
||||||
|
*/
|
||||||
|
private AnyMatcher() {
|
||||||
|
// do nothing
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isCoveredBy(AttributeMatcher attributeMatcher) {
|
||||||
|
return attributeMatcher == this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isCoveredBy(ClosedMatcher closedMatcher) {
|
||||||
|
return closedMatcher == this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isCoveredBy(ElementMatcher elementMatcher) {
|
||||||
|
return elementMatcher == this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean matches(Closed closed) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean matches(Element element) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean matches(Tag[] tags) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
23
src/org/mapsforge/android/rendertheme/AttributeMatcher.java
Normal file
23
src/org/mapsforge/android/rendertheme/AttributeMatcher.java
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010, 2011, 2012 mapsforge.org
|
||||||
|
*
|
||||||
|
* 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.mapsforge.android.rendertheme;
|
||||||
|
|
||||||
|
import org.mapsforge.core.Tag;
|
||||||
|
|
||||||
|
interface AttributeMatcher {
|
||||||
|
boolean isCoveredBy(AttributeMatcher attributeMatcher);
|
||||||
|
|
||||||
|
boolean matches(Tag[] tags);
|
||||||
|
}
|
||||||
19
src/org/mapsforge/android/rendertheme/Closed.java
Normal file
19
src/org/mapsforge/android/rendertheme/Closed.java
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010, 2011, 2012 mapsforge.org
|
||||||
|
*
|
||||||
|
* 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.mapsforge.android.rendertheme;
|
||||||
|
|
||||||
|
enum Closed {
|
||||||
|
ANY, NO, YES;
|
||||||
|
}
|
||||||
21
src/org/mapsforge/android/rendertheme/ClosedMatcher.java
Normal file
21
src/org/mapsforge/android/rendertheme/ClosedMatcher.java
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010, 2011, 2012 mapsforge.org
|
||||||
|
*
|
||||||
|
* 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.mapsforge.android.rendertheme;
|
||||||
|
|
||||||
|
interface ClosedMatcher {
|
||||||
|
boolean isCoveredBy(ClosedMatcher closedMatcher);
|
||||||
|
|
||||||
|
boolean matches(Closed closed);
|
||||||
|
}
|
||||||
40
src/org/mapsforge/android/rendertheme/ClosedWayMatcher.java
Normal file
40
src/org/mapsforge/android/rendertheme/ClosedWayMatcher.java
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010, 2011, 2012 mapsforge.org
|
||||||
|
*
|
||||||
|
* 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.mapsforge.android.rendertheme;
|
||||||
|
|
||||||
|
final class ClosedWayMatcher implements ClosedMatcher {
|
||||||
|
private static final ClosedWayMatcher INSTANCE = new ClosedWayMatcher();
|
||||||
|
|
||||||
|
static ClosedWayMatcher getInstance() {
|
||||||
|
return INSTANCE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Private constructor to prevent instantiation from other classes.
|
||||||
|
*/
|
||||||
|
private ClosedWayMatcher() {
|
||||||
|
// do nothing
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isCoveredBy(ClosedMatcher closedMatcher) {
|
||||||
|
return closedMatcher.matches(Closed.YES);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean matches(Closed closed) {
|
||||||
|
return closed == Closed.YES;
|
||||||
|
}
|
||||||
|
}
|
||||||
19
src/org/mapsforge/android/rendertheme/Element.java
Normal file
19
src/org/mapsforge/android/rendertheme/Element.java
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010, 2011, 2012 mapsforge.org
|
||||||
|
*
|
||||||
|
* 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.mapsforge.android.rendertheme;
|
||||||
|
|
||||||
|
enum Element {
|
||||||
|
ANY, NODE, WAY;
|
||||||
|
}
|
||||||
21
src/org/mapsforge/android/rendertheme/ElementMatcher.java
Normal file
21
src/org/mapsforge/android/rendertheme/ElementMatcher.java
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010, 2011, 2012 mapsforge.org
|
||||||
|
*
|
||||||
|
* 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.mapsforge.android.rendertheme;
|
||||||
|
|
||||||
|
interface ElementMatcher {
|
||||||
|
boolean isCoveredBy(ElementMatcher elementMatcher);
|
||||||
|
|
||||||
|
boolean matches(Element element);
|
||||||
|
}
|
||||||
@@ -0,0 +1,40 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010, 2011, 2012 mapsforge.org
|
||||||
|
*
|
||||||
|
* 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.mapsforge.android.rendertheme;
|
||||||
|
|
||||||
|
final class ElementNodeMatcher implements ElementMatcher {
|
||||||
|
private static final ElementNodeMatcher INSTANCE = new ElementNodeMatcher();
|
||||||
|
|
||||||
|
static ElementNodeMatcher getInstance() {
|
||||||
|
return INSTANCE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Private constructor to prevent instantiation from other classes.
|
||||||
|
*/
|
||||||
|
private ElementNodeMatcher() {
|
||||||
|
// do nothing
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isCoveredBy(ElementMatcher elementMatcher) {
|
||||||
|
return elementMatcher.matches(Element.NODE);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean matches(Element element) {
|
||||||
|
return element == Element.NODE;
|
||||||
|
}
|
||||||
|
}
|
||||||
40
src/org/mapsforge/android/rendertheme/ElementWayMatcher.java
Normal file
40
src/org/mapsforge/android/rendertheme/ElementWayMatcher.java
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010, 2011, 2012 mapsforge.org
|
||||||
|
*
|
||||||
|
* 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.mapsforge.android.rendertheme;
|
||||||
|
|
||||||
|
final class ElementWayMatcher implements ElementMatcher {
|
||||||
|
private static final ElementWayMatcher INSTANCE = new ElementWayMatcher();
|
||||||
|
|
||||||
|
static ElementWayMatcher getInstance() {
|
||||||
|
return INSTANCE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Private constructor to prevent instantiation from other classes.
|
||||||
|
*/
|
||||||
|
private ElementWayMatcher() {
|
||||||
|
// do nothing
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isCoveredBy(ElementMatcher elementMatcher) {
|
||||||
|
return elementMatcher.matches(Element.WAY);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean matches(Element element) {
|
||||||
|
return element == Element.WAY;
|
||||||
|
}
|
||||||
|
}
|
||||||
109
src/org/mapsforge/android/rendertheme/ExternalRenderTheme.java
Normal file
109
src/org/mapsforge/android/rendertheme/ExternalRenderTheme.java
Normal file
@@ -0,0 +1,109 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010, 2011, 2012 mapsforge.org
|
||||||
|
*
|
||||||
|
* 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.mapsforge.android.rendertheme;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileInputStream;
|
||||||
|
import java.io.FileNotFoundException;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.io.ObjectInputStream;
|
||||||
|
|
||||||
|
import org.mapsforge.android.mapgenerator.JobTheme;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An ExternalRenderTheme allows for customizing the rendering style of the map via an XML file.
|
||||||
|
*/
|
||||||
|
public class ExternalRenderTheme implements JobTheme {
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
private final long mFileModificationDate;
|
||||||
|
private transient int mHashCodeValue;
|
||||||
|
private final String mRenderThemePath;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param renderThemePath
|
||||||
|
* the path to the XML render theme file.
|
||||||
|
* @throws FileNotFoundException
|
||||||
|
* if the file does not exist or cannot be read.
|
||||||
|
*/
|
||||||
|
public ExternalRenderTheme(String renderThemePath) throws FileNotFoundException {
|
||||||
|
File renderThemeFile = new File(renderThemePath);
|
||||||
|
if (!renderThemeFile.exists()) {
|
||||||
|
throw new FileNotFoundException("file does not exist: " + renderThemePath);
|
||||||
|
} else if (!renderThemeFile.isFile()) {
|
||||||
|
throw new FileNotFoundException("not a file: " + renderThemePath);
|
||||||
|
} else if (!renderThemeFile.canRead()) {
|
||||||
|
throw new FileNotFoundException("cannot read file: " + renderThemePath);
|
||||||
|
}
|
||||||
|
|
||||||
|
mFileModificationDate = renderThemeFile.lastModified();
|
||||||
|
if (mFileModificationDate == 0L) {
|
||||||
|
throw new FileNotFoundException("cannot read last modification time");
|
||||||
|
}
|
||||||
|
mRenderThemePath = renderThemePath;
|
||||||
|
calculateTransientValues();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object obj) {
|
||||||
|
if (this == obj) {
|
||||||
|
return true;
|
||||||
|
} else if (!(obj instanceof ExternalRenderTheme)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
ExternalRenderTheme other = (ExternalRenderTheme) obj;
|
||||||
|
if (mFileModificationDate != other.mFileModificationDate) {
|
||||||
|
return false;
|
||||||
|
} else if (mRenderThemePath == null && other.mRenderThemePath != null) {
|
||||||
|
return false;
|
||||||
|
} else if (mRenderThemePath != null && !mRenderThemePath.equals(other.mRenderThemePath)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public InputStream getRenderThemeAsStream() throws FileNotFoundException {
|
||||||
|
return new FileInputStream(mRenderThemePath);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return mHashCodeValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the hash code of this object.
|
||||||
|
*/
|
||||||
|
private int calculateHashCode() {
|
||||||
|
int result = 1;
|
||||||
|
result = 31 * result + (int) (mFileModificationDate ^ (mFileModificationDate >>> 32));
|
||||||
|
result = 31 * result + ((mRenderThemePath == null) ? 0 : mRenderThemePath.hashCode());
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calculates the values of some transient variables.
|
||||||
|
*/
|
||||||
|
private void calculateTransientValues() {
|
||||||
|
mHashCodeValue = calculateHashCode();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void readObject(ObjectInputStream objectInputStream) throws IOException, ClassNotFoundException {
|
||||||
|
objectInputStream.defaultReadObject();
|
||||||
|
calculateTransientValues();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,42 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010, 2011, 2012 mapsforge.org
|
||||||
|
*
|
||||||
|
* 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.mapsforge.android.rendertheme;
|
||||||
|
|
||||||
|
import java.io.InputStream;
|
||||||
|
|
||||||
|
import org.mapsforge.android.mapgenerator.JobTheme;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Enumeration of all internal rendering themes.
|
||||||
|
*/
|
||||||
|
public enum InternalRenderTheme implements JobTheme {
|
||||||
|
/**
|
||||||
|
* A rendering theme similar to the OpenStreetMap Osmarender style.
|
||||||
|
*
|
||||||
|
* @see <a href="http://wiki.openstreetmap.org/wiki/Osmarender">Osmarender</a>
|
||||||
|
*/
|
||||||
|
OSMARENDER("/org/mapsforge/android/rendertheme/osmarender/osmarender.xml");
|
||||||
|
|
||||||
|
private final String mPath;
|
||||||
|
|
||||||
|
private InternalRenderTheme(String path) {
|
||||||
|
mPath = path;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public InputStream getRenderThemeAsStream() {
|
||||||
|
return Thread.currentThread().getClass().getResourceAsStream(mPath);
|
||||||
|
}
|
||||||
|
}
|
||||||
40
src/org/mapsforge/android/rendertheme/LinearWayMatcher.java
Normal file
40
src/org/mapsforge/android/rendertheme/LinearWayMatcher.java
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010, 2011, 2012 mapsforge.org
|
||||||
|
*
|
||||||
|
* 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.mapsforge.android.rendertheme;
|
||||||
|
|
||||||
|
final class LinearWayMatcher implements ClosedMatcher {
|
||||||
|
private static final LinearWayMatcher INSTANCE = new LinearWayMatcher();
|
||||||
|
|
||||||
|
static LinearWayMatcher getInstance() {
|
||||||
|
return INSTANCE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Private constructor to prevent instantiation from other classes.
|
||||||
|
*/
|
||||||
|
private LinearWayMatcher() {
|
||||||
|
// do nothing
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isCoveredBy(ClosedMatcher closedMatcher) {
|
||||||
|
return closedMatcher.matches(Closed.NO);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean matches(Closed closed) {
|
||||||
|
return closed == Closed.NO;
|
||||||
|
}
|
||||||
|
}
|
||||||
79
src/org/mapsforge/android/rendertheme/MatchingCacheKey.java
Normal file
79
src/org/mapsforge/android/rendertheme/MatchingCacheKey.java
Normal file
@@ -0,0 +1,79 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010, 2011, 2012 mapsforge.org
|
||||||
|
*
|
||||||
|
* 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.mapsforge.android.rendertheme;
|
||||||
|
|
||||||
|
import org.mapsforge.core.Tag;
|
||||||
|
|
||||||
|
class MatchingCacheKey {
|
||||||
|
private final int mHashCodeValue;
|
||||||
|
final Tag[] mTags;
|
||||||
|
final byte mZoomLevel;
|
||||||
|
|
||||||
|
MatchingCacheKey(Tag[] tags, byte zoomLevel) {
|
||||||
|
mTags = tags;
|
||||||
|
mZoomLevel = zoomLevel;
|
||||||
|
mHashCodeValue = calculateHashCode();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object obj) {
|
||||||
|
if (this == obj) {
|
||||||
|
return true;
|
||||||
|
} else if (!(obj instanceof MatchingCacheKey)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
MatchingCacheKey other = (MatchingCacheKey) obj;
|
||||||
|
|
||||||
|
if (mZoomLevel != other.mZoomLevel)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (mTags == null) {
|
||||||
|
return (other.mTags == null);
|
||||||
|
} else if (other.mTags == null)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
int length = mTags.length;
|
||||||
|
if (length != other.mTags.length) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < length; i++)
|
||||||
|
if (mTags[i] != other.mTags[i])
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return mHashCodeValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the hash code of this object.
|
||||||
|
*/
|
||||||
|
private int calculateHashCode() {
|
||||||
|
int result = 7;
|
||||||
|
|
||||||
|
for (int i = 0, n = mTags.length; i < n; i++) {
|
||||||
|
if (mTags[i] == null) // FIXME
|
||||||
|
break;
|
||||||
|
result = 31 * result + mTags[i].hashCode();
|
||||||
|
}
|
||||||
|
result = 31 * result + mZoomLevel;
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
54
src/org/mapsforge/android/rendertheme/MultiKeyMatcher.java
Normal file
54
src/org/mapsforge/android/rendertheme/MultiKeyMatcher.java
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010, 2011, 2012 mapsforge.org
|
||||||
|
*
|
||||||
|
* 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.mapsforge.android.rendertheme;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.mapsforge.core.Tag;
|
||||||
|
|
||||||
|
class MultiKeyMatcher implements AttributeMatcher {
|
||||||
|
private final String[] mKeys;
|
||||||
|
|
||||||
|
MultiKeyMatcher(List<String> keys) {
|
||||||
|
mKeys = new String[keys.size()];
|
||||||
|
for (int i = 0, n = mKeys.length; i < n; ++i) {
|
||||||
|
mKeys[i] = keys.get(i).intern();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isCoveredBy(AttributeMatcher attributeMatcher) {
|
||||||
|
if (attributeMatcher == this) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
Tag[] tags = new Tag[mKeys.length];
|
||||||
|
int i = 0;
|
||||||
|
for (String key : mKeys) {
|
||||||
|
tags[i++] = new Tag(key, null);
|
||||||
|
}
|
||||||
|
return attributeMatcher.matches(tags);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean matches(Tag[] tags) {
|
||||||
|
for (Tag tag : tags)
|
||||||
|
for (String key : mKeys)
|
||||||
|
if (key == tag.key)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
54
src/org/mapsforge/android/rendertheme/MultiValueMatcher.java
Normal file
54
src/org/mapsforge/android/rendertheme/MultiValueMatcher.java
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010, 2011, 2012 mapsforge.org
|
||||||
|
*
|
||||||
|
* 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.mapsforge.android.rendertheme;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.mapsforge.core.Tag;
|
||||||
|
|
||||||
|
class MultiValueMatcher implements AttributeMatcher {
|
||||||
|
private final String[] mValues;
|
||||||
|
|
||||||
|
MultiValueMatcher(List<String> values) {
|
||||||
|
mValues = new String[values.size()];
|
||||||
|
for (int i = 0, n = mValues.length; i < n; ++i) {
|
||||||
|
mValues[i] = values.get(i).intern();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isCoveredBy(AttributeMatcher attributeMatcher) {
|
||||||
|
if (attributeMatcher == this) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
Tag[] tags = new Tag[mValues.length];
|
||||||
|
|
||||||
|
int i = 0;
|
||||||
|
for (String val : mValues) {
|
||||||
|
tags[i++] = new Tag(null, val);
|
||||||
|
}
|
||||||
|
return attributeMatcher.matches(tags);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean matches(Tag[] tags) {
|
||||||
|
for (Tag tag : tags)
|
||||||
|
for (String val : mValues)
|
||||||
|
if (val == tag.value)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
63
src/org/mapsforge/android/rendertheme/NegativeMatcher.java
Normal file
63
src/org/mapsforge/android/rendertheme/NegativeMatcher.java
Normal file
@@ -0,0 +1,63 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010, 2011, 2012 mapsforge.org
|
||||||
|
*
|
||||||
|
* 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.mapsforge.android.rendertheme;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.mapsforge.core.Tag;
|
||||||
|
|
||||||
|
class NegativeMatcher implements AttributeMatcher {
|
||||||
|
private final String[] mKeyList;
|
||||||
|
private final String[] mValueList;
|
||||||
|
|
||||||
|
NegativeMatcher(List<String> keyList, List<String> valueList) {
|
||||||
|
mKeyList = new String[keyList.size()];
|
||||||
|
for (int i = 0; i < mKeyList.length; i++)
|
||||||
|
mKeyList[i] = keyList.get(i).intern();
|
||||||
|
|
||||||
|
mValueList = new String[valueList.size()];
|
||||||
|
for (int i = 0; i < mValueList.length; i++)
|
||||||
|
mValueList[i] = valueList.get(i).intern();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isCoveredBy(AttributeMatcher attributeMatcher) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean matches(Tag[] tags) {
|
||||||
|
if (keyListDoesNotContainKeys(tags)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (Tag tag : tags) {
|
||||||
|
for (String value : mValueList)
|
||||||
|
if (value == tag.value)
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean keyListDoesNotContainKeys(Tag[] tags) {
|
||||||
|
for (Tag tag : tags) {
|
||||||
|
for (String key : mKeyList)
|
||||||
|
if (key == tag.key)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
42
src/org/mapsforge/android/rendertheme/NegativeRule.java
Normal file
42
src/org/mapsforge/android/rendertheme/NegativeRule.java
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010, 2011, 2012 mapsforge.org
|
||||||
|
*
|
||||||
|
* 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.mapsforge.android.rendertheme;
|
||||||
|
|
||||||
|
import org.mapsforge.core.Tag;
|
||||||
|
|
||||||
|
class NegativeRule extends Rule {
|
||||||
|
final AttributeMatcher mAttributeMatcher;
|
||||||
|
|
||||||
|
NegativeRule(ElementMatcher elementMatcher, ClosedMatcher closedMatcher, byte zoomMin, byte zoomMax,
|
||||||
|
AttributeMatcher attributeMatcher) {
|
||||||
|
super(elementMatcher, closedMatcher, zoomMin, zoomMax);
|
||||||
|
|
||||||
|
mAttributeMatcher = attributeMatcher;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
boolean matchesNode(Tag[] tags, byte zoomLevel) {
|
||||||
|
return mZoomMin <= zoomLevel && mZoomMax >= zoomLevel
|
||||||
|
&& (mElementMatcher == null || mElementMatcher.matches(Element.NODE))
|
||||||
|
&& mAttributeMatcher.matches(tags);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
boolean matchesWay(Tag[] tags, byte zoomLevel, Closed closed) {
|
||||||
|
return mZoomMin <= zoomLevel && mZoomMax >= zoomLevel
|
||||||
|
&& (mElementMatcher == null || mElementMatcher.matches(Element.WAY))
|
||||||
|
&& (mClosedMatcher == null || mClosedMatcher.matches(closed)) && mAttributeMatcher.matches(tags);
|
||||||
|
}
|
||||||
|
}
|
||||||
54
src/org/mapsforge/android/rendertheme/PositiveRule.java
Normal file
54
src/org/mapsforge/android/rendertheme/PositiveRule.java
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010, 2011, 2012 mapsforge.org
|
||||||
|
*
|
||||||
|
* 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.mapsforge.android.rendertheme;
|
||||||
|
|
||||||
|
import org.mapsforge.core.Tag;
|
||||||
|
|
||||||
|
class PositiveRule extends Rule {
|
||||||
|
final AttributeMatcher mKeyMatcher;
|
||||||
|
final AttributeMatcher mValueMatcher;
|
||||||
|
|
||||||
|
PositiveRule(ElementMatcher elementMatcher, ClosedMatcher closedMatcher, byte zoomMin, byte zoomMax,
|
||||||
|
AttributeMatcher keyMatcher, AttributeMatcher valueMatcher) {
|
||||||
|
super(elementMatcher, closedMatcher, zoomMin, zoomMax);
|
||||||
|
|
||||||
|
if (keyMatcher instanceof AnyMatcher)
|
||||||
|
mKeyMatcher = null;
|
||||||
|
else
|
||||||
|
mKeyMatcher = keyMatcher;
|
||||||
|
|
||||||
|
if (valueMatcher instanceof AnyMatcher)
|
||||||
|
mValueMatcher = null;
|
||||||
|
else
|
||||||
|
mValueMatcher = valueMatcher;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
boolean matchesNode(Tag[] tags, byte zoomLevel) {
|
||||||
|
return mZoomMin <= zoomLevel && mZoomMax >= zoomLevel
|
||||||
|
&& (mElementMatcher == null || mElementMatcher.matches(Element.NODE))
|
||||||
|
&& (mKeyMatcher == null || mKeyMatcher.matches(tags))
|
||||||
|
&& (mValueMatcher == null || mValueMatcher.matches(tags));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
boolean matchesWay(Tag[] tags, byte zoomLevel, Closed closed) {
|
||||||
|
return mZoomMin <= zoomLevel && mZoomMax >= zoomLevel
|
||||||
|
&& (mElementMatcher == null || mElementMatcher.matches(Element.WAY))
|
||||||
|
&& (mClosedMatcher == null || mClosedMatcher.matches(closed))
|
||||||
|
&& (mKeyMatcher == null || mKeyMatcher.matches(tags))
|
||||||
|
&& (mValueMatcher == null || mValueMatcher.matches(tags));
|
||||||
|
}
|
||||||
|
}
|
||||||
122
src/org/mapsforge/android/rendertheme/RenderCallback.java
Normal file
122
src/org/mapsforge/android/rendertheme/RenderCallback.java
Normal file
@@ -0,0 +1,122 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010, 2011, 2012 mapsforge.org
|
||||||
|
*
|
||||||
|
* 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.mapsforge.android.rendertheme;
|
||||||
|
|
||||||
|
import org.mapsforge.android.rendertheme.renderinstruction.Area;
|
||||||
|
import org.mapsforge.android.rendertheme.renderinstruction.Line;
|
||||||
|
|
||||||
|
import android.graphics.Bitmap;
|
||||||
|
import android.graphics.Paint;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Callback methods for rendering areas, ways and points of interest (POIs).
|
||||||
|
*/
|
||||||
|
public interface RenderCallback {
|
||||||
|
/**
|
||||||
|
* Renders an area with the given parameters.
|
||||||
|
*
|
||||||
|
* @param area
|
||||||
|
* ...
|
||||||
|
*/
|
||||||
|
void renderArea(Area area);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Renders an area caption with the given text.
|
||||||
|
*
|
||||||
|
* @param caption
|
||||||
|
* the text to be rendered.
|
||||||
|
* @param verticalOffset
|
||||||
|
* the vertical offset of the caption.
|
||||||
|
* @param paint
|
||||||
|
* the paint to be used for rendering the text.
|
||||||
|
* @param stroke
|
||||||
|
* an optional paint for the text casing (may be null).
|
||||||
|
*/
|
||||||
|
void renderAreaCaption(String caption, float verticalOffset, Paint paint, Paint stroke);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Renders an area symbol with the given bitmap.
|
||||||
|
*
|
||||||
|
* @param symbol
|
||||||
|
* the symbol to be rendered.
|
||||||
|
*/
|
||||||
|
void renderAreaSymbol(Bitmap symbol);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Renders a point of interest caption with the given text.
|
||||||
|
*
|
||||||
|
* @param caption
|
||||||
|
* the text to be rendered.
|
||||||
|
* @param verticalOffset
|
||||||
|
* the vertical offset of the caption.
|
||||||
|
* @param paint
|
||||||
|
* the paint to be used for rendering the text.
|
||||||
|
* @param stroke
|
||||||
|
* an optional paint for the text casing (may be null).
|
||||||
|
*/
|
||||||
|
void renderPointOfInterestCaption(String caption, float verticalOffset, Paint paint, Paint stroke);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Renders a point of interest circle with the given parameters.
|
||||||
|
*
|
||||||
|
* @param radius
|
||||||
|
* the radius of the circle.
|
||||||
|
* @param fill
|
||||||
|
* the paint to be used for rendering the circle.
|
||||||
|
* @param level
|
||||||
|
* the drawing level on which the circle should be rendered.
|
||||||
|
*/
|
||||||
|
void renderPointOfInterestCircle(float radius, Paint fill, int level);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Renders a point of interest symbol with the given bitmap.
|
||||||
|
*
|
||||||
|
* @param symbol
|
||||||
|
* the symbol to be rendered.
|
||||||
|
*/
|
||||||
|
void renderPointOfInterestSymbol(Bitmap symbol);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Renders a way with the given parameters.
|
||||||
|
*
|
||||||
|
* @param line
|
||||||
|
* ...
|
||||||
|
*/
|
||||||
|
void renderWay(Line line);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Renders a way with the given symbol along the way path.
|
||||||
|
*
|
||||||
|
* @param symbol
|
||||||
|
* the symbol to be rendered.
|
||||||
|
* @param alignCenter
|
||||||
|
* true if the symbol should be centered, false otherwise.
|
||||||
|
* @param repeat
|
||||||
|
* true if the symbol should be repeated, false otherwise.
|
||||||
|
*/
|
||||||
|
void renderWaySymbol(Bitmap symbol, boolean alignCenter, boolean repeat);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Renders a way with the given text along the way path.
|
||||||
|
*
|
||||||
|
* @param text
|
||||||
|
* the text to be rendered.
|
||||||
|
* @param paint
|
||||||
|
* the paint to be used for rendering the text.
|
||||||
|
* @param stroke
|
||||||
|
* an optional paint for the text casing (may be null).
|
||||||
|
*/
|
||||||
|
void renderWayText(String text, Paint paint, Paint stroke);
|
||||||
|
}
|
||||||
377
src/org/mapsforge/android/rendertheme/RenderTheme.java
Normal file
377
src/org/mapsforge/android/rendertheme/RenderTheme.java
Normal file
@@ -0,0 +1,377 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010, 2011, 2012 mapsforge.org
|
||||||
|
*
|
||||||
|
* 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.mapsforge.android.rendertheme;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.mapsforge.android.rendertheme.renderinstruction.Line;
|
||||||
|
import org.mapsforge.android.rendertheme.renderinstruction.RenderInstruction;
|
||||||
|
import org.mapsforge.core.LRUCache;
|
||||||
|
import org.mapsforge.core.Tag;
|
||||||
|
import org.xml.sax.Attributes;
|
||||||
|
|
||||||
|
import android.graphics.Color;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A RenderTheme defines how ways and nodes are drawn.
|
||||||
|
*/
|
||||||
|
public class RenderTheme {
|
||||||
|
private static final int MATCHING_CACHE_SIZE = 1024;
|
||||||
|
private static final int RENDER_THEME_VERSION = 1;
|
||||||
|
|
||||||
|
private static void validate(String elementName, Integer version, float baseStrokeWidth, float baseTextSize) {
|
||||||
|
if (version == null) {
|
||||||
|
throw new IllegalArgumentException("missing attribute version for element:" + elementName);
|
||||||
|
} else if (version.intValue() != RENDER_THEME_VERSION) {
|
||||||
|
throw new IllegalArgumentException("invalid render theme version:" + version);
|
||||||
|
} else if (baseStrokeWidth < 0) {
|
||||||
|
throw new IllegalArgumentException("base-stroke-width must not be negative: " + baseStrokeWidth);
|
||||||
|
} else if (baseTextSize < 0) {
|
||||||
|
throw new IllegalArgumentException("base-text-size must not be negative: " + baseTextSize);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static RenderTheme create(String elementName, Attributes attributes) {
|
||||||
|
Integer version = null;
|
||||||
|
int mapBackground = Color.WHITE;
|
||||||
|
float baseStrokeWidth = 1;
|
||||||
|
float baseTextSize = 1;
|
||||||
|
|
||||||
|
for (int i = 0; i < attributes.getLength(); ++i) {
|
||||||
|
String name = attributes.getLocalName(i);
|
||||||
|
String value = attributes.getValue(i);
|
||||||
|
|
||||||
|
if ("schemaLocation".equals(name)) {
|
||||||
|
continue;
|
||||||
|
} else if ("version".equals(name)) {
|
||||||
|
version = Integer.valueOf(Integer.parseInt(value));
|
||||||
|
} else if ("map-background".equals(name)) {
|
||||||
|
mapBackground = Color.parseColor(value);
|
||||||
|
} else if ("base-stroke-width".equals(name)) {
|
||||||
|
baseStrokeWidth = Float.parseFloat(value);
|
||||||
|
} else if ("base-text-size".equals(name)) {
|
||||||
|
baseTextSize = Float.parseFloat(value);
|
||||||
|
} else {
|
||||||
|
RenderThemeHandler.logUnknownAttribute(elementName, name, value, i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
validate(elementName, version, baseStrokeWidth, baseTextSize);
|
||||||
|
return new RenderTheme(mapBackground, baseStrokeWidth, baseTextSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
private final float mBaseStrokeWidth;
|
||||||
|
private final float mBaseTextSize;
|
||||||
|
private int mLevels;
|
||||||
|
private final int mMapBackground;
|
||||||
|
private final ArrayList<Rule> mRulesList;
|
||||||
|
|
||||||
|
private final LRUCache<MatchingCacheKey, RenderInstruction[]> mMatchingCacheNodes;
|
||||||
|
private final LRUCache<MatchingCacheKey, RenderInstruction[]> mMatchingCacheWay;
|
||||||
|
private final LRUCache<MatchingCacheKey, RenderInstruction[]> mMatchingCacheArea;
|
||||||
|
|
||||||
|
// private List<RenderInstruction> mMatchingListWay;
|
||||||
|
// private List<RenderInstruction> mMatchingListArea;
|
||||||
|
// private List<RenderInstruction> mMatchingListNode;
|
||||||
|
|
||||||
|
RenderTheme(int mapBackground, float baseStrokeWidth, float baseTextSize) {
|
||||||
|
mMapBackground = mapBackground;
|
||||||
|
mBaseStrokeWidth = baseStrokeWidth;
|
||||||
|
mBaseTextSize = baseTextSize;
|
||||||
|
mRulesList = new ArrayList<Rule>();
|
||||||
|
|
||||||
|
mMatchingCacheNodes = new LRUCache<MatchingCacheKey, RenderInstruction[]>(MATCHING_CACHE_SIZE);
|
||||||
|
mMatchingCacheWay = new LRUCache<MatchingCacheKey, RenderInstruction[]>(MATCHING_CACHE_SIZE);
|
||||||
|
mMatchingCacheArea = new LRUCache<MatchingCacheKey, RenderInstruction[]>(MATCHING_CACHE_SIZE);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Must be called when this RenderTheme gets destroyed to clean up and free resources.
|
||||||
|
*/
|
||||||
|
public void destroy() {
|
||||||
|
mMatchingCacheNodes.clear();
|
||||||
|
mMatchingCacheArea.clear();
|
||||||
|
mMatchingCacheWay.clear();
|
||||||
|
|
||||||
|
for (int i = 0, n = mRulesList.size(); i < n; ++i) {
|
||||||
|
mRulesList.get(i).onDestroy();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the number of distinct drawing levels required by this RenderTheme.
|
||||||
|
*/
|
||||||
|
public int getLevels() {
|
||||||
|
return mLevels;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the map background color of this RenderTheme.
|
||||||
|
* @see Color
|
||||||
|
*/
|
||||||
|
public int getMapBackground() {
|
||||||
|
return mMapBackground;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param renderCallback
|
||||||
|
* ...
|
||||||
|
* @param tags
|
||||||
|
* ...
|
||||||
|
* @param zoomLevel
|
||||||
|
* ...
|
||||||
|
*/
|
||||||
|
public void matchNode(RenderCallback renderCallback, Tag[] tags, byte zoomLevel) {
|
||||||
|
// List<RenderInstruction> matchingList = matchingListNode;
|
||||||
|
// MatchingCacheKey matchingCacheKey = matchingCacheKeyNode;
|
||||||
|
//
|
||||||
|
// if (!changed) {
|
||||||
|
// if (matchingList != null) {
|
||||||
|
// for (int i = 0, n = matchingList.size(); i < n; ++i) {
|
||||||
|
// matchingList.get(i).renderNode(renderCallback, tags);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// return;
|
||||||
|
// }
|
||||||
|
// matchingCacheKey = new MatchingCacheKey(tags, zoomLevel);
|
||||||
|
// matchingList = matchingCacheNodes.get(matchingCacheKey);
|
||||||
|
//
|
||||||
|
// if (matchingList != null) {
|
||||||
|
// // cache hit
|
||||||
|
// for (int i = 0, n = matchingList.size(); i < n; ++i) {
|
||||||
|
// matchingList.get(i).renderNode(renderCallback, tags);
|
||||||
|
// }
|
||||||
|
// } else {
|
||||||
|
// // cache miss
|
||||||
|
// matchingList = new ArrayList<RenderInstruction>();
|
||||||
|
// for (int i = 0, n = mRulesList.size(); i < n; ++i) {
|
||||||
|
// mRulesList.get(i).matchNode(renderCallback, tags, zoomLevel, matchingList);
|
||||||
|
// }
|
||||||
|
// matchingCacheNodes.put(matchingCacheKey, matchingList);
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// matchingListNode = matchingList;
|
||||||
|
// matchingCacheKeyNode = matchingCacheKey;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Scales the stroke width of this RenderTheme by the given factor.
|
||||||
|
*
|
||||||
|
* @param scaleFactor
|
||||||
|
* the factor by which the stroke width should be scaled.
|
||||||
|
*/
|
||||||
|
public void scaleStrokeWidth(float scaleFactor) {
|
||||||
|
for (int i = 0, n = mRulesList.size(); i < n; ++i) {
|
||||||
|
mRulesList.get(i).scaleStrokeWidth(scaleFactor * mBaseStrokeWidth);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Scales the text size of this RenderTheme by the given factor.
|
||||||
|
*
|
||||||
|
* @param scaleFactor
|
||||||
|
* the factor by which the text size should be scaled.
|
||||||
|
*/
|
||||||
|
public void scaleTextSize(float scaleFactor) {
|
||||||
|
for (int i = 0, n = mRulesList.size(); i < n; ++i) {
|
||||||
|
mRulesList.get(i).scaleTextSize(scaleFactor * mBaseTextSize);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private RenderInstruction[] mRenderInstructions = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Matches a way with the given parameters against this RenderTheme.
|
||||||
|
*
|
||||||
|
* @param renderCallback
|
||||||
|
* the callback implementation which will be executed on each match.
|
||||||
|
* @param tags
|
||||||
|
* the tags of the way.
|
||||||
|
* @param zoomLevel
|
||||||
|
* the zoom level at which the way should be matched.
|
||||||
|
* @param closed
|
||||||
|
* way is Closed
|
||||||
|
* @param changed
|
||||||
|
* ...
|
||||||
|
*/
|
||||||
|
public void matchWay(RenderCallback renderCallback, Tag[] tags, byte zoomLevel, boolean closed, boolean changed) {
|
||||||
|
RenderInstruction[] renderInstructions = null;
|
||||||
|
|
||||||
|
LRUCache<MatchingCacheKey, RenderInstruction[]> matchingCache;
|
||||||
|
MatchingCacheKey matchingCacheKey;
|
||||||
|
|
||||||
|
if (!changed) {
|
||||||
|
renderInstructions = mRenderInstructions;
|
||||||
|
|
||||||
|
if (renderInstructions != null) {
|
||||||
|
for (int i = 0, n = renderInstructions.length; i < n; i++)
|
||||||
|
renderInstructions[i].renderWay(renderCallback, tags);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (closed) {
|
||||||
|
matchingCache = mMatchingCacheArea;
|
||||||
|
} else {
|
||||||
|
matchingCache = mMatchingCacheWay;
|
||||||
|
}
|
||||||
|
|
||||||
|
matchingCacheKey = new MatchingCacheKey(tags, zoomLevel);
|
||||||
|
boolean found = matchingCache.containsKey(matchingCacheKey);
|
||||||
|
if (found) {
|
||||||
|
renderInstructions = matchingCache.get(matchingCacheKey);
|
||||||
|
|
||||||
|
if (renderInstructions != null) {
|
||||||
|
for (int i = 0, n = renderInstructions.length; i < n; i++)
|
||||||
|
renderInstructions[i].renderWay(renderCallback, tags);
|
||||||
|
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// cache miss
|
||||||
|
Closed c = (closed ? Closed.YES : Closed.NO);
|
||||||
|
List<RenderInstruction> matchingList = new ArrayList<RenderInstruction>(4);
|
||||||
|
for (int i = 0, n = mRulesList.size(); i < n; ++i) {
|
||||||
|
mRulesList.get(i).matchWay(renderCallback, tags, zoomLevel, c, matchingList);
|
||||||
|
}
|
||||||
|
int size = matchingList.size();
|
||||||
|
if (size > 0) {
|
||||||
|
renderInstructions = new RenderInstruction[matchingList.size()];
|
||||||
|
for (int i = 0, n = matchingList.size(); i < n; ++i) {
|
||||||
|
RenderInstruction renderInstruction = matchingList.get(i);
|
||||||
|
renderInstruction.renderWay(renderCallback, tags);
|
||||||
|
renderInstructions[i] = renderInstruction;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
matchingCache.put(matchingCacheKey, renderInstructions);
|
||||||
|
}
|
||||||
|
|
||||||
|
mRenderInstructions = renderInstructions;
|
||||||
|
|
||||||
|
// if (matchingList != null) {
|
||||||
|
// for (int i = 0, n = matchingList.size(); i < n; ++i) {
|
||||||
|
// matchingList.get(i).renderWay(renderCallback, tags);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// return renderInstructions;
|
||||||
|
|
||||||
|
// if (closed) {
|
||||||
|
// mMatchingListArea = matchingList;
|
||||||
|
// } else {
|
||||||
|
// mMatchingListWay = matchingList;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// if (mCompareKey.set(tags, zoomLevel, closed)) {
|
||||||
|
// // Log.d("mapsforge", "SAME AS BAFORE!!!" + tags);
|
||||||
|
// for (int i = 0, n = mInstructionList.length; i < n; ++i) {
|
||||||
|
// mInstructionList[i].renderWay(renderCallback, tags);
|
||||||
|
// }
|
||||||
|
// return;
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// SparseArray<RenderInstruction[]> matchingList = mMatchingCache.get(mCompareKey);
|
||||||
|
//
|
||||||
|
// if (matchingList != null) {
|
||||||
|
// mInstructionList = matchingList.get(zoomLevel);
|
||||||
|
// if (mInstructionList != null) {
|
||||||
|
// // cache hit
|
||||||
|
// // Log.d("mapsforge", "CCACHE HIT !!!" + tags);
|
||||||
|
// for (int i = 0, n = mInstructionList.length; i < n; ++i) {
|
||||||
|
// mInstructionList[i].renderWay(renderCallback, tags);
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// return;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// // Log.d("mapsforge", "CACHE MISS !!!" + tags);
|
||||||
|
// // cache miss
|
||||||
|
// ArrayList<RenderInstruction> instructionList = new ArrayList<RenderInstruction>();
|
||||||
|
//
|
||||||
|
// for (int i = 0, n = mRulesList.size(); i < n; ++i) {
|
||||||
|
// mRulesList.get(i).matchWay(renderCallback, mCompareKey.getTags(), zoomLevel, closed, instructionList);
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// boolean found = false;
|
||||||
|
// int size = instructionList.size();
|
||||||
|
//
|
||||||
|
// if (matchingList == null) {
|
||||||
|
// matchingList = new SparseArray<RenderInstruction[]>(25);
|
||||||
|
// MatchingCacheKey matchingCacheKey = new MatchingCacheKey(mCompareKey);
|
||||||
|
// mMatchingCache.put(matchingCacheKey, matchingList);
|
||||||
|
// } else {
|
||||||
|
// // check if another zoomLevel uses the same instructionList
|
||||||
|
// for (int i = 0, n = matchingList.size(); i < n; i++) {
|
||||||
|
// int key = matchingList.keyAt(i);
|
||||||
|
//
|
||||||
|
// RenderInstruction[] list2 = matchingList.get(key);
|
||||||
|
// if (list2.length != size)
|
||||||
|
// continue;
|
||||||
|
//
|
||||||
|
// int j = 0;
|
||||||
|
// while (j < size && (list2[j] == instructionList.get(j)))
|
||||||
|
// j++;
|
||||||
|
//
|
||||||
|
// if (j == size) {
|
||||||
|
// instructionList.clear();
|
||||||
|
// mInstructionList = list2;
|
||||||
|
// found = true;
|
||||||
|
// break;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// if (!found) {
|
||||||
|
// mInstructionList = new RenderInstruction[size];
|
||||||
|
// for (int i = 0; i < size; i++)
|
||||||
|
// mInstructionList[i] = instructionList.get(i);
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// for (int i = 0, n = mInstructionList.length; i < n; ++i)
|
||||||
|
// mInstructionList[i].renderWay(renderCallback, tags);
|
||||||
|
//
|
||||||
|
// matchingList.put(zoomLevel, mInstructionList);
|
||||||
|
}
|
||||||
|
|
||||||
|
void addRule(Rule rule) {
|
||||||
|
mRulesList.add(rule);
|
||||||
|
}
|
||||||
|
|
||||||
|
void complete() {
|
||||||
|
mRulesList.trimToSize();
|
||||||
|
for (int i = 0, n = mRulesList.size(); i < n; ++i) {
|
||||||
|
mRulesList.get(i).onComplete();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private final ArrayList<Line> outlineLayers = new ArrayList<Line>();
|
||||||
|
|
||||||
|
void addOutlineLayer(Line line) {
|
||||||
|
outlineLayers.add(line);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param layer
|
||||||
|
* ...
|
||||||
|
* @return Line (paint and level) used for outline
|
||||||
|
*/
|
||||||
|
public Line getOutline(int layer) {
|
||||||
|
return outlineLayers.get(layer);
|
||||||
|
}
|
||||||
|
|
||||||
|
void setLevels(int levels) {
|
||||||
|
mLevels = levels;
|
||||||
|
}
|
||||||
|
}
|
||||||
245
src/org/mapsforge/android/rendertheme/RenderThemeHandler.java
Normal file
245
src/org/mapsforge/android/rendertheme/RenderThemeHandler.java
Normal file
@@ -0,0 +1,245 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010, 2011, 2012 mapsforge.org
|
||||||
|
*
|
||||||
|
* 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.mapsforge.android.rendertheme;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.util.Stack;
|
||||||
|
import java.util.logging.Level;
|
||||||
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
|
import javax.xml.parsers.ParserConfigurationException;
|
||||||
|
import javax.xml.parsers.SAXParserFactory;
|
||||||
|
|
||||||
|
import org.mapsforge.android.rendertheme.renderinstruction.Area;
|
||||||
|
import org.mapsforge.android.rendertheme.renderinstruction.Caption;
|
||||||
|
import org.mapsforge.android.rendertheme.renderinstruction.Circle;
|
||||||
|
import org.mapsforge.android.rendertheme.renderinstruction.Line;
|
||||||
|
import org.mapsforge.android.rendertheme.renderinstruction.LineSymbol;
|
||||||
|
import org.mapsforge.android.rendertheme.renderinstruction.PathText;
|
||||||
|
import org.mapsforge.android.rendertheme.renderinstruction.Symbol;
|
||||||
|
import org.xml.sax.Attributes;
|
||||||
|
import org.xml.sax.InputSource;
|
||||||
|
import org.xml.sax.SAXException;
|
||||||
|
import org.xml.sax.SAXParseException;
|
||||||
|
import org.xml.sax.XMLReader;
|
||||||
|
import org.xml.sax.helpers.DefaultHandler;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* SAX2 handler to parse XML render theme files.
|
||||||
|
*/
|
||||||
|
public class RenderThemeHandler extends DefaultHandler {
|
||||||
|
private static final Logger LOG = Logger.getLogger(RenderThemeHandler.class.getName());
|
||||||
|
|
||||||
|
private static enum Element {
|
||||||
|
RENDER_THEME, RENDERING_INSTRUCTION, RULE;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final String ELEMENT_NAME_RENDER_THEME = "rendertheme";
|
||||||
|
private static final String ELEMENT_NAME_RULE = "rule";
|
||||||
|
private static final String UNEXPECTED_ELEMENT = "unexpected element: ";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param inputStream
|
||||||
|
* an input stream containing valid render theme XML data.
|
||||||
|
* @return a new RenderTheme which is created by parsing the XML data from the input stream.
|
||||||
|
* @throws SAXException
|
||||||
|
* if an error occurs while parsing the render theme XML.
|
||||||
|
* @throws ParserConfigurationException
|
||||||
|
* if an error occurs while creating the XML parser.
|
||||||
|
* @throws IOException
|
||||||
|
* if an I/O error occurs while reading from the input stream.
|
||||||
|
*/
|
||||||
|
public static RenderTheme getRenderTheme(InputStream inputStream) throws SAXException,
|
||||||
|
ParserConfigurationException, IOException {
|
||||||
|
RenderThemeHandler renderThemeHandler = new RenderThemeHandler();
|
||||||
|
XMLReader xmlReader = SAXParserFactory.newInstance().newSAXParser().getXMLReader();
|
||||||
|
xmlReader.setContentHandler(renderThemeHandler);
|
||||||
|
xmlReader.parse(new InputSource(inputStream));
|
||||||
|
return renderThemeHandler.mRenderTheme;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Logs the given information about an unknown XML attribute.
|
||||||
|
*
|
||||||
|
* @param element
|
||||||
|
* the XML element name.
|
||||||
|
* @param name
|
||||||
|
* the XML attribute name.
|
||||||
|
* @param value
|
||||||
|
* the XML attribute value.
|
||||||
|
* @param attributeIndex
|
||||||
|
* the XML attribute index position.
|
||||||
|
*/
|
||||||
|
public static void logUnknownAttribute(String element, String name, String value, int attributeIndex) {
|
||||||
|
StringBuilder stringBuilder = new StringBuilder();
|
||||||
|
stringBuilder.append("unknown attribute in element ");
|
||||||
|
stringBuilder.append(element);
|
||||||
|
stringBuilder.append(" (");
|
||||||
|
stringBuilder.append(attributeIndex);
|
||||||
|
stringBuilder.append("): ");
|
||||||
|
stringBuilder.append(name);
|
||||||
|
stringBuilder.append('=');
|
||||||
|
stringBuilder.append(value);
|
||||||
|
LOG.info(stringBuilder.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
private Rule mCurrentRule;
|
||||||
|
private final Stack<Element> mElementStack = new Stack<Element>();
|
||||||
|
private int mLevel;
|
||||||
|
private RenderTheme mRenderTheme;
|
||||||
|
private final Stack<Rule> mRuleStack = new Stack<Rule>();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void endDocument() {
|
||||||
|
if (mRenderTheme == null) {
|
||||||
|
throw new IllegalArgumentException("missing element: rules");
|
||||||
|
}
|
||||||
|
|
||||||
|
mRenderTheme.setLevels(mLevel);
|
||||||
|
mRenderTheme.complete();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void endElement(String uri, String localName, String qName) {
|
||||||
|
mElementStack.pop();
|
||||||
|
|
||||||
|
if (ELEMENT_NAME_RULE.equals(localName)) {
|
||||||
|
mRuleStack.pop();
|
||||||
|
if (mRuleStack.empty()) {
|
||||||
|
mRenderTheme.addRule(mCurrentRule);
|
||||||
|
} else {
|
||||||
|
mCurrentRule = mRuleStack.peek();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void error(SAXParseException exception) {
|
||||||
|
LOG.log(Level.SEVERE, null, exception);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
|
||||||
|
try {
|
||||||
|
if (ELEMENT_NAME_RENDER_THEME.equals(localName)) {
|
||||||
|
checkState(localName, Element.RENDER_THEME);
|
||||||
|
mRenderTheme = RenderTheme.create(localName, attributes);
|
||||||
|
}
|
||||||
|
|
||||||
|
else if (ELEMENT_NAME_RULE.equals(localName)) {
|
||||||
|
checkState(localName, Element.RULE);
|
||||||
|
Rule rule = Rule.create(localName, attributes, mRuleStack);
|
||||||
|
if (!mRuleStack.empty()) {
|
||||||
|
mCurrentRule.addSubRule(rule);
|
||||||
|
}
|
||||||
|
mCurrentRule = rule;
|
||||||
|
mRuleStack.push(mCurrentRule);
|
||||||
|
}
|
||||||
|
|
||||||
|
else if ("area".equals(localName)) {
|
||||||
|
checkState(localName, Element.RENDERING_INSTRUCTION);
|
||||||
|
Area area = Area.create(localName, attributes, mLevel++);
|
||||||
|
mRuleStack.peek().addRenderingInstruction(area);
|
||||||
|
}
|
||||||
|
|
||||||
|
else if ("caption".equals(localName)) {
|
||||||
|
checkState(localName, Element.RENDERING_INSTRUCTION);
|
||||||
|
Caption caption = Caption.create(localName, attributes);
|
||||||
|
mCurrentRule.addRenderingInstruction(caption);
|
||||||
|
}
|
||||||
|
|
||||||
|
else if ("circle".equals(localName)) {
|
||||||
|
checkState(localName, Element.RENDERING_INSTRUCTION);
|
||||||
|
Circle circle = Circle.create(localName, attributes, mLevel++);
|
||||||
|
mCurrentRule.addRenderingInstruction(circle);
|
||||||
|
}
|
||||||
|
|
||||||
|
else if ("line".equals(localName)) {
|
||||||
|
checkState(localName, Element.RENDERING_INSTRUCTION);
|
||||||
|
Line line = Line.create(localName, attributes, mLevel++);
|
||||||
|
mCurrentRule.addRenderingInstruction(line);
|
||||||
|
}
|
||||||
|
|
||||||
|
else if ("outline".equals(localName)) {
|
||||||
|
checkState(localName, Element.RENDERING_INSTRUCTION);
|
||||||
|
Line line = Line.create(localName, attributes, mLevel++);
|
||||||
|
mRenderTheme.addOutlineLayer(line);
|
||||||
|
// mCurrentRule.addRenderingInstruction(line);
|
||||||
|
}
|
||||||
|
|
||||||
|
else if ("lineSymbol".equals(localName)) {
|
||||||
|
checkState(localName, Element.RENDERING_INSTRUCTION);
|
||||||
|
LineSymbol lineSymbol = LineSymbol.create(localName, attributes);
|
||||||
|
mCurrentRule.addRenderingInstruction(lineSymbol);
|
||||||
|
}
|
||||||
|
|
||||||
|
else if ("pathText".equals(localName)) {
|
||||||
|
checkState(localName, Element.RENDERING_INSTRUCTION);
|
||||||
|
PathText pathText = PathText.create(localName, attributes);
|
||||||
|
mCurrentRule.addRenderingInstruction(pathText);
|
||||||
|
}
|
||||||
|
|
||||||
|
else if ("symbol".equals(localName)) {
|
||||||
|
checkState(localName, Element.RENDERING_INSTRUCTION);
|
||||||
|
Symbol symbol = Symbol.create(localName, attributes);
|
||||||
|
mCurrentRule.addRenderingInstruction(symbol);
|
||||||
|
}
|
||||||
|
|
||||||
|
else {
|
||||||
|
throw new SAXException("unknown element: " + localName);
|
||||||
|
}
|
||||||
|
} catch (IllegalArgumentException e) {
|
||||||
|
throw new SAXException(null, e);
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new SAXException(null, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void warning(SAXParseException exception) {
|
||||||
|
LOG.log(Level.SEVERE, null, exception);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void checkElement(String elementName, Element element) throws SAXException {
|
||||||
|
switch (element) {
|
||||||
|
case RENDER_THEME:
|
||||||
|
if (!mElementStack.empty()) {
|
||||||
|
throw new SAXException(UNEXPECTED_ELEMENT + elementName);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
|
||||||
|
case RULE:
|
||||||
|
Element parentElement = mElementStack.peek();
|
||||||
|
if (parentElement != Element.RENDER_THEME && parentElement != Element.RULE) {
|
||||||
|
throw new SAXException(UNEXPECTED_ELEMENT + elementName);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
|
||||||
|
case RENDERING_INSTRUCTION:
|
||||||
|
if (mElementStack.peek() != Element.RULE) {
|
||||||
|
throw new SAXException(UNEXPECTED_ELEMENT + elementName);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new SAXException("unknown enum value: " + element);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void checkState(String elementName, Element element) throws SAXException {
|
||||||
|
checkElement(elementName, element);
|
||||||
|
mElementStack.push(element);
|
||||||
|
}
|
||||||
|
}
|
||||||
287
src/org/mapsforge/android/rendertheme/Rule.java
Normal file
287
src/org/mapsforge/android/rendertheme/Rule.java
Normal file
@@ -0,0 +1,287 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010, 2011, 2012 mapsforge.org
|
||||||
|
*
|
||||||
|
* 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.mapsforge.android.rendertheme;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Locale;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Stack;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
|
import org.mapsforge.android.rendertheme.renderinstruction.RenderInstruction;
|
||||||
|
import org.mapsforge.core.Tag;
|
||||||
|
import org.xml.sax.Attributes;
|
||||||
|
|
||||||
|
abstract class Rule {
|
||||||
|
private static final Map<List<String>, AttributeMatcher> MATCHERS_CACHE_KEY = new HashMap<List<String>, AttributeMatcher>();
|
||||||
|
private static final Map<List<String>, AttributeMatcher> MATCHERS_CACHE_VALUE = new HashMap<List<String>, AttributeMatcher>();
|
||||||
|
private static final Pattern SPLIT_PATTERN = Pattern.compile("\\|");
|
||||||
|
private static final String STRING_NEGATION = "~";
|
||||||
|
private static final String STRING_WILDCARD = "*";
|
||||||
|
private static final String UNKNOWN_ENUM_VALUE = "unknown enum value: ";
|
||||||
|
|
||||||
|
private static Rule createRule(Stack<Rule> ruleStack, Element element, String keys, String values, Closed closed,
|
||||||
|
byte zoomMin, byte zoomMax) {
|
||||||
|
ElementMatcher elementMatcher = getElementMatcher(element);
|
||||||
|
ClosedMatcher closedMatcher = getClosedMatcher(closed);
|
||||||
|
List<String> keyList = new ArrayList<String>(Arrays.asList(SPLIT_PATTERN.split(keys)));
|
||||||
|
List<String> valueList = new ArrayList<String>(Arrays.asList(SPLIT_PATTERN.split(values)));
|
||||||
|
|
||||||
|
elementMatcher = RuleOptimizer.optimize(elementMatcher, ruleStack);
|
||||||
|
closedMatcher = RuleOptimizer.optimize(closedMatcher, ruleStack);
|
||||||
|
|
||||||
|
if (valueList.remove(STRING_NEGATION)) {
|
||||||
|
AttributeMatcher attributeMatcher = new NegativeMatcher(keyList, valueList);
|
||||||
|
return new NegativeRule(elementMatcher, closedMatcher, zoomMin, zoomMax, attributeMatcher);
|
||||||
|
}
|
||||||
|
|
||||||
|
AttributeMatcher keyMatcher = getKeyMatcher(keyList);
|
||||||
|
AttributeMatcher valueMatcher = getValueMatcher(valueList);
|
||||||
|
|
||||||
|
keyMatcher = RuleOptimizer.optimize(keyMatcher, ruleStack);
|
||||||
|
valueMatcher = RuleOptimizer.optimize(valueMatcher, ruleStack);
|
||||||
|
|
||||||
|
return new PositiveRule(elementMatcher, closedMatcher, zoomMin, zoomMax, keyMatcher, valueMatcher);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static ClosedMatcher getClosedMatcher(Closed closed) {
|
||||||
|
switch (closed) {
|
||||||
|
case YES:
|
||||||
|
return ClosedWayMatcher.getInstance();
|
||||||
|
case NO:
|
||||||
|
return LinearWayMatcher.getInstance();
|
||||||
|
case ANY:
|
||||||
|
return AnyMatcher.getInstance();
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new IllegalArgumentException(UNKNOWN_ENUM_VALUE + closed);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static ElementMatcher getElementMatcher(Element element) {
|
||||||
|
switch (element) {
|
||||||
|
case NODE:
|
||||||
|
return ElementNodeMatcher.getInstance();
|
||||||
|
case WAY:
|
||||||
|
return ElementWayMatcher.getInstance();
|
||||||
|
case ANY:
|
||||||
|
return AnyMatcher.getInstance();
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new IllegalArgumentException(UNKNOWN_ENUM_VALUE + element);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static AttributeMatcher getKeyMatcher(List<String> keyList) {
|
||||||
|
if (STRING_WILDCARD.equals(keyList.get(0))) {
|
||||||
|
return AnyMatcher.getInstance();
|
||||||
|
}
|
||||||
|
|
||||||
|
AttributeMatcher attributeMatcher = MATCHERS_CACHE_KEY.get(keyList);
|
||||||
|
if (attributeMatcher == null) {
|
||||||
|
if (keyList.size() == 1) {
|
||||||
|
attributeMatcher = new SingleKeyMatcher(keyList.get(0));
|
||||||
|
} else {
|
||||||
|
attributeMatcher = new MultiKeyMatcher(keyList);
|
||||||
|
}
|
||||||
|
MATCHERS_CACHE_KEY.put(keyList, attributeMatcher);
|
||||||
|
}
|
||||||
|
return attributeMatcher;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static AttributeMatcher getValueMatcher(List<String> valueList) {
|
||||||
|
if (STRING_WILDCARD.equals(valueList.get(0))) {
|
||||||
|
return AnyMatcher.getInstance();
|
||||||
|
}
|
||||||
|
|
||||||
|
AttributeMatcher attributeMatcher = MATCHERS_CACHE_VALUE.get(valueList);
|
||||||
|
if (attributeMatcher == null) {
|
||||||
|
if (valueList.size() == 1) {
|
||||||
|
attributeMatcher = new SingleValueMatcher(valueList.get(0));
|
||||||
|
} else {
|
||||||
|
attributeMatcher = new MultiValueMatcher(valueList);
|
||||||
|
}
|
||||||
|
MATCHERS_CACHE_VALUE.put(valueList, attributeMatcher);
|
||||||
|
}
|
||||||
|
return attributeMatcher;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void validate(String elementName, Element element, String keys, String values, byte zoomMin,
|
||||||
|
byte zoomMax) {
|
||||||
|
if (element == null) {
|
||||||
|
throw new IllegalArgumentException("missing attribute e for element: " + elementName);
|
||||||
|
} else if (keys == null) {
|
||||||
|
throw new IllegalArgumentException("missing attribute k for element: " + elementName);
|
||||||
|
} else if (values == null) {
|
||||||
|
throw new IllegalArgumentException("missing attribute v for element: " + elementName);
|
||||||
|
} else if (zoomMin < 0) {
|
||||||
|
throw new IllegalArgumentException("zoom-min must not be negative: " + zoomMin);
|
||||||
|
} else if (zoomMax < 0) {
|
||||||
|
throw new IllegalArgumentException("zoom-max must not be negative: " + zoomMax);
|
||||||
|
} else if (zoomMin > zoomMax) {
|
||||||
|
throw new IllegalArgumentException("zoom-min must be less or equal zoom-max: " + zoomMin);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static Rule create(String elementName, Attributes attributes, Stack<Rule> ruleStack) {
|
||||||
|
Element element = null;
|
||||||
|
String keys = null;
|
||||||
|
String values = null;
|
||||||
|
Closed closed = Closed.ANY;
|
||||||
|
byte zoomMin = 0;
|
||||||
|
byte zoomMax = Byte.MAX_VALUE;
|
||||||
|
|
||||||
|
for (int i = 0; i < attributes.getLength(); ++i) {
|
||||||
|
String name = attributes.getLocalName(i);
|
||||||
|
String value = attributes.getValue(i);
|
||||||
|
|
||||||
|
if ("e".equals(name)) {
|
||||||
|
element = Element.valueOf(value.toUpperCase(Locale.ENGLISH));
|
||||||
|
} else if ("k".equals(name)) {
|
||||||
|
keys = value;
|
||||||
|
} else if ("v".equals(name)) {
|
||||||
|
values = value;
|
||||||
|
} else if ("closed".equals(name)) {
|
||||||
|
closed = Closed.valueOf(value.toUpperCase(Locale.ENGLISH));
|
||||||
|
} else if ("zoom-min".equals(name)) {
|
||||||
|
zoomMin = Byte.parseByte(value);
|
||||||
|
} else if ("zoom-max".equals(name)) {
|
||||||
|
zoomMax = Byte.parseByte(value);
|
||||||
|
} else {
|
||||||
|
RenderThemeHandler.logUnknownAttribute(elementName, name, value, i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
validate(elementName, element, keys, values, zoomMin, zoomMax);
|
||||||
|
return createRule(ruleStack, element, keys, values, closed, zoomMin, zoomMax);
|
||||||
|
}
|
||||||
|
|
||||||
|
private ArrayList<RenderInstruction> mRenderInstructions;
|
||||||
|
private ArrayList<Rule> mSubRules;
|
||||||
|
|
||||||
|
private Rule[] mSubRuleArray;
|
||||||
|
private RenderInstruction[] mRenderInstructionArray;
|
||||||
|
|
||||||
|
final ClosedMatcher mClosedMatcher;
|
||||||
|
final ElementMatcher mElementMatcher;
|
||||||
|
final byte mZoomMax;
|
||||||
|
final byte mZoomMin;
|
||||||
|
|
||||||
|
Rule(ElementMatcher elementMatcher, ClosedMatcher closedMatcher, byte zoomMin, byte zoomMax) {
|
||||||
|
if (elementMatcher instanceof AnyMatcher)
|
||||||
|
mElementMatcher = null;
|
||||||
|
else
|
||||||
|
mElementMatcher = elementMatcher;
|
||||||
|
|
||||||
|
if (closedMatcher instanceof AnyMatcher)
|
||||||
|
mClosedMatcher = null;
|
||||||
|
else
|
||||||
|
mClosedMatcher = closedMatcher;
|
||||||
|
|
||||||
|
mZoomMin = zoomMin;
|
||||||
|
mZoomMax = zoomMax;
|
||||||
|
|
||||||
|
mRenderInstructions = new ArrayList<RenderInstruction>(4);
|
||||||
|
mSubRules = new ArrayList<Rule>(4);
|
||||||
|
}
|
||||||
|
|
||||||
|
void addRenderingInstruction(RenderInstruction renderInstruction) {
|
||||||
|
mRenderInstructions.add(renderInstruction);
|
||||||
|
}
|
||||||
|
|
||||||
|
void addSubRule(Rule rule) {
|
||||||
|
mSubRules.add(rule);
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract boolean matchesNode(Tag[] tags, byte zoomLevel);
|
||||||
|
|
||||||
|
abstract boolean matchesWay(Tag[] tags, byte zoomLevel, Closed closed);
|
||||||
|
|
||||||
|
void matchNode(RenderCallback renderCallback, Tag[] tags, byte zoomLevel) {
|
||||||
|
if (matchesNode(tags, zoomLevel)) {
|
||||||
|
for (int i = 0, n = mRenderInstructionArray.length; i < n; i++)
|
||||||
|
mRenderInstructionArray[i].renderNode(renderCallback, tags);
|
||||||
|
|
||||||
|
for (int i = 0, n = mSubRuleArray.length; i < n; i++)
|
||||||
|
mSubRuleArray[i].matchNode(renderCallback, tags, zoomLevel);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void matchWay(RenderCallback renderCallback, Tag[] tags, byte zoomLevel, Closed closed,
|
||||||
|
List<RenderInstruction> matchingList) {
|
||||||
|
|
||||||
|
if (matchesWay(tags, zoomLevel, closed)) {
|
||||||
|
for (int i = 0, n = mRenderInstructionArray.length; i < n; i++)
|
||||||
|
matchingList.add(mRenderInstructionArray[i]);
|
||||||
|
|
||||||
|
for (int i = 0, n = mSubRuleArray.length; i < n; i++)
|
||||||
|
mSubRuleArray[i].matchWay(renderCallback, tags, zoomLevel, closed, matchingList);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void onComplete() {
|
||||||
|
MATCHERS_CACHE_KEY.clear();
|
||||||
|
MATCHERS_CACHE_VALUE.clear();
|
||||||
|
|
||||||
|
mRenderInstructionArray = new RenderInstruction[mRenderInstructions.size()];
|
||||||
|
|
||||||
|
for (int i = 0, n = mRenderInstructions.size(); i < n; i++)
|
||||||
|
mRenderInstructionArray[i] = mRenderInstructions.get(i);
|
||||||
|
|
||||||
|
mSubRuleArray = new Rule[mSubRules.size()];
|
||||||
|
|
||||||
|
for (int i = 0, n = mSubRules.size(); i < n; i++)
|
||||||
|
mSubRuleArray[i] = mSubRules.get(i);
|
||||||
|
|
||||||
|
mRenderInstructions.clear();
|
||||||
|
mRenderInstructions = null;
|
||||||
|
mSubRules.clear();
|
||||||
|
mSubRules = null;
|
||||||
|
|
||||||
|
for (int i = 0, n = mSubRuleArray.length; i < n; i++)
|
||||||
|
mSubRuleArray[i].onComplete();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void onDestroy() {
|
||||||
|
for (int i = 0, n = mRenderInstructionArray.length; i < n; i++)
|
||||||
|
mRenderInstructionArray[i].destroy();
|
||||||
|
|
||||||
|
for (int i = 0, n = mSubRuleArray.length; i < n; i++)
|
||||||
|
mSubRuleArray[i].onDestroy();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void scaleStrokeWidth(float scaleFactor) {
|
||||||
|
for (int i = 0, n = mRenderInstructionArray.length; i < n; i++)
|
||||||
|
mRenderInstructionArray[i].scaleStrokeWidth(scaleFactor);
|
||||||
|
|
||||||
|
for (int i = 0, n = mSubRuleArray.length; i < n; i++)
|
||||||
|
mSubRuleArray[i].scaleStrokeWidth(scaleFactor);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void scaleTextSize(float scaleFactor) {
|
||||||
|
for (int i = 0, n = mRenderInstructionArray.length; i < n; i++)
|
||||||
|
mRenderInstructionArray[i].scaleTextSize(scaleFactor);
|
||||||
|
|
||||||
|
for (int i = 0, n = mSubRuleArray.length; i < n; i++)
|
||||||
|
mSubRuleArray[i].scaleTextSize(scaleFactor);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
125
src/org/mapsforge/android/rendertheme/RuleOptimizer.java
Normal file
125
src/org/mapsforge/android/rendertheme/RuleOptimizer.java
Normal file
@@ -0,0 +1,125 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010, 2011, 2012 mapsforge.org
|
||||||
|
*
|
||||||
|
* 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.mapsforge.android.rendertheme;
|
||||||
|
|
||||||
|
import java.util.Stack;
|
||||||
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
|
final class RuleOptimizer {
|
||||||
|
private static final Logger LOG = Logger.getLogger(RuleOptimizer.class.getName());
|
||||||
|
|
||||||
|
private static AttributeMatcher optimizeKeyMatcher(AttributeMatcher attributeMatcher, Stack<Rule> ruleStack) {
|
||||||
|
for (int i = 0, n = ruleStack.size(); i < n; ++i) {
|
||||||
|
if (ruleStack.get(i) instanceof PositiveRule) {
|
||||||
|
PositiveRule positiveRule = (PositiveRule) ruleStack.get(i);
|
||||||
|
if (positiveRule.mKeyMatcher != null && positiveRule.mKeyMatcher.isCoveredBy(attributeMatcher)) {
|
||||||
|
return null; // AnyMatcher.getInstance();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return attributeMatcher;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static AttributeMatcher optimizeValueMatcher(AttributeMatcher attributeMatcher, Stack<Rule> ruleStack) {
|
||||||
|
for (int i = 0, n = ruleStack.size(); i < n; ++i) {
|
||||||
|
if (ruleStack.get(i) instanceof PositiveRule) {
|
||||||
|
PositiveRule positiveRule = (PositiveRule) ruleStack.get(i);
|
||||||
|
|
||||||
|
if (positiveRule.mValueMatcher != null && positiveRule.mValueMatcher.isCoveredBy(attributeMatcher)) {
|
||||||
|
return null; // AnyMatcher.getInstance();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return attributeMatcher;
|
||||||
|
}
|
||||||
|
|
||||||
|
static AttributeMatcher optimize(AttributeMatcher attributeMatcher, Stack<Rule> ruleStack) {
|
||||||
|
if (attributeMatcher instanceof AnyMatcher)
|
||||||
|
return attributeMatcher;// return null;
|
||||||
|
else if (attributeMatcher instanceof NegativeMatcher) {
|
||||||
|
return attributeMatcher;
|
||||||
|
} else if (attributeMatcher instanceof SingleKeyMatcher) {
|
||||||
|
return optimizeKeyMatcher(attributeMatcher, ruleStack);
|
||||||
|
} else if (attributeMatcher instanceof SingleValueMatcher) {
|
||||||
|
return optimizeValueMatcher(attributeMatcher, ruleStack);
|
||||||
|
} else if (attributeMatcher instanceof MultiKeyMatcher) {
|
||||||
|
return optimizeKeyMatcher(attributeMatcher, ruleStack);
|
||||||
|
} else if (attributeMatcher instanceof MultiValueMatcher) {
|
||||||
|
return optimizeValueMatcher(attributeMatcher, ruleStack);
|
||||||
|
}
|
||||||
|
throw new IllegalArgumentException("unknown AttributeMatcher: " + attributeMatcher);
|
||||||
|
}
|
||||||
|
|
||||||
|
static ClosedMatcher optimize(ClosedMatcher closedMatcher, Stack<Rule> ruleStack) {
|
||||||
|
if (closedMatcher == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (closedMatcher instanceof AnyMatcher) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0, n = ruleStack.size(); i < n; ++i) {
|
||||||
|
ClosedMatcher matcher = ruleStack.get(i).mClosedMatcher;
|
||||||
|
if (matcher == null)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
if (matcher.isCoveredBy(closedMatcher)) {
|
||||||
|
return null; // AnyMatcher.getInstance();
|
||||||
|
|
||||||
|
} else if (!closedMatcher.isCoveredBy(ruleStack.get(i).mClosedMatcher)) {
|
||||||
|
LOG.warning("unreachable rule (closed)");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return closedMatcher;
|
||||||
|
}
|
||||||
|
|
||||||
|
static ElementMatcher optimize(ElementMatcher elementMatcher, Stack<Rule> ruleStack) {
|
||||||
|
|
||||||
|
if (elementMatcher == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (elementMatcher instanceof AnyMatcher) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0, n = ruleStack.size(); i < n; ++i) {
|
||||||
|
ElementMatcher matcher = ruleStack.get(i).mElementMatcher;
|
||||||
|
|
||||||
|
if (matcher == null)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
if (matcher.isCoveredBy(elementMatcher)) {
|
||||||
|
return null; // AnyMatcher.getInstance();
|
||||||
|
|
||||||
|
} else if (!elementMatcher.isCoveredBy(ruleStack.get(i).mElementMatcher)) {
|
||||||
|
LOG.warning("unreachable rule (e)");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return elementMatcher;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Private constructor to prevent instantiation from other classes.
|
||||||
|
*/
|
||||||
|
private RuleOptimizer() {
|
||||||
|
// do nothing
|
||||||
|
}
|
||||||
|
}
|
||||||
41
src/org/mapsforge/android/rendertheme/SingleKeyMatcher.java
Normal file
41
src/org/mapsforge/android/rendertheme/SingleKeyMatcher.java
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010, 2011, 2012 mapsforge.org
|
||||||
|
*
|
||||||
|
* 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.mapsforge.android.rendertheme;
|
||||||
|
|
||||||
|
import org.mapsforge.core.Tag;
|
||||||
|
|
||||||
|
class SingleKeyMatcher implements AttributeMatcher {
|
||||||
|
private final String mKey;
|
||||||
|
|
||||||
|
SingleKeyMatcher(String key) {
|
||||||
|
mKey = key.intern();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isCoveredBy(AttributeMatcher attributeMatcher) {
|
||||||
|
Tag[] tags = { new Tag(mKey, null) };
|
||||||
|
|
||||||
|
return attributeMatcher == this || attributeMatcher.matches(tags);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean matches(Tag[] tags) {
|
||||||
|
for (Tag tag : tags)
|
||||||
|
if (mKey == tag.key)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,41 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010, 2011, 2012 mapsforge.org
|
||||||
|
*
|
||||||
|
* 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.mapsforge.android.rendertheme;
|
||||||
|
|
||||||
|
import org.mapsforge.core.Tag;
|
||||||
|
|
||||||
|
class SingleValueMatcher implements AttributeMatcher {
|
||||||
|
private final String mValue;
|
||||||
|
|
||||||
|
SingleValueMatcher(String value) {
|
||||||
|
mValue = value.intern();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isCoveredBy(AttributeMatcher attributeMatcher) {
|
||||||
|
Tag[] tags = { new Tag(null, mValue) };
|
||||||
|
|
||||||
|
return attributeMatcher == this || attributeMatcher.matches(tags);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean matches(Tag[] tags) {
|
||||||
|
for (Tag tag : tags)
|
||||||
|
if (mValue == tag.value)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
689
src/org/mapsforge/android/rendertheme/osmarender/osmarender.xml
Normal file
689
src/org/mapsforge/android/rendertheme/osmarender/osmarender.xml
Normal file
@@ -0,0 +1,689 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<rendertheme xmlns="http://mapsforge.org/renderTheme"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://mapsforge.org/renderTheme ../renderTheme.xsd"
|
||||||
|
version="1" map-background="#f0f0f0">
|
||||||
|
|
||||||
|
<!-- ways -->
|
||||||
|
<rule e="way" k="*" v="*">
|
||||||
|
|
||||||
|
<!-- landuse -->
|
||||||
|
<rule e="way" k="landuse" v="*" zoom-min="10">
|
||||||
|
<rule e="way" k="landuse" v="residential|farmyard|retail|commercial">
|
||||||
|
<area fill="#ededec" fade="10" />
|
||||||
|
</rule>
|
||||||
|
|
||||||
|
<!-- <rule e="way" k="landuse" v="industrial|brownfield|railway"> <area
|
||||||
|
fill="#bcaacd" stroke="#e4e4e4" stroke-width="0.2" /> -->
|
||||||
|
<!--<rule e="way" k="landuse" v="construction|greenfield"> <area fill="#a47c41"
|
||||||
|
stroke="#e4e4e4" stroke-width="0.2" /> </rule> -->
|
||||||
|
<!-- <rule e="way" k="landuse" v="garages"> <area fill="#d6d6e4" /> </rule> -->
|
||||||
|
|
||||||
|
<rule e="way" k="landuse" v="grass">
|
||||||
|
<area fill="#deecb9" fade="12" />
|
||||||
|
</rule>
|
||||||
|
</rule>
|
||||||
|
|
||||||
|
<rule e="way" k="outline" v="*">
|
||||||
|
<rule e="way" k="*" v="0">
|
||||||
|
<outline stroke="#44404040" />
|
||||||
|
</rule>
|
||||||
|
</rule>
|
||||||
|
|
||||||
|
<!-- tunnel -->
|
||||||
|
<rule e="way" k="tunnel" v="true|yes" zoom-min="12">
|
||||||
|
<!-- highway tunnels -->
|
||||||
|
<rule e="way" k="highway" v="*">
|
||||||
|
|
||||||
|
<rule e="way" k="*" v="steps|footway|path">
|
||||||
|
<line stroke="#ffffff" stroke-width="0.45" outline="0"
|
||||||
|
stroke-linecap="butt" />
|
||||||
|
</rule>
|
||||||
|
<rule e="way" k="*" v="track">
|
||||||
|
<line stroke="#ffffff" stroke-width="0.7" outline="0"
|
||||||
|
stroke-linecap="butt" />
|
||||||
|
</rule>
|
||||||
|
<rule e="way" k="*" v="cycleway|bridleway|service">
|
||||||
|
<line stroke="#ffffff" stroke-width="0.85" outline="0"
|
||||||
|
stroke-linecap="butt" />
|
||||||
|
</rule>
|
||||||
|
<rule e="way" k="*" v="construction">
|
||||||
|
<line stroke="#ffffff" stroke-width="1.0" outline="0"
|
||||||
|
stroke-linecap="butt" />
|
||||||
|
</rule>
|
||||||
|
<rule e="way" k="*" v="road">
|
||||||
|
<line stroke="#ffffff" stroke-width="1.25" outline="0"
|
||||||
|
stroke-linecap="butt" />
|
||||||
|
</rule>
|
||||||
|
<rule e="way" k="*"
|
||||||
|
v="pedestrian|unclassified|residential|living_street|byway">
|
||||||
|
<line stroke="#ffffff" stroke-width="1.3" outline="0"
|
||||||
|
stroke-linecap="butt" />
|
||||||
|
</rule>
|
||||||
|
<rule e="way" k="*"
|
||||||
|
v="tertiary|secondary_link|primary_link|trunk_link|motorway_link|secondary|primary">
|
||||||
|
<line stroke="#bbffff9a" stroke-width="1.5" outline="0"
|
||||||
|
stroke-linecap="butt" />
|
||||||
|
</rule>
|
||||||
|
<rule e="way" k="*" v="motorway|trunk">
|
||||||
|
<line stroke="#bbfed6a3" stroke-width="1.7" outline="0"
|
||||||
|
stroke-linecap="butt" />
|
||||||
|
</rule>
|
||||||
|
</rule>
|
||||||
|
|
||||||
|
<!-- railway tunnel -->
|
||||||
|
<rule e="way" k="railway" v="*">
|
||||||
|
<!-- <rule e="way" k="railway" v="tram|subway|light_rail|narrow_gauge">
|
||||||
|
<line stroke="#a0a0a0" stroke-width="0.8" stroke-linecap="butt" fixed="true"/>
|
||||||
|
</rule> -->
|
||||||
|
<rule e="way" k="railway" v="rail">
|
||||||
|
<line stroke="#aa888888" stroke-width="0.9" stroke-linecap="butt"
|
||||||
|
fixed="true" />
|
||||||
|
</rule>
|
||||||
|
</rule>
|
||||||
|
</rule>
|
||||||
|
|
||||||
|
<rule e="way" k="leisure" v="*" zoom-min="12">
|
||||||
|
<!-- ist eigentlich mehr landuse imho. -->
|
||||||
|
<rule e="way" k="*" v="nature_reserve">
|
||||||
|
<area fill="#deecb9" fade="12" />
|
||||||
|
<rule e="way" k="leisure" v="*" zoom-min="14">
|
||||||
|
<line stroke="#abe29c" stroke-width="1.0" fixed="true"
|
||||||
|
stroke-linecap="butt" />
|
||||||
|
</rule>
|
||||||
|
</rule>
|
||||||
|
</rule>
|
||||||
|
<!-- landuse -->
|
||||||
|
<rule e="way" k="landuse" v="*" zoom-min="10">
|
||||||
|
<!-- <rule e="way" k="*" v="landfill|quarry"> <area fill="#e9dd72" stroke="#556b2f"
|
||||||
|
stroke-width="0.2" /> </rule> -->
|
||||||
|
<rule e="way" k="*" v="cemetery">
|
||||||
|
<area fill="#d7e6b0" fade="12" />
|
||||||
|
</rule>
|
||||||
|
<rule e="way" k="*" v="meadow|scrub">
|
||||||
|
<area fill="#deecb9" fade="12" />
|
||||||
|
</rule>
|
||||||
|
<rule e="way" k="*" v="farmland|farm">
|
||||||
|
<area fill="#fff8bf" fade="12" />
|
||||||
|
</rule>
|
||||||
|
<rule e="way" k="*" v="allotments|village_green|recreation_ground">
|
||||||
|
<area fill="#c9d8a2" fade="12" />
|
||||||
|
</rule>
|
||||||
|
<rule e="way" k="*" v="reservoir|basin">
|
||||||
|
<area fill="#b4cbdc" />
|
||||||
|
</rule>
|
||||||
|
</rule>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<rule e="way" k="leisure" v="*" zoom-min="12">
|
||||||
|
<rule e="way" k="*" v="park|common|green">
|
||||||
|
<area fill="#d7e6b0" fade="12" />
|
||||||
|
</rule>
|
||||||
|
</rule>
|
||||||
|
|
||||||
|
|
||||||
|
<rule e="way" k="natural|landuse" v="forest|wood" zoom-min="10">
|
||||||
|
<!-- <area fill="#BCCBB0" fade="10" /> -->
|
||||||
|
<area fill="#cde2bc" fade="10" />
|
||||||
|
<!-- <area fill="#87a670" fade="10" /> -->
|
||||||
|
</rule>
|
||||||
|
|
||||||
|
|
||||||
|
<!-- amenity -->
|
||||||
|
<rule e="way" k="amenity" v="*">
|
||||||
|
<!-- <rule e="way" k="*" v="kindergarten|school|college|university" zoom-min="16">
|
||||||
|
<area fill="#cdabde" stroke="#b094bf" stroke-width="0.2" /> </rule> -->
|
||||||
|
<rule e="way" k="*" v="parking" zoom-min="14">
|
||||||
|
<area fill="#f4f4f4" stroke="#d4d4d4" stroke-width="0.2" />
|
||||||
|
</rule>
|
||||||
|
<rule e="way" k="*" v="fountain" closed="yes">
|
||||||
|
<area fill="#b4cbdc" stroke="#000080" stroke-width="0.15" />
|
||||||
|
</rule>
|
||||||
|
</rule>
|
||||||
|
|
||||||
|
|
||||||
|
<rule e="way" k="natural" v="coastline">
|
||||||
|
<line stroke="#a4bbcc" stroke-width="1.2" fixed="true" />
|
||||||
|
</rule>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<!-- natural -->
|
||||||
|
<rule e="way" k="natural" v="*" zoom-min="10">
|
||||||
|
|
||||||
|
<rule e="way" k="*" v="glacier">
|
||||||
|
<area fill="#fafaff" />
|
||||||
|
</rule>
|
||||||
|
<rule e="way" k="*" v="land">
|
||||||
|
<area fill="#f8f8f8" />
|
||||||
|
</rule>
|
||||||
|
<rule e="way" k="*" v="beach">
|
||||||
|
<area fill="#eecc55" />
|
||||||
|
</rule>
|
||||||
|
<!-- Heideland -->
|
||||||
|
<rule e="way" k="*" v="heath">
|
||||||
|
<area fill="#ffffc0" fade="10" />
|
||||||
|
</rule>
|
||||||
|
<rule e="way" k="*" v="marsh|wetland">
|
||||||
|
<area fill="#deecb9" fade="12" />
|
||||||
|
</rule>
|
||||||
|
</rule>
|
||||||
|
|
||||||
|
|
||||||
|
<!-- leisure -->
|
||||||
|
<rule e="way" k="leisure" v="*" zoom-min="12">
|
||||||
|
|
||||||
|
<rule e="way" k="*" v="garden|golf_course">
|
||||||
|
<area fill="#d7e6b0" fade="12" />
|
||||||
|
</rule>
|
||||||
|
|
||||||
|
<rule e="way" k="*" v="*" zoom-min="15">
|
||||||
|
<rule e="way" k="*" v="playground|playing_fields|pitch|dog_park">
|
||||||
|
<area fill="#d7e6b0" stroke="#b7c690" stroke-width="0.2" />
|
||||||
|
</rule>
|
||||||
|
</rule>
|
||||||
|
|
||||||
|
|
||||||
|
<rule e="way" k="*" v="sports_centre|water_park">
|
||||||
|
<area fill="#c9d8a2" fade="12" />
|
||||||
|
</rule>
|
||||||
|
|
||||||
|
<!-- <rule e="way" k="*" v="track"> <rule e="way" k="area" v="yes|true">
|
||||||
|
<area fill="#c9d8a2" stroke="#b7c690" stroke-width="0.025" /> </rule> <rule
|
||||||
|
e="way" k="area" v="~|no|false"> <line stroke="#b7c690" stroke-width="0.75"
|
||||||
|
/> </rule> </rule> -->
|
||||||
|
|
||||||
|
<rule e="way" k="*" v="swimming_pool">
|
||||||
|
<area fill="#b4cbdc" stroke="#6060ff" stroke-width="0.2" />
|
||||||
|
</rule>
|
||||||
|
</rule>
|
||||||
|
|
||||||
|
<rule e="way" k="natural" v="water">
|
||||||
|
<area fill="#b4cbdc" />
|
||||||
|
</rule>
|
||||||
|
|
||||||
|
<!-- waterways -->
|
||||||
|
<rule e="way" k="waterway" v="*">
|
||||||
|
|
||||||
|
<rule e="way" k="waterway" v="ditch|drain" zoom-min="14">
|
||||||
|
<line stroke="#b4cbdc" stroke-width="1.0" stroke-linecap="butt"
|
||||||
|
fixed="true" />
|
||||||
|
</rule>
|
||||||
|
|
||||||
|
<rule e="way" k="waterway" v="canal">
|
||||||
|
<line stroke="#b4cbdc" stroke-width="0.8" stroke-linecap="butt" />
|
||||||
|
</rule>
|
||||||
|
<rule e="way" k="waterway" v="stream" zoom-min="14">
|
||||||
|
<line stroke="#b4cbdc" stroke-width="0.275" stroke-linecap="butt" />
|
||||||
|
</rule>
|
||||||
|
<rule e="way" k="waterway" v="river" zoom-min="12">
|
||||||
|
<line stroke="#b4cbdc" stroke-width="1.0" stroke-linecap="butt" />
|
||||||
|
</rule>
|
||||||
|
<rule e="way" k="waterway" v="river" zoom-max="11">
|
||||||
|
<line stroke="#b4cbdc" stroke-width="1.0" stroke-linecap="butt"
|
||||||
|
fixed="true" />
|
||||||
|
</rule>
|
||||||
|
<rule e="way" k="waterway" v="riverbank|dock">
|
||||||
|
<area fill="#b4cbdc" />
|
||||||
|
</rule>
|
||||||
|
<rule e="way" k="waterway" v="weir">
|
||||||
|
<line stroke="#000044" stroke-width="0.375" stroke-linecap="butt" />
|
||||||
|
</rule>
|
||||||
|
<rule e="way" k="waterway" v="dam" zoom-min="12">
|
||||||
|
<!-- sehr seltsam was in deutschland so als Damm gekenzeichnet wird.. -->
|
||||||
|
<line stroke="#ababab" stroke-width="0.5" stroke-linecap="butt" />
|
||||||
|
</rule>
|
||||||
|
<rule e="way" k="lock" v="yes|true">
|
||||||
|
<line stroke="#f8f8f8" stroke-width="1.5" stroke-linecap="butt" />
|
||||||
|
</rule>
|
||||||
|
</rule>
|
||||||
|
|
||||||
|
<!-- sport -->
|
||||||
|
<!-- <rule e="way" k="sport" v="*"> <rule e="way" k="sport" v="soccer"
|
||||||
|
zoom-min="17"> <rule e="way" k="sport" v="swimming|canoe|diving|scuba_diving">
|
||||||
|
<area fill="#b4cbdc" stroke="#6060ff" stroke-width="0.2" /> </rule> <rule
|
||||||
|
e="way" k="sport" v="tennis"> <area fill="#d18a6a" stroke="#b36c4c" stroke-width="0.2"
|
||||||
|
/> </rule> </rule> -->
|
||||||
|
|
||||||
|
<!-- tourism areas -->
|
||||||
|
<rule e="way" k="tourism" v="*">
|
||||||
|
<!-- <rule e="way" k="tourism" v="attraction"> <area fill="#f2caea" />
|
||||||
|
</rule> -->
|
||||||
|
<rule e="way" k="tourism" v="zoo|picnic_site|caravan_site|camp_site">
|
||||||
|
<area fill="#d7e6b0" stroke="#b7c690" stroke-width="0.2" />
|
||||||
|
</rule>
|
||||||
|
</rule>
|
||||||
|
|
||||||
|
<!-- highway area -->
|
||||||
|
<rule e="way" k="area" v="yes|true">
|
||||||
|
<rule e="way" k="highway" v="*">
|
||||||
|
|
||||||
|
<rule e="way" k="*" v="footway" zoom-min="15">
|
||||||
|
<area fill="#fefefe" stroke="#707070" stroke-width="0.25" />
|
||||||
|
<line stroke="#c0c0c0" stroke-width="0.15" stroke-linecap="butt" />
|
||||||
|
</rule>
|
||||||
|
|
||||||
|
<rule e="way" k="*" zoom-min="14"
|
||||||
|
v="pedestrian|service|unclassified|residential|road|living_street">
|
||||||
|
<area fill="#fefefe" />
|
||||||
|
<line stroke="#c0c0c0" stroke-width="0.15" stroke-linecap="butt" />
|
||||||
|
</rule>
|
||||||
|
|
||||||
|
<rule e="way" k="*" v="path" zoom-min="14">
|
||||||
|
<area fill="#d0d0d0" />
|
||||||
|
</rule>
|
||||||
|
</rule>
|
||||||
|
</rule>
|
||||||
|
|
||||||
|
<!-- platform cores -->
|
||||||
|
<rule e="way" k="highway|railway|public_transport" v="platform">
|
||||||
|
<rule e="way" k="*" v="*" closed="yes">
|
||||||
|
<area fill="#dbdbc9" />
|
||||||
|
</rule>
|
||||||
|
<rule e="way" k="*" v="*" closed="no">
|
||||||
|
<line stroke="#dbdbc9" stroke-width="0.3" />
|
||||||
|
</rule>
|
||||||
|
</rule>
|
||||||
|
|
||||||
|
|
||||||
|
<!-- runways areas -->
|
||||||
|
<rule e="way" k="aeroway" v="*">
|
||||||
|
<rule e="way" k="*" v="aerodrome" closed="yes">
|
||||||
|
<area fill="#e8ecde" />
|
||||||
|
</rule>
|
||||||
|
<!-- A place where planes are parked -->
|
||||||
|
<rule e="way" k="*" v="apron">
|
||||||
|
<area fill="#f0f0f0" />
|
||||||
|
</rule>
|
||||||
|
<!-- Airport passenger building -->
|
||||||
|
<!-- <rule e="way" k="*" v="terminal"> <area fill="#f3d6b6" stroke="#6a5a8e"
|
||||||
|
stroke-width="0.2" /> </rule> -->
|
||||||
|
</rule>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<!-- turning circles -->
|
||||||
|
<!-- <rule e="node" k="highway" v="turning_circle"> <circle r="1.5" scale-radius="true"
|
||||||
|
fill="#707070" /> </rule> -->
|
||||||
|
<!-- building -->
|
||||||
|
<rule e="way" k="building" v="*">
|
||||||
|
|
||||||
|
<!-- <rule e="way" k="*" v="*" zoom-min="15">
|
||||||
|
<line stroke="#c9c3c3" stroke-width="0.9" fixed="true"
|
||||||
|
stroke-linecap="butt" />
|
||||||
|
<area fill="#d9d3d3" fade="15" />
|
||||||
|
</rule>-->
|
||||||
|
|
||||||
|
<rule e="way" k="*" v="*" zoom-min="15">
|
||||||
|
<line stroke="#c9c3c3" stroke-width="0.5" fixed="true"
|
||||||
|
stroke-linecap="butt" />
|
||||||
|
<area fill="#e9e6e6" fade="15" />
|
||||||
|
</rule>
|
||||||
|
|
||||||
|
<!-- <rule e="way" k="*" v="*" zoom-min="17">
|
||||||
|
<caption k="name" font-style="bold" font-size="10" fill="#4040ff"
|
||||||
|
stroke="#ffffff" stroke-width="2.0" />
|
||||||
|
<caption k="addr:housenumber" font-style="bold" font-size="10" fill="#606060"
|
||||||
|
stroke="#ffffff" stroke-width="2.0" />
|
||||||
|
</rule> -->
|
||||||
|
</rule>
|
||||||
|
|
||||||
|
<rule e="way" k="outline" v="*">
|
||||||
|
<rule e="way" k="*" v="1">
|
||||||
|
<outline stroke="#909090" />
|
||||||
|
</rule>
|
||||||
|
<rule e="way" k="*" v="2">
|
||||||
|
<outline stroke="#c0c0c0" />
|
||||||
|
</rule>
|
||||||
|
<rule e="way" k="*" v="3">
|
||||||
|
<outline stroke="#404040" />
|
||||||
|
</rule>
|
||||||
|
|
||||||
|
</rule>
|
||||||
|
|
||||||
|
<!-- highway -->
|
||||||
|
|
||||||
|
<rule e="way" k="highway" v="*">
|
||||||
|
<rule e="way" k="area" v="~|no|false">
|
||||||
|
|
||||||
|
<rule e="way" k="*" v="*" zoom-min="5" zoom-max="10">
|
||||||
|
|
||||||
|
<rule e="way" k="*" v="secondary|primary_link" zoom-min="9">
|
||||||
|
<line stroke="#eeee4a" stroke-width="1.5" stroke-linecap="butt"
|
||||||
|
fixed="true" />
|
||||||
|
</rule>
|
||||||
|
|
||||||
|
<rule e="way" k="*" v="trunk_link|motorway_link" zoom-min="8">
|
||||||
|
<line stroke="#fed6a3" stroke-width="1.6" stroke-linecap="butt"
|
||||||
|
fixed="true" />
|
||||||
|
</rule>
|
||||||
|
|
||||||
|
<rule e="way" k="*" v="primary" zoom-min="8">
|
||||||
|
<line stroke="#eeee4a" stroke-width="1.6" stroke-linecap="butt"
|
||||||
|
fixed="true" />
|
||||||
|
</rule>
|
||||||
|
|
||||||
|
<rule e="way" k="*" v="trunk" zoom-min="8">
|
||||||
|
<line stroke="#fed6a3" stroke-width="1.6" stroke-linecap="butt"
|
||||||
|
fixed="true" />
|
||||||
|
</rule>
|
||||||
|
|
||||||
|
<rule e="way" k="*" v="motorway">
|
||||||
|
<line stroke="#eec693" stroke-width="1.7" stroke-linecap="butt"
|
||||||
|
fixed="true" />
|
||||||
|
</rule>
|
||||||
|
</rule>
|
||||||
|
|
||||||
|
<rule e="way" k="tunnel" v="~|no|false">
|
||||||
|
|
||||||
|
<rule e="way" k="*" v="*" zoom-min="15">
|
||||||
|
|
||||||
|
<rule e="way" k="*" v="steps">
|
||||||
|
<line stroke="#f1f0f4" stroke-width="0.35" outline="2"
|
||||||
|
stroke-linecap="butt" />
|
||||||
|
</rule>
|
||||||
|
<rule e="way" k="*" v="track|footway|path|cycleway" zoom-min="16">
|
||||||
|
<line stroke="#c1bcb6" stroke-width="0.25" stroke-linecap="butt" />
|
||||||
|
</rule>
|
||||||
|
</rule>
|
||||||
|
|
||||||
|
<rule e="way" k="*" v="*" zoom-min="14">
|
||||||
|
<rule e="way" k="*" v="track|footway|path|cycleway" zoom-max="15">
|
||||||
|
<line stroke="#c1bcb6" stroke-width="0.6" stroke-linecap="butt"
|
||||||
|
fixed="true" />
|
||||||
|
</rule>
|
||||||
|
|
||||||
|
<rule e="way" k="*" v="bridleway">
|
||||||
|
<line stroke="#d3cb98" stroke-width="0.4" outline="2" />
|
||||||
|
</rule>
|
||||||
|
|
||||||
|
<rule e="way" k="*" v="service|byway">
|
||||||
|
<line stroke="#ffffff" stroke-width="0.8" outline="1" />
|
||||||
|
</rule>
|
||||||
|
|
||||||
|
<rule e="way" k="*" v="pedestrian">
|
||||||
|
<line stroke="#f1f0f4" stroke-width="0.8" outline="1" />
|
||||||
|
</rule>
|
||||||
|
|
||||||
|
<rule e="way" k="*" v="construction">
|
||||||
|
<line stroke="#d0d0d0" stroke-width="1.3" outline="1" />
|
||||||
|
</rule>
|
||||||
|
</rule>
|
||||||
|
|
||||||
|
<rule e="way" k="*" v="*" zoom-min="13">
|
||||||
|
|
||||||
|
<rule e="way" k="*" v="residential|road|unclassified|living_street">
|
||||||
|
<rule e="way" k="bridge" v="yes|true">
|
||||||
|
<line stroke="#ffffff" stroke-width="1.3" stroke-linecap="butt"
|
||||||
|
outline="2" />
|
||||||
|
|
||||||
|
</rule>
|
||||||
|
<rule e="way" k="bridge" v="~|no|false">
|
||||||
|
<line stroke="#ffffff" stroke-width="1.3" outline="1" />
|
||||||
|
</rule>
|
||||||
|
</rule>
|
||||||
|
|
||||||
|
</rule>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<rule e="way" k="*" v="*" zoom-min="11">
|
||||||
|
|
||||||
|
<rule e="way" k="*" v="tertiary|secondary_link">
|
||||||
|
<line stroke="#ffff9a" stroke-width="1.5" outline="1" />
|
||||||
|
</rule>
|
||||||
|
|
||||||
|
<rule e="way" k="*" v="trunk_link|motorway_link">
|
||||||
|
<line stroke="#fed6a3" stroke-width="1.6" stroke-linecap="butt"
|
||||||
|
outline="1" />
|
||||||
|
</rule>
|
||||||
|
|
||||||
|
<rule e="way" k="*" v="secondary|primary_link">
|
||||||
|
|
||||||
|
<rule e="way" k="bridge" v="yes|true">
|
||||||
|
<line stroke="#fefe8a" stroke-width="1.6" outline="1"
|
||||||
|
stroke-linecap="butt" />
|
||||||
|
</rule>
|
||||||
|
|
||||||
|
<rule e="way" k="bridge" v="~|no|false">
|
||||||
|
<line stroke="#fefe8a" stroke-width="1.6" outline="1" />
|
||||||
|
</rule>
|
||||||
|
</rule>
|
||||||
|
|
||||||
|
<rule e="way" k="*" v="primary">
|
||||||
|
<line stroke="#fefe8a" stroke-width="1.7" stroke-linecap="butt"
|
||||||
|
outline="1" />
|
||||||
|
</rule>
|
||||||
|
|
||||||
|
<rule e="way" k="*" v="trunk">
|
||||||
|
<line stroke="#fed6a3" stroke-width="1.8" stroke-linecap="butt"
|
||||||
|
outline="1" />
|
||||||
|
</rule>
|
||||||
|
|
||||||
|
<rule e="way" k="*" v="motorway">
|
||||||
|
<line stroke="#eec693" stroke-width="1.9" stroke-linecap="butt"
|
||||||
|
outline="1" />
|
||||||
|
</rule>
|
||||||
|
</rule>
|
||||||
|
</rule>
|
||||||
|
</rule>
|
||||||
|
</rule>
|
||||||
|
|
||||||
|
|
||||||
|
<!-- runways cores -->
|
||||||
|
<rule e="way" k="aeroway" v="*">
|
||||||
|
<rule e="way" k="*" v="runway">
|
||||||
|
<line stroke="#c8ccbe" stroke-width="1.8" stroke-linecap="butt" />
|
||||||
|
</rule>
|
||||||
|
<rule e="way" k="*" v="taxiway">
|
||||||
|
<line stroke="#c8ccbe" stroke-width="1.0" stroke-linecap="butt" />
|
||||||
|
</rule>
|
||||||
|
</rule>
|
||||||
|
|
||||||
|
|
||||||
|
<!-- man_made features -->
|
||||||
|
<rule e="way" k="man_made" v="pier">
|
||||||
|
<rule e="way" k="*" v="*" closed="no">
|
||||||
|
<line stroke="#d0d0d0" stroke-width="0.4" stroke-linecap="butt" />
|
||||||
|
<line stroke="#e4e4e4" stroke-width="0.3" stroke-linecap="butt" />
|
||||||
|
</rule>
|
||||||
|
<rule e="way" k="*" v="*" closed="yes">
|
||||||
|
<area fill="#e4e4e4" stroke="#d0d0d0" stroke-width="0.05" />
|
||||||
|
</rule>
|
||||||
|
</rule>
|
||||||
|
|
||||||
|
|
||||||
|
<!-- barriers -->
|
||||||
|
<rule e="way" k="barrier" v="*">
|
||||||
|
<!-- <rule e="way" k="*" v="fence|wall|city_wall" zoom-min="15"> <line
|
||||||
|
stroke="#909090" stroke-width="0.1" stroke-linecap="butt" /> </rule> -->
|
||||||
|
<rule e="way" k="*" v="retaining_wall" zoom-min="15">
|
||||||
|
<line stroke="#888888" stroke-width="0.1" stroke-linecap="butt" />
|
||||||
|
</rule>
|
||||||
|
</rule>
|
||||||
|
|
||||||
|
|
||||||
|
<!-- non-physical routes -->
|
||||||
|
<!-- <rule e="way" k="route" v="ferry"> <line stroke="#707070" stroke-width="0.3"
|
||||||
|
stroke-dasharray="15,10" stroke-linecap="butt" /> </rule> -->
|
||||||
|
|
||||||
|
<!-- aerial ways -->
|
||||||
|
<!-- <rule e="way" k="aerialway" v="*"> <line stroke="#202020" stroke-width="0.4"
|
||||||
|
stroke-linecap="butt" /> <rule e="way" k="aerialway" v="cable_car"> <lineSymbol
|
||||||
|
src="jar:/org/mapsforge/android/maps/rendertheme/osmarender/symbols/cable_car.png"
|
||||||
|
/> </rule> <rule e="way" k="aerialway" v="chair_lift"> <lineSymbol src="jar:/org/mapsforge/android/maps/rendertheme/osmarender/symbols/chair_lift_2.png"
|
||||||
|
/> </rule> <rule e="way" k="aerialway" v="gondola"> <lineSymbol src="jar:/org/mapsforge/android/maps/rendertheme/osmarender/symbols/gondola.png"
|
||||||
|
/> </rule> <rule e="way" k="*" v="*" zoom-min="14"> <pathText k="name" font-style="bold"
|
||||||
|
font-size="10" fill="#606060" stroke="#ffffff" stroke-width="2.0" /> </rule>
|
||||||
|
</rule> -->
|
||||||
|
|
||||||
|
|
||||||
|
<!-- railway (no tunnel) -->
|
||||||
|
<rule e="way" k="railway" v="*" zoom-min="10">
|
||||||
|
<rule e="way" k="tunnel" v="~|false|no">
|
||||||
|
|
||||||
|
<rule e="way" k="railway" v="station">
|
||||||
|
<area fill="#dbdbc9" stroke="#707070" stroke-width="0.3" />
|
||||||
|
</rule>
|
||||||
|
|
||||||
|
<!-- railway bridge casings -->
|
||||||
|
<rule e="way" k="*" v="*" zoom-min="14">
|
||||||
|
<rule e="way" k="bridge" v="yes|true">
|
||||||
|
<rule e="way" k="railway" v="tram">
|
||||||
|
<line stroke="#777777" stroke-width="0.9" stroke-linecap="butt"
|
||||||
|
fixed="true" />
|
||||||
|
</rule>
|
||||||
|
<rule e="way" k="railway" v="subway|light_rail|narrow_gauge">
|
||||||
|
<line stroke="#777777" stroke-width="0.9" stroke-linecap="butt"
|
||||||
|
fixed="true" />
|
||||||
|
</rule>
|
||||||
|
<rule e="way" k="railway" v="rail">
|
||||||
|
<line stroke="#777777" stroke-width="0.9" stroke-linecap="butt"
|
||||||
|
fixed="true" />
|
||||||
|
</rule>
|
||||||
|
</rule>
|
||||||
|
</rule>
|
||||||
|
|
||||||
|
<!-- railway casings and cores -->
|
||||||
|
<rule e="way" k="railway" v="tram">
|
||||||
|
<line stroke="#8c8f8c" stroke-width="0.6" fixed="true" />
|
||||||
|
</rule>
|
||||||
|
|
||||||
|
<rule e="way" k="railway" v="light_rail|subway|narrow_gauge">
|
||||||
|
<line stroke="#a0a0a0" stroke-width="0.6" stroke-linecap="butt"
|
||||||
|
fixed="true" />
|
||||||
|
|
||||||
|
</rule>
|
||||||
|
<rule e="way" k="railway" v="rail" zoom-min="15">
|
||||||
|
<line stroke="#777799" stroke-width="0.5" stroke-linecap="butt"
|
||||||
|
fixed="true" />
|
||||||
|
</rule>
|
||||||
|
<rule e="way" k="railway" v="rail" zoom-max="14" zoom-min="13">
|
||||||
|
<line stroke="#8888aa" stroke-width="0.5" stroke-linecap="butt"
|
||||||
|
fixed="true" />
|
||||||
|
</rule>
|
||||||
|
<rule e="way" k="railway" v="rail" zoom-max="12" zoom-min="11">
|
||||||
|
<line stroke="#bbbbcc" stroke-width="0.5" stroke-linecap="butt"
|
||||||
|
fixed="true" />
|
||||||
|
</rule>
|
||||||
|
</rule>
|
||||||
|
</rule>
|
||||||
|
|
||||||
|
|
||||||
|
<!-- non-physical boundaries -->
|
||||||
|
<!-- <rule e="way" k="boundary" v="*"> <rule e="way" k="boundary" v="national_park">
|
||||||
|
<line stroke="#4ef94b" stroke-width="0.25" stroke-dasharray="15, 5, 5, 5"
|
||||||
|
/> -->
|
||||||
|
|
||||||
|
<!--<rule e="way" k="boundary" v="administrative"> -->
|
||||||
|
<rule e="way" k="admin_level" v="*">
|
||||||
|
<!-- <rule e="way" k="admin_level" v="11"> <line stroke="#f9574b" stroke-width="0.1"
|
||||||
|
fixed="true" stroke-linecap="butt" /> </rule> <rule e="way" k="admin_level"
|
||||||
|
v="10"> <line stroke="#f9574b" stroke-width="0.1" fixed="true" stroke-linecap="butt"
|
||||||
|
/> </rule> <rule e="way" k="admin_level" v="9"> <line stroke="#f9574b" stroke-width="0.1"
|
||||||
|
fixed="true" stroke-linecap="butt" /> </rule> <rule e="way" k="admin_level"
|
||||||
|
v="8"> <line stroke="#f9574b" stroke-width="0.3" fixed="true" stroke-linecap="butt"
|
||||||
|
/> </rule> <rule e="way" k="admin_level" v="7"> <line stroke="#f9574b" stroke-width="0.1"
|
||||||
|
fixed="true" stroke-linecap="butt" /> </rule> <rule e="way" k="admin_level"
|
||||||
|
v="6"> <line stroke="#f9574b" stroke-width="0.15" fixed="true" stroke-linecap="butt"
|
||||||
|
/> </rule> <rule e="way" k="admin_level" v="5"> <line stroke="#f9574b" stroke-width="0.15"
|
||||||
|
fixed="true" stroke-linecap="butt" /> </rule> -->
|
||||||
|
<rule e="way" k="admin_level" v="4">
|
||||||
|
<line stroke="#8f80dd" stroke-width="0.9" fixed="true"
|
||||||
|
stroke-linecap="butt" />
|
||||||
|
</rule>
|
||||||
|
<rule e="way" k="admin_level" v="3">
|
||||||
|
<line stroke="#0000ff" stroke-width="0.95" fixed="true"
|
||||||
|
stroke-linecap="butt" />
|
||||||
|
</rule>
|
||||||
|
<rule e="way" k="admin_level" v="2">
|
||||||
|
<line stroke="#a0a0a0" stroke-width="0.95" fixed="true"
|
||||||
|
stroke-linecap="butt" />
|
||||||
|
</rule>
|
||||||
|
<rule e="way" k="admin_level" v="1">
|
||||||
|
<line stroke="#ff0000" stroke-width="0.95" fixed="true"
|
||||||
|
stroke-linecap="butt" />
|
||||||
|
</rule>
|
||||||
|
|
||||||
|
</rule>
|
||||||
|
<!-- </rule> -->
|
||||||
|
|
||||||
|
|
||||||
|
<!-- historic -->
|
||||||
|
<rule e="way" k="historic" v="ruins" zoom-min="17">
|
||||||
|
<caption k="name" font-style="bold" font-size="10" fill="#4040ff"
|
||||||
|
stroke="#ffffff" stroke-width="2.0" />
|
||||||
|
</rule>
|
||||||
|
|
||||||
|
|
||||||
|
<!-- place -->
|
||||||
|
<rule e="way" k="place" v="locality" zoom-min="17">
|
||||||
|
<caption k="name" font-style="bold" font-size="10" fill="#000000"
|
||||||
|
stroke="#ffffff" stroke-width="2.0" />
|
||||||
|
</rule>
|
||||||
|
</rule>
|
||||||
|
|
||||||
|
<rule e="node" k="*" v="*">
|
||||||
|
<!-- barrier -->
|
||||||
|
<rule e="node" k="barrier" v="bollard">
|
||||||
|
<circle r="1.5" fill="#909090" />
|
||||||
|
</rule>
|
||||||
|
|
||||||
|
|
||||||
|
<!-- highway -->
|
||||||
|
<!-- <rule e="node" k="highway" v="*"> <rule e="node" k="highway" v="turning_circle">
|
||||||
|
<circle r="1.4" scale-radius="true" fill="#ffffff" /> </rule> </rule> -->
|
||||||
|
|
||||||
|
<!-- historic -->
|
||||||
|
<!-- <rule e="node" k="historic" v="*"> <circle r="3" fill="#4040ff" stroke="#606060"
|
||||||
|
stroke-width="1.5" /> <rule e="node" k="*" v="*" zoom-min="17"> <caption
|
||||||
|
k="name" dy="-10" font-style="bold" font-size="10" fill="#4040ff" stroke="#ffffff"
|
||||||
|
stroke-width="2.0" /> </rule> </rule> -->
|
||||||
|
|
||||||
|
|
||||||
|
<!-- house numbers -->
|
||||||
|
<!-- <rule e="node" k="addr:housenumber" v="*" zoom-min="18"> <caption
|
||||||
|
k="addr:housenumber" font-style="bold" font-size="10" fill="#606060" stroke="#ffffff"
|
||||||
|
stroke-width="2.0" /> </rule> -->
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<!-- place -->
|
||||||
|
<rule e="node" k="place" v="*">
|
||||||
|
<rule e="node" k="*" v="suburb|town|village" zoom-max="14">
|
||||||
|
<caption k="name" font-style="bold" font-size="15" fill="#000000"
|
||||||
|
stroke="#ffffff" stroke-width="2.0" />
|
||||||
|
</rule>
|
||||||
|
<rule e="node" k="*" v="island" zoom-min="10">
|
||||||
|
<caption k="name" font-style="bold" font-size="20" fill="#000000"
|
||||||
|
stroke="#ffffff" stroke-width="2.0" />
|
||||||
|
</rule>
|
||||||
|
<rule e="node" k="*" v="city" zoom-max="14">
|
||||||
|
<caption k="name" font-style="bold" font-size="25" fill="#000000"
|
||||||
|
stroke="#ffffff" stroke-width="2.0" />
|
||||||
|
</rule>
|
||||||
|
<rule e="node" k="*" v="country" zoom-max="6">
|
||||||
|
<caption k="name" font-style="bold" font-size="25" fill="#000000"
|
||||||
|
stroke="#ffffff" stroke-width="2.0" />
|
||||||
|
</rule>
|
||||||
|
</rule>
|
||||||
|
|
||||||
|
|
||||||
|
<!-- railway -->
|
||||||
|
<rule e="node" k="railway" v="*">
|
||||||
|
<rule e="node" k="*" v="station" zoom-min="14">
|
||||||
|
<circle r="6" fill="#ec2d2d" stroke="#606060" stroke-width="1.5" />
|
||||||
|
<!-- <caption k="name" dy="-10" font-style="bold" font-size="13" fill="#ec2d2d"
|
||||||
|
stroke="#ffffff" stroke-width="2.0" /> -->
|
||||||
|
</rule>
|
||||||
|
<rule e="node" k="*" v="halt|tram_stop" zoom-min="17">
|
||||||
|
<circle r="4" fill="#ec2d2d" stroke="#606060" stroke-width="1.5" />
|
||||||
|
<!-- <caption k="name" dy="-15" font-style="bold" font-size="11" fill="#ec2d2d"
|
||||||
|
stroke="#ffffff" stroke-width="2.0" /> -->
|
||||||
|
</rule>
|
||||||
|
</rule>
|
||||||
|
</rule>
|
||||||
|
|
||||||
|
</rendertheme>
|
||||||
229
src/org/mapsforge/android/rendertheme/renderTheme.xsd
Normal file
229
src/org/mapsforge/android/rendertheme/renderTheme.xsd
Normal file
@@ -0,0 +1,229 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
|
||||||
|
targetNamespace="http://mapsforge.org/renderTheme" xmlns:tns="http://mapsforge.org/renderTheme"
|
||||||
|
elementFormDefault="qualified" xml:lang="en">
|
||||||
|
<!-- attribute types -->
|
||||||
|
<xs:simpleType name="cap">
|
||||||
|
<xs:restriction base="xs:string">
|
||||||
|
<xs:enumeration value="butt" />
|
||||||
|
<xs:enumeration value="round" />
|
||||||
|
<xs:enumeration value="square" />
|
||||||
|
</xs:restriction>
|
||||||
|
</xs:simpleType>
|
||||||
|
|
||||||
|
<xs:simpleType name="closed">
|
||||||
|
<xs:restriction base="xs:string">
|
||||||
|
<xs:enumeration value="yes" />
|
||||||
|
<xs:enumeration value="no" />
|
||||||
|
<xs:enumeration value="any" />
|
||||||
|
</xs:restriction>
|
||||||
|
</xs:simpleType>
|
||||||
|
|
||||||
|
<xs:simpleType name="color">
|
||||||
|
<xs:restriction base="xs:string">
|
||||||
|
<xs:pattern value="#([0-9a-fA-F]{6}|[0-9a-fA-F]{8})" />
|
||||||
|
</xs:restriction>
|
||||||
|
</xs:simpleType>
|
||||||
|
|
||||||
|
<xs:simpleType name="elementList">
|
||||||
|
<xs:restriction base="xs:string">
|
||||||
|
<xs:enumeration value="node" />
|
||||||
|
<xs:enumeration value="way" />
|
||||||
|
<xs:enumeration value="any" />
|
||||||
|
</xs:restriction>
|
||||||
|
</xs:simpleType>
|
||||||
|
|
||||||
|
<xs:simpleType name="fontFamily">
|
||||||
|
<xs:restriction base="xs:string">
|
||||||
|
<xs:enumeration value="default" />
|
||||||
|
<xs:enumeration value="default_bold" />
|
||||||
|
<xs:enumeration value="monospace" />
|
||||||
|
<xs:enumeration value="sans_serif" />
|
||||||
|
<xs:enumeration value="serif" />
|
||||||
|
</xs:restriction>
|
||||||
|
</xs:simpleType>
|
||||||
|
|
||||||
|
<xs:simpleType name="fontStyle">
|
||||||
|
<xs:restriction base="xs:string">
|
||||||
|
<xs:enumeration value="bold" />
|
||||||
|
<xs:enumeration value="bold_italic" />
|
||||||
|
<xs:enumeration value="italic" />
|
||||||
|
<xs:enumeration value="normal" />
|
||||||
|
</xs:restriction>
|
||||||
|
</xs:simpleType>
|
||||||
|
|
||||||
|
<xs:simpleType name="nonNegativeFloat">
|
||||||
|
<xs:restriction base="xs:float">
|
||||||
|
<xs:minInclusive value="0" />
|
||||||
|
</xs:restriction>
|
||||||
|
</xs:simpleType>
|
||||||
|
|
||||||
|
<xs:simpleType name="src">
|
||||||
|
<xs:restriction base="xs:string">
|
||||||
|
<xs:pattern value="(jar|file)\:.+" />
|
||||||
|
</xs:restriction>
|
||||||
|
</xs:simpleType>
|
||||||
|
|
||||||
|
<xs:simpleType name="strokeDasharray">
|
||||||
|
<xs:restriction base="xs:string">
|
||||||
|
<xs:pattern
|
||||||
|
value="([0-9]+(\.[0-9]+)? *, *[0-9]+(\.[0-9]+)? *, *)*[0-9]+(\.[0-9]+)? *, *[0-9]+(\.[0-9]+)?" />
|
||||||
|
</xs:restriction>
|
||||||
|
</xs:simpleType>
|
||||||
|
|
||||||
|
<xs:simpleType name="textKey">
|
||||||
|
<xs:restriction base="xs:string">
|
||||||
|
<xs:enumeration value="ele" />
|
||||||
|
<xs:enumeration value="addr:housenumber" />
|
||||||
|
<xs:enumeration value="name" />
|
||||||
|
<xs:enumeration value="ref" />
|
||||||
|
</xs:restriction>
|
||||||
|
</xs:simpleType>
|
||||||
|
|
||||||
|
|
||||||
|
<!-- rendering instructions -->
|
||||||
|
<xs:complexType name="area">
|
||||||
|
<xs:attribute name="src" type="tns:src" use="optional" />
|
||||||
|
<xs:attribute name="fill" type="tns:color" use="optional"
|
||||||
|
default="#000000" />
|
||||||
|
<xs:attribute name="stroke" type="tns:color" use="optional"
|
||||||
|
default="#00000000" />
|
||||||
|
<xs:attribute name="stroke-width" type="tns:nonNegativeFloat"
|
||||||
|
use="optional" default="0" />
|
||||||
|
<xs:attribute name="fade" type="xs:integer" use="optional"
|
||||||
|
default="-1" />
|
||||||
|
</xs:complexType>
|
||||||
|
|
||||||
|
<xs:complexType name="caption">
|
||||||
|
<xs:attribute name="k" type="tns:textKey" use="required" />
|
||||||
|
<xs:attribute name="dy" type="xs:float" use="optional"
|
||||||
|
default="0" />
|
||||||
|
<xs:attribute name="font-family" type="tns:fontFamily"
|
||||||
|
use="optional" default="default" />
|
||||||
|
<xs:attribute name="font-style" type="tns:fontStyle" use="optional"
|
||||||
|
default="normal" />
|
||||||
|
<xs:attribute name="font-size" type="tns:nonNegativeFloat"
|
||||||
|
use="optional" default="0" />
|
||||||
|
<xs:attribute name="fill" type="tns:color" use="optional"
|
||||||
|
default="#000000" />
|
||||||
|
<xs:attribute name="stroke" type="tns:color" use="optional"
|
||||||
|
default="#000000" />
|
||||||
|
<xs:attribute name="stroke-width" type="tns:nonNegativeFloat"
|
||||||
|
use="optional" default="0" />
|
||||||
|
</xs:complexType>
|
||||||
|
|
||||||
|
<xs:complexType name="circle">
|
||||||
|
<xs:attribute name="r" type="tns:nonNegativeFloat" use="required" />
|
||||||
|
<xs:attribute name="scale-radius" type="xs:boolean" use="optional"
|
||||||
|
default="false" />
|
||||||
|
<xs:attribute name="fill" type="tns:color" use="optional"
|
||||||
|
default="#00000000" />
|
||||||
|
<xs:attribute name="stroke" type="tns:color" use="optional"
|
||||||
|
default="#00000000" />
|
||||||
|
<xs:attribute name="stroke-width" type="tns:nonNegativeFloat"
|
||||||
|
use="optional" default="0" />
|
||||||
|
</xs:complexType>
|
||||||
|
|
||||||
|
<xs:complexType name="line">
|
||||||
|
<xs:attribute name="src" type="tns:src" use="optional" />
|
||||||
|
<xs:attribute name="stroke" type="tns:color" use="optional"
|
||||||
|
default="#000000" />
|
||||||
|
<xs:attribute name="stroke-width" type="tns:nonNegativeFloat"
|
||||||
|
use="optional" default="0" />
|
||||||
|
<xs:attribute name="stroke-dasharray" type="tns:strokeDasharray"
|
||||||
|
use="optional" />
|
||||||
|
<xs:attribute name="stroke-linecap" type="tns:cap" use="optional"
|
||||||
|
default="round" />
|
||||||
|
<xs:attribute name="outline" type="xs:integer" use="optional"
|
||||||
|
default="0" />
|
||||||
|
<xs:attribute name="fade" type="xs:integer" use="optional"
|
||||||
|
default="-1" />
|
||||||
|
<xs:attribute name="fixed" type="xs:boolean" use="optional"
|
||||||
|
default="false" />
|
||||||
|
</xs:complexType>
|
||||||
|
|
||||||
|
<xs:complexType name="outline">
|
||||||
|
<xs:attribute name="src" type="tns:src" use="optional" />
|
||||||
|
<xs:attribute name="stroke" type="tns:color" use="optional"
|
||||||
|
default="#000000" />
|
||||||
|
<xs:attribute name="stroke-width" type="tns:nonNegativeFloat"
|
||||||
|
use="optional" default="0" />
|
||||||
|
</xs:complexType>
|
||||||
|
|
||||||
|
<xs:complexType name="lineSymbol">
|
||||||
|
<xs:attribute name="src" type="tns:src" use="required" />
|
||||||
|
<xs:attribute name="align-center" type="xs:boolean" use="optional"
|
||||||
|
default="false" />
|
||||||
|
<xs:attribute name="repeat" type="xs:boolean" use="optional"
|
||||||
|
default="false" />
|
||||||
|
</xs:complexType>
|
||||||
|
|
||||||
|
<xs:complexType name="pathText">
|
||||||
|
<xs:attribute name="k" type="tns:textKey" use="required" />
|
||||||
|
<xs:attribute name="dy" type="xs:float" use="optional"
|
||||||
|
default="0" />
|
||||||
|
<xs:attribute name="font-family" type="tns:fontFamily"
|
||||||
|
use="optional" default="default" />
|
||||||
|
<xs:attribute name="font-style" type="tns:fontStyle" use="optional"
|
||||||
|
default="normal" />
|
||||||
|
<xs:attribute name="font-size" type="tns:nonNegativeFloat"
|
||||||
|
use="optional" default="0" />
|
||||||
|
<xs:attribute name="fill" type="tns:color" use="optional"
|
||||||
|
default="#000000" />
|
||||||
|
<xs:attribute name="stroke" type="tns:color" use="optional"
|
||||||
|
default="#000000" />
|
||||||
|
<xs:attribute name="stroke-width" type="tns:nonNegativeFloat"
|
||||||
|
use="optional" default="0" />
|
||||||
|
</xs:complexType>
|
||||||
|
|
||||||
|
<xs:complexType name="symbol">
|
||||||
|
<xs:attribute name="src" type="tns:src" use="required" />
|
||||||
|
</xs:complexType>
|
||||||
|
|
||||||
|
|
||||||
|
<!-- rule elements -->
|
||||||
|
<xs:complexType name="rule">
|
||||||
|
<xs:choice minOccurs="0" maxOccurs="unbounded">
|
||||||
|
<!-- recursion to allow for nested rules -->
|
||||||
|
<xs:element name="rule" type="tns:rule" />
|
||||||
|
|
||||||
|
<xs:element name="area" type="tns:area" />
|
||||||
|
<xs:element name="caption" type="tns:caption" />
|
||||||
|
<xs:element name="circle" type="tns:circle" />
|
||||||
|
<xs:element name="line" type="tns:line" />
|
||||||
|
<xs:element name="outline" type="tns:outline" />
|
||||||
|
<xs:element name="lineSymbol" type="tns:lineSymbol" />
|
||||||
|
<xs:element name="pathText" type="tns:pathText" />
|
||||||
|
<xs:element name="symbol" type="tns:symbol" />
|
||||||
|
</xs:choice>
|
||||||
|
<xs:attribute name="e" type="tns:elementList" use="required" />
|
||||||
|
<xs:attribute name="k" type="xs:string" use="required" />
|
||||||
|
<xs:attribute name="v" type="xs:string" use="required" />
|
||||||
|
<xs:attribute name="closed" type="tns:closed" use="optional"
|
||||||
|
default="any" />
|
||||||
|
<xs:attribute name="zoom-min" type="xs:unsignedByte" use="optional"
|
||||||
|
default="0" />
|
||||||
|
<xs:attribute name="zoom-max" type="xs:unsignedByte" use="optional"
|
||||||
|
default="127" />
|
||||||
|
</xs:complexType>
|
||||||
|
|
||||||
|
|
||||||
|
<!-- rendertheme element -->
|
||||||
|
<xs:complexType name="rendertheme">
|
||||||
|
<xs:sequence minOccurs="0" maxOccurs="unbounded">
|
||||||
|
<xs:element name="rule" type="tns:rule" />
|
||||||
|
</xs:sequence>
|
||||||
|
<xs:attribute name="version" type="xs:positiveInteger"
|
||||||
|
use="required" />
|
||||||
|
<xs:attribute name="map-background" type="tns:color" use="optional"
|
||||||
|
default="#ffffff" />
|
||||||
|
<xs:attribute name="base-stroke-width" type="tns:nonNegativeFloat"
|
||||||
|
use="optional" default="1" />
|
||||||
|
<xs:attribute name="base-text-size" type="tns:nonNegativeFloat"
|
||||||
|
use="optional" default="1" />
|
||||||
|
</xs:complexType>
|
||||||
|
|
||||||
|
|
||||||
|
<!-- root element -->
|
||||||
|
<xs:element name="rendertheme" type="tns:rendertheme" />
|
||||||
|
</xs:schema>
|
||||||
@@ -0,0 +1,162 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010, 2011, 2012 mapsforge.org
|
||||||
|
*
|
||||||
|
* 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.mapsforge.android.rendertheme.renderinstruction;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
import org.mapsforge.android.rendertheme.RenderCallback;
|
||||||
|
import org.mapsforge.android.rendertheme.RenderThemeHandler;
|
||||||
|
import org.mapsforge.core.Tag;
|
||||||
|
import org.xml.sax.Attributes;
|
||||||
|
|
||||||
|
import android.graphics.Color;
|
||||||
|
import android.graphics.Paint;
|
||||||
|
import android.graphics.Paint.Cap;
|
||||||
|
import android.graphics.Paint.Style;
|
||||||
|
import android.graphics.Shader;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents a closed polygon on the map.
|
||||||
|
*/
|
||||||
|
public final class Area implements RenderInstruction {
|
||||||
|
/**
|
||||||
|
* @param elementName
|
||||||
|
* the name of the XML element.
|
||||||
|
* @param attributes
|
||||||
|
* the attributes of the XML element.
|
||||||
|
* @param level
|
||||||
|
* the drawing level of this instruction.
|
||||||
|
* @return a new Area with the given rendering attributes.
|
||||||
|
* @throws IOException
|
||||||
|
* if an I/O error occurs while reading a resource.
|
||||||
|
*/
|
||||||
|
public static Area create(String elementName, Attributes attributes, int level) throws IOException {
|
||||||
|
String src = null;
|
||||||
|
int fill = Color.BLACK;
|
||||||
|
int stroke = Color.TRANSPARENT;
|
||||||
|
float strokeWidth = 0;
|
||||||
|
int fade = -1;
|
||||||
|
for (int i = 0; i < attributes.getLength(); ++i) {
|
||||||
|
String name = attributes.getLocalName(i);
|
||||||
|
String value = attributes.getValue(i);
|
||||||
|
|
||||||
|
if ("src".equals(name)) {
|
||||||
|
src = value;
|
||||||
|
} else if ("fill".equals(name)) {
|
||||||
|
fill = Color.parseColor(value);
|
||||||
|
} else if ("stroke".equals(name)) {
|
||||||
|
stroke = Color.parseColor(value);
|
||||||
|
} else if ("stroke-width".equals(name)) {
|
||||||
|
strokeWidth = Float.parseFloat(value);
|
||||||
|
} else if ("fade".equals(name)) {
|
||||||
|
fade = Integer.parseInt(value);
|
||||||
|
} else {
|
||||||
|
RenderThemeHandler.logUnknownAttribute(elementName, name, value, i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
validate(strokeWidth);
|
||||||
|
return new Area(src, fill, stroke, strokeWidth, fade, level);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void validate(float strokeWidth) {
|
||||||
|
if (strokeWidth < 0) {
|
||||||
|
throw new IllegalArgumentException("stroke-width must not be negative: " + strokeWidth);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public final int level;
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public final Paint paintFill;
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public final Paint paintOutline;
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public final float strokeWidth;
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public final int color;
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public final int fade;
|
||||||
|
|
||||||
|
private Area(String src, int fill, int stroke, float strokeWidth, int fade, int level) throws IOException {
|
||||||
|
super();
|
||||||
|
|
||||||
|
Shader shader = BitmapUtils.createBitmapShader(src);
|
||||||
|
|
||||||
|
if (fill == Color.TRANSPARENT) {
|
||||||
|
paintFill = null;
|
||||||
|
} else {
|
||||||
|
paintFill = new Paint(Paint.ANTI_ALIAS_FLAG);
|
||||||
|
paintFill.setShader(shader);
|
||||||
|
paintFill.setStyle(Style.FILL);
|
||||||
|
paintFill.setColor(fill);
|
||||||
|
paintFill.setStrokeCap(Cap.ROUND);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (stroke == Color.TRANSPARENT) {
|
||||||
|
paintOutline = null;
|
||||||
|
} else {
|
||||||
|
paintOutline = new Paint(Paint.ANTI_ALIAS_FLAG);
|
||||||
|
paintOutline.setStyle(Style.STROKE);
|
||||||
|
paintOutline.setColor(stroke);
|
||||||
|
paintOutline.setStrokeCap(Cap.ROUND);
|
||||||
|
}
|
||||||
|
color = fill;
|
||||||
|
this.strokeWidth = strokeWidth;
|
||||||
|
this.fade = fade;
|
||||||
|
this.level = level;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void destroy() {
|
||||||
|
// do nothing
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void renderNode(RenderCallback renderCallback, Tag[] tags) {
|
||||||
|
// do nothing
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void renderWay(RenderCallback renderCallback, Tag[] tags) {
|
||||||
|
if (paintFill != null) {
|
||||||
|
renderCallback.renderArea(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void scaleStrokeWidth(float scaleFactor) {
|
||||||
|
if (paintOutline != null) {
|
||||||
|
paintOutline.setStrokeWidth(strokeWidth * scaleFactor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void scaleTextSize(float scaleFactor) {
|
||||||
|
// do nothing
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,78 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010, 2011, 2012 mapsforge.org
|
||||||
|
*
|
||||||
|
* 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.mapsforge.android.rendertheme.renderinstruction;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileInputStream;
|
||||||
|
import java.io.FileNotFoundException;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
|
||||||
|
import android.graphics.Bitmap;
|
||||||
|
import android.graphics.BitmapFactory;
|
||||||
|
import android.graphics.BitmapShader;
|
||||||
|
import android.graphics.Shader.TileMode;
|
||||||
|
|
||||||
|
final class BitmapUtils {
|
||||||
|
private static final String PREFIX_FILE = "file:";
|
||||||
|
private static final String PREFIX_JAR = "jar:";
|
||||||
|
|
||||||
|
private static InputStream createInputStream(String src) throws FileNotFoundException {
|
||||||
|
if (src.startsWith(PREFIX_JAR)) {
|
||||||
|
String name = src.substring(PREFIX_JAR.length());
|
||||||
|
InputStream inputStream = Thread.currentThread().getClass().getResourceAsStream(name);
|
||||||
|
if (inputStream == null) {
|
||||||
|
throw new FileNotFoundException("resource not found: " + src);
|
||||||
|
}
|
||||||
|
return inputStream;
|
||||||
|
} else if (src.startsWith(PREFIX_FILE)) {
|
||||||
|
File file = new File(src.substring(PREFIX_FILE.length()));
|
||||||
|
if (!file.exists()) {
|
||||||
|
throw new IllegalArgumentException("file does not exist: " + src);
|
||||||
|
} else if (!file.isFile()) {
|
||||||
|
throw new IllegalArgumentException("not a file: " + src);
|
||||||
|
} else if (!file.canRead()) {
|
||||||
|
throw new IllegalArgumentException("cannot read file: " + src);
|
||||||
|
}
|
||||||
|
return new FileInputStream(file);
|
||||||
|
}
|
||||||
|
throw new IllegalArgumentException("invalid bitmap source: " + src);
|
||||||
|
}
|
||||||
|
|
||||||
|
static Bitmap createBitmap(String src) throws IOException {
|
||||||
|
if (src == null || src.length() == 0) {
|
||||||
|
// no image source defined
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
InputStream inputStream = createInputStream(src);
|
||||||
|
Bitmap bitmap = BitmapFactory.decodeStream(inputStream);
|
||||||
|
inputStream.close();
|
||||||
|
return bitmap;
|
||||||
|
}
|
||||||
|
|
||||||
|
static BitmapShader createBitmapShader(String src) throws IOException {
|
||||||
|
Bitmap bitmap = BitmapUtils.createBitmap(src);
|
||||||
|
if (bitmap == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return new BitmapShader(bitmap, TileMode.REPEAT, TileMode.REPEAT);
|
||||||
|
}
|
||||||
|
|
||||||
|
private BitmapUtils() {
|
||||||
|
throw new IllegalStateException();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,143 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010, 2011, 2012 mapsforge.org
|
||||||
|
*
|
||||||
|
* 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.mapsforge.android.rendertheme.renderinstruction;
|
||||||
|
|
||||||
|
import java.util.Locale;
|
||||||
|
|
||||||
|
import org.mapsforge.android.rendertheme.RenderCallback;
|
||||||
|
import org.mapsforge.android.rendertheme.RenderThemeHandler;
|
||||||
|
import org.mapsforge.core.Tag;
|
||||||
|
import org.xml.sax.Attributes;
|
||||||
|
|
||||||
|
import android.graphics.Color;
|
||||||
|
import android.graphics.Paint;
|
||||||
|
import android.graphics.Paint.Align;
|
||||||
|
import android.graphics.Paint.Style;
|
||||||
|
import android.graphics.Typeface;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents a text label on the map.
|
||||||
|
*/
|
||||||
|
public final class Caption implements RenderInstruction {
|
||||||
|
/**
|
||||||
|
* @param elementName
|
||||||
|
* the name of the XML element.
|
||||||
|
* @param attributes
|
||||||
|
* the attributes of the XML element.
|
||||||
|
* @return a new Caption with the given rendering attributes.
|
||||||
|
*/
|
||||||
|
public static Caption create(String elementName, Attributes attributes) {
|
||||||
|
String textKey = null;
|
||||||
|
float dy = 0;
|
||||||
|
FontFamily fontFamily = FontFamily.DEFAULT;
|
||||||
|
FontStyle fontStyle = FontStyle.NORMAL;
|
||||||
|
float fontSize = 0;
|
||||||
|
int fill = Color.BLACK;
|
||||||
|
int stroke = Color.BLACK;
|
||||||
|
float strokeWidth = 0;
|
||||||
|
|
||||||
|
for (int i = 0; i < attributes.getLength(); ++i) {
|
||||||
|
String name = attributes.getLocalName(i);
|
||||||
|
String value = attributes.getValue(i);
|
||||||
|
|
||||||
|
if ("k".equals(name)) {
|
||||||
|
textKey = TextKey.getInstance(value);
|
||||||
|
} else if ("dy".equals(name)) {
|
||||||
|
dy = Float.parseFloat(value);
|
||||||
|
} else if ("font-family".equals(name)) {
|
||||||
|
fontFamily = FontFamily.valueOf(value.toUpperCase(Locale.ENGLISH));
|
||||||
|
} else if ("font-style".equals(name)) {
|
||||||
|
fontStyle = FontStyle.valueOf(value.toUpperCase(Locale.ENGLISH));
|
||||||
|
} else if ("font-size".equals(name)) {
|
||||||
|
fontSize = Float.parseFloat(value);
|
||||||
|
} else if ("fill".equals(name)) {
|
||||||
|
fill = Color.parseColor(value);
|
||||||
|
} else if ("stroke".equals(name)) {
|
||||||
|
stroke = Color.parseColor(value);
|
||||||
|
} else if ("stroke-width".equals(name)) {
|
||||||
|
strokeWidth = Float.parseFloat(value);
|
||||||
|
} else {
|
||||||
|
RenderThemeHandler.logUnknownAttribute(elementName, name, value, i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
validate(elementName, textKey, fontSize, strokeWidth);
|
||||||
|
Typeface typeface = Typeface.create(fontFamily.toTypeface(), fontStyle.toInt());
|
||||||
|
return new Caption(textKey, dy, typeface, fontSize, fill, stroke, strokeWidth);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void validate(String elementName, String textKey, float fontSize, float strokeWidth) {
|
||||||
|
if (textKey == null) {
|
||||||
|
throw new IllegalArgumentException("missing attribute k for element: " + elementName);
|
||||||
|
} else if (fontSize < 0) {
|
||||||
|
throw new IllegalArgumentException("font-size must not be negative: " + fontSize);
|
||||||
|
} else if (strokeWidth < 0) {
|
||||||
|
throw new IllegalArgumentException("stroke-width must not be negative: " + strokeWidth);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private final float mDy;
|
||||||
|
private final float mFontSize;
|
||||||
|
private final Paint mPaint;
|
||||||
|
private final Paint mStroke;
|
||||||
|
private final String mTextKey;
|
||||||
|
|
||||||
|
private Caption(String textKey, float dy, Typeface typeface, float fontSize, int fill, int stroke, float strokeWidth) {
|
||||||
|
super();
|
||||||
|
|
||||||
|
mTextKey = textKey;
|
||||||
|
mDy = dy;
|
||||||
|
|
||||||
|
mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
|
||||||
|
mPaint.setTextAlign(Align.LEFT);
|
||||||
|
mPaint.setTypeface(typeface);
|
||||||
|
mPaint.setColor(fill);
|
||||||
|
|
||||||
|
mStroke = new Paint(Paint.ANTI_ALIAS_FLAG);
|
||||||
|
mStroke.setStyle(Style.STROKE);
|
||||||
|
mStroke.setTextAlign(Align.LEFT);
|
||||||
|
mStroke.setTypeface(typeface);
|
||||||
|
mStroke.setColor(stroke);
|
||||||
|
mStroke.setStrokeWidth(strokeWidth);
|
||||||
|
|
||||||
|
mFontSize = fontSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void destroy() {
|
||||||
|
// do nothing
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void renderNode(RenderCallback renderCallback, Tag[] tags) {
|
||||||
|
renderCallback.renderPointOfInterestCaption(mTextKey, mDy, mPaint, mStroke);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void renderWay(RenderCallback renderCallback, Tag[] tags) {
|
||||||
|
renderCallback.renderAreaCaption(mTextKey, mDy, mPaint, mStroke);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void scaleStrokeWidth(float scaleFactor) {
|
||||||
|
// do nothing
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void scaleTextSize(float scaleFactor) {
|
||||||
|
mPaint.setTextSize(mFontSize * scaleFactor);
|
||||||
|
mStroke.setTextSize(mFontSize * scaleFactor);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,154 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010, 2011, 2012 mapsforge.org
|
||||||
|
*
|
||||||
|
* 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.mapsforge.android.rendertheme.renderinstruction;
|
||||||
|
|
||||||
|
import org.mapsforge.android.rendertheme.RenderCallback;
|
||||||
|
import org.mapsforge.android.rendertheme.RenderThemeHandler;
|
||||||
|
import org.mapsforge.core.Tag;
|
||||||
|
import org.xml.sax.Attributes;
|
||||||
|
|
||||||
|
import android.graphics.Color;
|
||||||
|
import android.graphics.Paint;
|
||||||
|
import android.graphics.Paint.Style;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents a round area on the map.
|
||||||
|
*/
|
||||||
|
public final class Circle implements RenderInstruction {
|
||||||
|
/**
|
||||||
|
* @param elementName
|
||||||
|
* the name of the XML element.
|
||||||
|
* @param attributes
|
||||||
|
* the attributes of the XML element.
|
||||||
|
* @param level
|
||||||
|
* the drawing level of this instruction.
|
||||||
|
* @return a new Circle with the given rendering attributes.
|
||||||
|
*/
|
||||||
|
public static Circle create(String elementName, Attributes attributes, int level) {
|
||||||
|
Float radius = null;
|
||||||
|
boolean scaleRadius = false;
|
||||||
|
int fill = Color.TRANSPARENT;
|
||||||
|
int stroke = Color.TRANSPARENT;
|
||||||
|
float strokeWidth = 0;
|
||||||
|
|
||||||
|
for (int i = 0; i < attributes.getLength(); ++i) {
|
||||||
|
String name = attributes.getLocalName(i);
|
||||||
|
String value = attributes.getValue(i);
|
||||||
|
|
||||||
|
if ("r".equals(name)) {
|
||||||
|
radius = Float.valueOf(Float.parseFloat(value));
|
||||||
|
} else if ("scale-radius".equals(name)) {
|
||||||
|
scaleRadius = Boolean.parseBoolean(value);
|
||||||
|
} else if ("fill".equals(name)) {
|
||||||
|
fill = Color.parseColor(value);
|
||||||
|
} else if ("stroke".equals(name)) {
|
||||||
|
stroke = Color.parseColor(value);
|
||||||
|
} else if ("stroke-width".equals(name)) {
|
||||||
|
strokeWidth = Float.parseFloat(value);
|
||||||
|
} else {
|
||||||
|
RenderThemeHandler.logUnknownAttribute(elementName, name, value, i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
validate(elementName, radius, strokeWidth);
|
||||||
|
return new Circle(radius, scaleRadius, fill, stroke, strokeWidth, level);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void validate(String elementName, Float radius, float strokeWidth) {
|
||||||
|
if (radius == null) {
|
||||||
|
throw new IllegalArgumentException("missing attribute r for element: " + elementName);
|
||||||
|
} else if (radius.floatValue() < 0) {
|
||||||
|
throw new IllegalArgumentException("radius must not be negative: " + radius);
|
||||||
|
} else if (strokeWidth < 0) {
|
||||||
|
throw new IllegalArgumentException("stroke-width must not be negative: " + strokeWidth);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private final Paint mFill;
|
||||||
|
private final int mLevel;
|
||||||
|
private final Paint mOutline;
|
||||||
|
private final float mRadius;
|
||||||
|
private float mRenderRadius;
|
||||||
|
private final boolean mScaleRadius;
|
||||||
|
private final float mStrokeWidth;
|
||||||
|
|
||||||
|
private Circle(Float radius, boolean scaleRadius, int fill, int stroke, float strokeWidth, int level) {
|
||||||
|
super();
|
||||||
|
|
||||||
|
mRadius = radius.floatValue();
|
||||||
|
mScaleRadius = scaleRadius;
|
||||||
|
|
||||||
|
if (fill == Color.TRANSPARENT) {
|
||||||
|
mFill = null;
|
||||||
|
} else {
|
||||||
|
mFill = new Paint(Paint.ANTI_ALIAS_FLAG);
|
||||||
|
mFill.setStyle(Style.FILL);
|
||||||
|
mFill.setColor(fill);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (stroke == Color.TRANSPARENT) {
|
||||||
|
mOutline = null;
|
||||||
|
} else {
|
||||||
|
mOutline = new Paint(Paint.ANTI_ALIAS_FLAG);
|
||||||
|
mOutline.setStyle(Style.STROKE);
|
||||||
|
mOutline.setColor(stroke);
|
||||||
|
}
|
||||||
|
|
||||||
|
mStrokeWidth = strokeWidth;
|
||||||
|
mLevel = level;
|
||||||
|
|
||||||
|
if (!mScaleRadius) {
|
||||||
|
mRenderRadius = mRadius;
|
||||||
|
if (mOutline != null) {
|
||||||
|
mOutline.setStrokeWidth(mStrokeWidth);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void destroy() {
|
||||||
|
// do nothing
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void renderNode(RenderCallback renderCallback, Tag[] tags) {
|
||||||
|
if (mOutline != null) {
|
||||||
|
renderCallback.renderPointOfInterestCircle(mRenderRadius, mOutline, mLevel);
|
||||||
|
}
|
||||||
|
if (mFill != null) {
|
||||||
|
renderCallback.renderPointOfInterestCircle(mRenderRadius, mFill, mLevel);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void renderWay(RenderCallback renderCallback, Tag[] tags) {
|
||||||
|
// do nothing
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void scaleStrokeWidth(float scaleFactor) {
|
||||||
|
if (mScaleRadius) {
|
||||||
|
mRenderRadius = mRadius * scaleFactor;
|
||||||
|
if (mOutline != null) {
|
||||||
|
mOutline.setStrokeWidth(mStrokeWidth * scaleFactor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void scaleTextSize(float scaleFactor) {
|
||||||
|
// do nothing
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,42 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010, 2011, 2012 mapsforge.org
|
||||||
|
*
|
||||||
|
* 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.mapsforge.android.rendertheme.renderinstruction;
|
||||||
|
|
||||||
|
import android.graphics.Typeface;
|
||||||
|
|
||||||
|
enum FontFamily {
|
||||||
|
DEFAULT, DEFAULT_BOLD, MONOSPACE, SANS_SERIF, SERIF;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the typeface object of this FontFamily.
|
||||||
|
* @see <a href="http://developer.android.com/reference/android/graphics/Typeface.html">Typeface</a>
|
||||||
|
*/
|
||||||
|
Typeface toTypeface() {
|
||||||
|
switch (this) {
|
||||||
|
case DEFAULT:
|
||||||
|
return Typeface.DEFAULT;
|
||||||
|
case DEFAULT_BOLD:
|
||||||
|
return Typeface.DEFAULT_BOLD;
|
||||||
|
case MONOSPACE:
|
||||||
|
return Typeface.MONOSPACE;
|
||||||
|
case SANS_SERIF:
|
||||||
|
return Typeface.SANS_SERIF;
|
||||||
|
case SERIF:
|
||||||
|
return Typeface.SERIF;
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new IllegalArgumentException("unknown enum value: " + this);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,38 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010, 2011, 2012 mapsforge.org
|
||||||
|
*
|
||||||
|
* 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.mapsforge.android.rendertheme.renderinstruction;
|
||||||
|
|
||||||
|
enum FontStyle {
|
||||||
|
BOLD, BOLD_ITALIC, ITALIC, NORMAL;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the constant int value of this FontStyle.
|
||||||
|
* @see <a href="http://developer.android.com/reference/android/graphics/Typeface.html">Typeface</a>
|
||||||
|
*/
|
||||||
|
int toInt() {
|
||||||
|
switch (this) {
|
||||||
|
case BOLD:
|
||||||
|
return 1;
|
||||||
|
case BOLD_ITALIC:
|
||||||
|
return 3;
|
||||||
|
case ITALIC:
|
||||||
|
return 2;
|
||||||
|
case NORMAL:
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new IllegalArgumentException("unknown enum value: " + this);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,182 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010, 2011, 2012 mapsforge.org
|
||||||
|
*
|
||||||
|
* 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.mapsforge.android.rendertheme.renderinstruction;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.Locale;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
|
import org.mapsforge.android.rendertheme.RenderCallback;
|
||||||
|
import org.mapsforge.android.rendertheme.RenderThemeHandler;
|
||||||
|
import org.mapsforge.core.Tag;
|
||||||
|
import org.xml.sax.Attributes;
|
||||||
|
|
||||||
|
import android.graphics.Color;
|
||||||
|
import android.graphics.DashPathEffect;
|
||||||
|
import android.graphics.Paint;
|
||||||
|
import android.graphics.Paint.Cap;
|
||||||
|
import android.graphics.Paint.Style;
|
||||||
|
import android.graphics.Shader;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents a polyline on the map.
|
||||||
|
*/
|
||||||
|
public final class Line implements RenderInstruction {
|
||||||
|
private static final Pattern SPLIT_PATTERN = Pattern.compile(",");
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param elementName
|
||||||
|
* the name of the XML element.
|
||||||
|
* @param attributes
|
||||||
|
* the attributes of the XML element.
|
||||||
|
* @param level
|
||||||
|
* the drawing level of this instruction.
|
||||||
|
* @return a new Line with the given rendering attributes.
|
||||||
|
* @throws IOException
|
||||||
|
* if an I/O error occurs while reading a resource.
|
||||||
|
*/
|
||||||
|
public static Line create(String elementName, Attributes attributes, int level) throws IOException {
|
||||||
|
String src = null;
|
||||||
|
int stroke = Color.BLACK;
|
||||||
|
float strokeWidth = 0;
|
||||||
|
float[] strokeDasharray = null;
|
||||||
|
Cap strokeLinecap = Cap.ROUND;
|
||||||
|
int outline = -1;
|
||||||
|
// int fade = -1;
|
||||||
|
boolean fixed = false;
|
||||||
|
|
||||||
|
for (int i = 0; i < attributes.getLength(); ++i) {
|
||||||
|
String name = attributes.getLocalName(i);
|
||||||
|
String value = attributes.getValue(i);
|
||||||
|
|
||||||
|
if ("src".equals(name)) {
|
||||||
|
src = value;
|
||||||
|
} else if ("stroke".equals(name)) {
|
||||||
|
stroke = Color.parseColor(value);
|
||||||
|
} else if ("stroke-width".equals(name)) {
|
||||||
|
strokeWidth = Float.parseFloat(value);
|
||||||
|
} else if ("stroke-dasharray".equals(name)) {
|
||||||
|
strokeDasharray = parseFloatArray(value);
|
||||||
|
} else if ("stroke-linecap".equals(name)) {
|
||||||
|
strokeLinecap = Cap.valueOf(value.toUpperCase(Locale.ENGLISH));
|
||||||
|
} else if ("outline".equals(name)) {
|
||||||
|
outline = Integer.parseInt(value);
|
||||||
|
} else if ("fade".equals(name)) {
|
||||||
|
// fade = Integer.parseInt(value);
|
||||||
|
} else if ("fixed".equals(name)) {
|
||||||
|
fixed = Boolean.parseBoolean(value);
|
||||||
|
} else {
|
||||||
|
RenderThemeHandler.logUnknownAttribute(elementName, name, value, i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
validate(strokeWidth);
|
||||||
|
return new Line(src, stroke, strokeWidth, strokeDasharray, strokeLinecap, level, outline, fixed);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void validate(float strokeWidth) {
|
||||||
|
if (strokeWidth < 0) {
|
||||||
|
throw new IllegalArgumentException("stroke-width must not be negative: " + strokeWidth);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static float[] parseFloatArray(String dashString) {
|
||||||
|
String[] dashEntries = SPLIT_PATTERN.split(dashString);
|
||||||
|
float[] dashIntervals = new float[dashEntries.length];
|
||||||
|
for (int i = 0; i < dashEntries.length; ++i) {
|
||||||
|
dashIntervals[i] = Float.parseFloat(dashEntries[i]);
|
||||||
|
}
|
||||||
|
return dashIntervals;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public final int level;
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public final Paint paint;
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public final float strokeWidth;
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public final boolean round;
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public final int color;
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public final int outline;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public final boolean fixed;
|
||||||
|
|
||||||
|
private Line(String src, int stroke, float strokeWidth, float[] strokeDasharray, Cap strokeLinecap, int level,
|
||||||
|
int outline, boolean fixed)
|
||||||
|
throws IOException {
|
||||||
|
super();
|
||||||
|
|
||||||
|
Shader shader = BitmapUtils.createBitmapShader(src);
|
||||||
|
|
||||||
|
paint = new Paint(Paint.ANTI_ALIAS_FLAG);
|
||||||
|
paint.setShader(shader);
|
||||||
|
paint.setStyle(Style.STROKE);
|
||||||
|
paint.setColor(stroke);
|
||||||
|
if (strokeDasharray != null) {
|
||||||
|
paint.setPathEffect(new DashPathEffect(strokeDasharray, 0));
|
||||||
|
}
|
||||||
|
paint.setStrokeCap(strokeLinecap);
|
||||||
|
round = strokeLinecap == Cap.ROUND;
|
||||||
|
this.color = stroke;
|
||||||
|
this.strokeWidth = strokeWidth;
|
||||||
|
this.level = level;
|
||||||
|
this.outline = outline;
|
||||||
|
this.fixed = fixed;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void destroy() {
|
||||||
|
// do nothing
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void renderNode(RenderCallback renderCallback, Tag[] tags) {
|
||||||
|
// do nothing
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void renderWay(RenderCallback renderCallback, Tag[] tags) {
|
||||||
|
// renderCallback.renderWay(mPaint, mLevel, mColor, mStrokeWidth, mRound, mOutline);
|
||||||
|
renderCallback.renderWay(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void scaleStrokeWidth(float scaleFactor) {
|
||||||
|
paint.setStrokeWidth(strokeWidth * scaleFactor);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void scaleTextSize(float scaleFactor) {
|
||||||
|
// do nothing
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,105 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010, 2011, 2012 mapsforge.org
|
||||||
|
*
|
||||||
|
* 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.mapsforge.android.rendertheme.renderinstruction;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
import org.mapsforge.android.rendertheme.RenderCallback;
|
||||||
|
import org.mapsforge.android.rendertheme.RenderThemeHandler;
|
||||||
|
import org.mapsforge.core.Tag;
|
||||||
|
import org.xml.sax.Attributes;
|
||||||
|
|
||||||
|
import android.graphics.Bitmap;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents an icon along a polyline on the map.
|
||||||
|
*/
|
||||||
|
public final class LineSymbol implements RenderInstruction {
|
||||||
|
/**
|
||||||
|
* @param elementName
|
||||||
|
* the name of the XML element.
|
||||||
|
* @param attributes
|
||||||
|
* the attributes of the XML element.
|
||||||
|
* @return a new LineSymbol with the given rendering attributes.
|
||||||
|
* @throws IOException
|
||||||
|
* if an I/O error occurs while reading a resource.
|
||||||
|
*/
|
||||||
|
public static LineSymbol create(String elementName, Attributes attributes) throws IOException {
|
||||||
|
String src = null;
|
||||||
|
boolean alignCenter = false;
|
||||||
|
boolean repeat = false;
|
||||||
|
|
||||||
|
for (int i = 0; i < attributes.getLength(); ++i) {
|
||||||
|
String name = attributes.getLocalName(i);
|
||||||
|
String value = attributes.getValue(i);
|
||||||
|
|
||||||
|
if ("src".equals(name)) {
|
||||||
|
src = value;
|
||||||
|
} else if ("align-center".equals(name)) {
|
||||||
|
alignCenter = Boolean.parseBoolean(value);
|
||||||
|
} else if ("repeat".equals(name)) {
|
||||||
|
repeat = Boolean.parseBoolean(value);
|
||||||
|
} else {
|
||||||
|
RenderThemeHandler.logUnknownAttribute(elementName, name, value, i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
validate(elementName, src);
|
||||||
|
return new LineSymbol(src, alignCenter, repeat);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void validate(String elementName, String src) {
|
||||||
|
if (src == null) {
|
||||||
|
throw new IllegalArgumentException("missing attribute src for element: " + elementName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private final boolean mAlignCenter;
|
||||||
|
private final Bitmap mBitmap;
|
||||||
|
private final boolean mRepeat;
|
||||||
|
|
||||||
|
private LineSymbol(String src, boolean alignCenter, boolean repeat) throws IOException {
|
||||||
|
super();
|
||||||
|
|
||||||
|
mBitmap = BitmapUtils.createBitmap(src);
|
||||||
|
mAlignCenter = alignCenter;
|
||||||
|
mRepeat = repeat;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void destroy() {
|
||||||
|
mBitmap.recycle();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void renderNode(RenderCallback renderCallback, Tag[] tags) {
|
||||||
|
// do nothing
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void renderWay(RenderCallback renderCallback, Tag[] tags) {
|
||||||
|
renderCallback.renderWaySymbol(mBitmap, mAlignCenter, mRepeat);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void scaleStrokeWidth(float scaleFactor) {
|
||||||
|
// do nothing
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void scaleTextSize(float scaleFactor) {
|
||||||
|
// do nothing
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,138 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010, 2011, 2012 mapsforge.org
|
||||||
|
*
|
||||||
|
* 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.mapsforge.android.rendertheme.renderinstruction;
|
||||||
|
|
||||||
|
import java.util.Locale;
|
||||||
|
|
||||||
|
import org.mapsforge.android.rendertheme.RenderCallback;
|
||||||
|
import org.mapsforge.android.rendertheme.RenderThemeHandler;
|
||||||
|
import org.mapsforge.core.Tag;
|
||||||
|
import org.xml.sax.Attributes;
|
||||||
|
|
||||||
|
import android.graphics.Color;
|
||||||
|
import android.graphics.Paint;
|
||||||
|
import android.graphics.Paint.Align;
|
||||||
|
import android.graphics.Paint.Style;
|
||||||
|
import android.graphics.Typeface;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents a text along a polyline on the map.
|
||||||
|
*/
|
||||||
|
public final class PathText implements RenderInstruction {
|
||||||
|
/**
|
||||||
|
* @param elementName
|
||||||
|
* the name of the XML element.
|
||||||
|
* @param attributes
|
||||||
|
* the attributes of the XML element.
|
||||||
|
* @return a new PathText with the given rendering attributes.
|
||||||
|
*/
|
||||||
|
public static PathText create(String elementName, Attributes attributes) {
|
||||||
|
String textKey = null;
|
||||||
|
FontFamily fontFamily = FontFamily.DEFAULT;
|
||||||
|
FontStyle fontStyle = FontStyle.NORMAL;
|
||||||
|
float fontSize = 0;
|
||||||
|
int fill = Color.BLACK;
|
||||||
|
int stroke = Color.BLACK;
|
||||||
|
float strokeWidth = 0;
|
||||||
|
|
||||||
|
for (int i = 0; i < attributes.getLength(); ++i) {
|
||||||
|
String name = attributes.getLocalName(i);
|
||||||
|
String value = attributes.getValue(i);
|
||||||
|
|
||||||
|
if ("k".equals(name)) {
|
||||||
|
textKey = TextKey.getInstance(value);
|
||||||
|
} else if ("font-family".equals(name)) {
|
||||||
|
fontFamily = FontFamily.valueOf(value.toUpperCase(Locale.ENGLISH));
|
||||||
|
} else if ("font-style".equals(name)) {
|
||||||
|
fontStyle = FontStyle.valueOf(value.toUpperCase(Locale.ENGLISH));
|
||||||
|
} else if ("font-size".equals(name)) {
|
||||||
|
fontSize = Float.parseFloat(value);
|
||||||
|
} else if ("fill".equals(name)) {
|
||||||
|
fill = Color.parseColor(value);
|
||||||
|
} else if ("stroke".equals(name)) {
|
||||||
|
stroke = Color.parseColor(value);
|
||||||
|
} else if ("stroke-width".equals(name)) {
|
||||||
|
strokeWidth = Float.parseFloat(value);
|
||||||
|
} else {
|
||||||
|
RenderThemeHandler.logUnknownAttribute(elementName, name, value, i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
validate(elementName, textKey, fontSize, strokeWidth);
|
||||||
|
Typeface typeface = Typeface.create(fontFamily.toTypeface(), fontStyle.toInt());
|
||||||
|
return new PathText(textKey, typeface, fontSize, fill, stroke, strokeWidth);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void validate(String elementName, String textKey, float fontSize, float strokeWidth) {
|
||||||
|
if (textKey == null) {
|
||||||
|
throw new IllegalArgumentException("missing attribute k for element: " + elementName);
|
||||||
|
} else if (fontSize < 0) {
|
||||||
|
throw new IllegalArgumentException("font-size must not be negative: " + fontSize);
|
||||||
|
} else if (strokeWidth < 0) {
|
||||||
|
throw new IllegalArgumentException("stroke-width must not be negative: " + strokeWidth);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private final float mFontSize;
|
||||||
|
private final Paint mPaint;
|
||||||
|
private final Paint mStroke;
|
||||||
|
private final String mTextKey;
|
||||||
|
|
||||||
|
private PathText(String textKey, Typeface typeface, float fontSize, int fill, int stroke, float strokeWidth) {
|
||||||
|
super();
|
||||||
|
|
||||||
|
mTextKey = textKey;
|
||||||
|
|
||||||
|
mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
|
||||||
|
mPaint.setTextAlign(Align.CENTER);
|
||||||
|
mPaint.setTypeface(typeface);
|
||||||
|
mPaint.setColor(fill);
|
||||||
|
|
||||||
|
mStroke = new Paint(Paint.ANTI_ALIAS_FLAG);
|
||||||
|
mStroke.setStyle(Style.STROKE);
|
||||||
|
mStroke.setTextAlign(Align.CENTER);
|
||||||
|
mStroke.setTypeface(typeface);
|
||||||
|
mStroke.setColor(stroke);
|
||||||
|
mStroke.setStrokeWidth(strokeWidth);
|
||||||
|
|
||||||
|
mFontSize = fontSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void destroy() {
|
||||||
|
// do nothing
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void renderNode(RenderCallback renderCallback, Tag[] tags) {
|
||||||
|
// do nothing
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void renderWay(RenderCallback renderCallback, Tag[] tags) {
|
||||||
|
renderCallback.renderWayText(mTextKey, mPaint, mStroke);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void scaleStrokeWidth(float scaleFactor) {
|
||||||
|
// do nothing
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void scaleTextSize(float scaleFactor) {
|
||||||
|
mPaint.setTextSize(mFontSize * scaleFactor);
|
||||||
|
mStroke.setTextSize(mFontSize * scaleFactor);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,60 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010, 2011, 2012 mapsforge.org
|
||||||
|
*
|
||||||
|
* 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.mapsforge.android.rendertheme.renderinstruction;
|
||||||
|
|
||||||
|
import org.mapsforge.android.rendertheme.RenderCallback;
|
||||||
|
import org.mapsforge.core.Tag;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A RenderInstruction is a basic graphical primitive to draw a map.
|
||||||
|
*/
|
||||||
|
public interface RenderInstruction {
|
||||||
|
/**
|
||||||
|
* Destroys this RenderInstruction and cleans up all its internal resources.
|
||||||
|
*/
|
||||||
|
void destroy();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param renderCallback
|
||||||
|
* a reference to the receiver of all render callbacks.
|
||||||
|
* @param tags
|
||||||
|
* the tags of the node.
|
||||||
|
*/
|
||||||
|
void renderNode(RenderCallback renderCallback, Tag[] tags);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param renderCallback
|
||||||
|
* a reference to the receiver of all render callbacks.
|
||||||
|
* @param tags
|
||||||
|
* the tags of the way.
|
||||||
|
*/
|
||||||
|
void renderWay(RenderCallback renderCallback, Tag[] tags);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Scales the stroke width of this RenderInstruction by the given factor.
|
||||||
|
*
|
||||||
|
* @param scaleFactor
|
||||||
|
* the factor by which the stroke width should be scaled.
|
||||||
|
*/
|
||||||
|
void scaleStrokeWidth(float scaleFactor);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Scales the text size of this RenderInstruction by the given factor.
|
||||||
|
*
|
||||||
|
* @param scaleFactor
|
||||||
|
* the factor by which the text size should be scaled.
|
||||||
|
*/
|
||||||
|
void scaleTextSize(float scaleFactor);
|
||||||
|
}
|
||||||
@@ -0,0 +1,95 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010, 2011, 2012 mapsforge.org
|
||||||
|
*
|
||||||
|
* 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.mapsforge.android.rendertheme.renderinstruction;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
import org.mapsforge.android.rendertheme.RenderCallback;
|
||||||
|
import org.mapsforge.android.rendertheme.RenderThemeHandler;
|
||||||
|
import org.mapsforge.core.Tag;
|
||||||
|
import org.xml.sax.Attributes;
|
||||||
|
|
||||||
|
import android.graphics.Bitmap;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents an icon on the map.
|
||||||
|
*/
|
||||||
|
public final class Symbol implements RenderInstruction {
|
||||||
|
/**
|
||||||
|
* @param elementName
|
||||||
|
* the name of the XML element.
|
||||||
|
* @param attributes
|
||||||
|
* the attributes of the XML element.
|
||||||
|
* @return a new Symbol with the given rendering attributes.
|
||||||
|
* @throws IOException
|
||||||
|
* if an I/O error occurs while reading a resource.
|
||||||
|
*/
|
||||||
|
public static Symbol create(String elementName, Attributes attributes) throws IOException {
|
||||||
|
String src = null;
|
||||||
|
|
||||||
|
for (int i = 0; i < attributes.getLength(); ++i) {
|
||||||
|
String name = attributes.getLocalName(i);
|
||||||
|
String value = attributes.getValue(i);
|
||||||
|
|
||||||
|
if ("src".equals(name)) {
|
||||||
|
src = value;
|
||||||
|
} else {
|
||||||
|
RenderThemeHandler.logUnknownAttribute(elementName, name, value, i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
validate(elementName, src);
|
||||||
|
return new Symbol(src);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void validate(String elementName, String src) {
|
||||||
|
if (src == null) {
|
||||||
|
throw new IllegalArgumentException("missing attribute src for element: " + elementName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private final Bitmap mBitmap;
|
||||||
|
|
||||||
|
private Symbol(String src) throws IOException {
|
||||||
|
super();
|
||||||
|
|
||||||
|
mBitmap = BitmapUtils.createBitmap(src);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void destroy() {
|
||||||
|
mBitmap.recycle();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void renderNode(RenderCallback renderCallback, Tag[] tags) {
|
||||||
|
renderCallback.renderPointOfInterestSymbol(mBitmap);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void renderWay(RenderCallback renderCallback, Tag[] tags) {
|
||||||
|
renderCallback.renderAreaSymbol(mBitmap);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void scaleStrokeWidth(float scaleFactor) {
|
||||||
|
// do nothing
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void scaleTextSize(float scaleFactor) {
|
||||||
|
// do nothing
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010, 2011, 2012 mapsforge.org
|
||||||
|
*
|
||||||
|
* 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.mapsforge.android.rendertheme.renderinstruction;
|
||||||
|
|
||||||
|
import org.mapsforge.core.Tag;
|
||||||
|
|
||||||
|
final class TextKey {
|
||||||
|
static String getInstance(String key) {
|
||||||
|
if (Tag.TAG_KEY_ELE.equals(key)) {
|
||||||
|
return Tag.TAG_KEY_ELE;
|
||||||
|
} else if (Tag.TAG_KEY_HOUSE_NUMBER.equals(key)) {
|
||||||
|
return Tag.TAG_KEY_HOUSE_NUMBER;
|
||||||
|
} else if (Tag.TAG_KEY_NAME.equals(key)) {
|
||||||
|
return Tag.TAG_KEY_NAME;
|
||||||
|
} else if (Tag.TAG_KEY_REF.equals(key)) {
|
||||||
|
return Tag.TAG_KEY_REF;
|
||||||
|
} else {
|
||||||
|
throw new IllegalArgumentException("invalid key: " + key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
254
src/org/mapsforge/android/swrenderer/CanvasRasterer.java
Normal file
254
src/org/mapsforge/android/swrenderer/CanvasRasterer.java
Normal file
@@ -0,0 +1,254 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010, 2011, 2012 mapsforge.org
|
||||||
|
*
|
||||||
|
* 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.mapsforge.android.swrenderer;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.mapsforge.core.Tile;
|
||||||
|
|
||||||
|
import android.graphics.Bitmap;
|
||||||
|
import android.graphics.Canvas;
|
||||||
|
import android.graphics.Color;
|
||||||
|
import android.graphics.Matrix;
|
||||||
|
import android.graphics.Paint;
|
||||||
|
import android.graphics.Path;
|
||||||
|
import android.graphics.Typeface;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A CanvasRasterer uses a Canvas for drawing.
|
||||||
|
*
|
||||||
|
* @see <a href="http://developer.android.com/reference/android/graphics/Canvas.html">Canvas</a>
|
||||||
|
*/
|
||||||
|
class CanvasRasterer {
|
||||||
|
private static final Paint PAINT_BITMAP_FILTER = new Paint(Paint.FILTER_BITMAP_FLAG);
|
||||||
|
private static final Paint PAINT_TILE_COORDINATES = new Paint(Paint.ANTI_ALIAS_FLAG);
|
||||||
|
private static final Paint PAINT_TILE_COORDINATES_STROKE = new Paint(Paint.ANTI_ALIAS_FLAG);
|
||||||
|
private static final Paint PAINT_TILE_FRAME = new Paint();
|
||||||
|
|
||||||
|
private static final Paint PAINT_MARK = new Paint();
|
||||||
|
static final int COLOR_MARK = Color.argb(30, 0, 255, 0);
|
||||||
|
|
||||||
|
// private static final float[] TILE_FRAME = new float[] { 0, 0, 0, Tile.TILE_SIZE, 0, Tile.TILE_SIZE,
|
||||||
|
// Tile.TILE_SIZE,
|
||||||
|
// Tile.TILE_SIZE, Tile.TILE_SIZE, Tile.TILE_SIZE, Tile.TILE_SIZE, 0 };
|
||||||
|
|
||||||
|
private static void configurePaints() {
|
||||||
|
PAINT_TILE_COORDINATES.setTypeface(Typeface.defaultFromStyle(Typeface.BOLD));
|
||||||
|
PAINT_TILE_COORDINATES.setTextSize(12);
|
||||||
|
|
||||||
|
PAINT_TILE_COORDINATES_STROKE.setTypeface(Typeface.defaultFromStyle(Typeface.BOLD));
|
||||||
|
PAINT_TILE_COORDINATES_STROKE.setStyle(Paint.Style.STROKE);
|
||||||
|
PAINT_TILE_COORDINATES_STROKE.setStrokeWidth(1);
|
||||||
|
PAINT_TILE_COORDINATES_STROKE.setTextSize(6);
|
||||||
|
PAINT_TILE_COORDINATES_STROKE.setColor(Color.WHITE);
|
||||||
|
PAINT_MARK.setColor(COLOR_MARK);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private final Canvas mCanvas;
|
||||||
|
private final Path mPath;
|
||||||
|
private final Matrix mSymbolMatrix;
|
||||||
|
|
||||||
|
private float mScaleFactor;
|
||||||
|
|
||||||
|
CanvasRasterer() {
|
||||||
|
mCanvas = new Canvas();
|
||||||
|
mSymbolMatrix = new Matrix();
|
||||||
|
mPath = new Path();
|
||||||
|
mPath.setFillType(Path.FillType.EVEN_ODD);
|
||||||
|
mScaleFactor = 1;
|
||||||
|
configurePaints();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private void drawTileCoordinate(String string, int offsetY) {
|
||||||
|
mCanvas.drawText(string, 20, offsetY, PAINT_TILE_COORDINATES);
|
||||||
|
}
|
||||||
|
|
||||||
|
void drawNodes(List<PointTextContainer> pointTextContainers) {
|
||||||
|
|
||||||
|
for (int index = pointTextContainers.size() - 1; index >= 0; --index) {
|
||||||
|
PointTextContainer pointTextContainer = pointTextContainers.get(index);
|
||||||
|
|
||||||
|
if (pointTextContainer.paintBack != null) {
|
||||||
|
|
||||||
|
mCanvas.drawText(pointTextContainer.text, pointTextContainer.x * mScaleFactor, pointTextContainer.y
|
||||||
|
* mScaleFactor, pointTextContainer.paintBack);
|
||||||
|
}
|
||||||
|
|
||||||
|
mCanvas.drawText(pointTextContainer.text, pointTextContainer.x * mScaleFactor, pointTextContainer.y
|
||||||
|
* mScaleFactor, pointTextContainer.paintFront);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void drawSymbols(List<SymbolContainer> symbolContainers) {
|
||||||
|
for (int index = symbolContainers.size() - 1; index >= 0; --index) {
|
||||||
|
SymbolContainer symbolContainer = symbolContainers.get(index);
|
||||||
|
|
||||||
|
if (symbolContainer.alignCenter) {
|
||||||
|
int pivotX = symbolContainer.symbol.getWidth() >> 1;
|
||||||
|
int pivotY = symbolContainer.symbol.getHeight() >> 1;
|
||||||
|
mSymbolMatrix.setRotate(symbolContainer.rotation, pivotX, pivotY);
|
||||||
|
mSymbolMatrix.postTranslate(symbolContainer.x - pivotX, symbolContainer.y - pivotY);
|
||||||
|
} else {
|
||||||
|
mSymbolMatrix.setRotate(symbolContainer.rotation);
|
||||||
|
mSymbolMatrix.postTranslate(symbolContainer.x, symbolContainer.y);
|
||||||
|
}
|
||||||
|
mSymbolMatrix.postTranslate(mScaleFactor, mScaleFactor);
|
||||||
|
|
||||||
|
// symbolMatrix.postScale(zoomFactor, zoomFactor);
|
||||||
|
mCanvas.drawBitmap(symbolContainer.symbol, mSymbolMatrix, PAINT_BITMAP_FILTER);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void drawTileCoordinates(Tile tile, long time_load, long time_draw, long blub, long blah) {
|
||||||
|
|
||||||
|
drawTileCoordinate(tile.tileX + " / " + tile.tileY + " / " + tile.zoomLevel + " " + mScaleFactor, 20);
|
||||||
|
|
||||||
|
drawTileCoordinate("l:" + time_load, 40);
|
||||||
|
drawTileCoordinate("d:" + time_draw, 60);
|
||||||
|
drawTileCoordinate("+:" + blub, 80);
|
||||||
|
drawTileCoordinate("-:" + blah, 100);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void drawTileFrame() {
|
||||||
|
float size = (Tile.TILE_SIZE * mScaleFactor);
|
||||||
|
float[] frame = new float[] { 0, 0, 0, size - 1, 0, size - 1, size - 1, size - 1, size - 1, size - 1, size - 1,
|
||||||
|
0 };
|
||||||
|
mCanvas.drawLines(frame, PAINT_TILE_FRAME);
|
||||||
|
}
|
||||||
|
|
||||||
|
void drawWayNames(float[] coords, List<WayTextContainer> wayTextContainers) {
|
||||||
|
|
||||||
|
for (int index = wayTextContainers.size() - 1; index >= 0; --index) {
|
||||||
|
WayTextContainer wayTextContainer = wayTextContainers.get(index);
|
||||||
|
mPath.rewind();
|
||||||
|
|
||||||
|
int first = wayTextContainer.first;
|
||||||
|
int last = wayTextContainer.last;
|
||||||
|
|
||||||
|
// int len = wayTextContainer.wayDataContainer.length[0];
|
||||||
|
// int pos = wayTextContainer.wayDataContainer.position[0];
|
||||||
|
|
||||||
|
// System.arraycopy(floats, pos, coords, 0, len);
|
||||||
|
|
||||||
|
if (coords[first] < coords[last]) {
|
||||||
|
mPath.moveTo(coords[first], coords[first + 1]);
|
||||||
|
|
||||||
|
for (int i = first + 2; i <= last; i += 2) {
|
||||||
|
mPath.lineTo(coords[i], coords[i + 1]);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
mPath.moveTo(coords[last], coords[last + 1]);
|
||||||
|
|
||||||
|
for (int i = last - 2; i >= first; i -= 2) {
|
||||||
|
mPath.lineTo(coords[i], coords[i + 1]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
mCanvas.drawTextOnPath(wayTextContainer.text, mPath, 0, 3, wayTextContainer.paint);
|
||||||
|
|
||||||
|
// if (wayTextContainer.match)
|
||||||
|
// canvas.drawRect(wayTextContainer.x1,
|
||||||
|
// wayTextContainer.top, wayTextContainer.x2,
|
||||||
|
// wayTextContainer.bot, PAINT_MARK);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void drawWays(float[] coords, LayerContainer[] drawWays) {
|
||||||
|
int levels = drawWays[0].mLevelActive.length;
|
||||||
|
|
||||||
|
for (LayerContainer layerContainer : drawWays) {
|
||||||
|
if (!layerContainer.mActive)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
for (int level = 0; level < levels; level++) {
|
||||||
|
|
||||||
|
if (!layerContainer.mLevelActive[level])
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// mPath.rewind();
|
||||||
|
|
||||||
|
LevelContainer levelContainer = layerContainer.mLevels[level];
|
||||||
|
|
||||||
|
for (int way = levelContainer.mShapeContainers.size() - 1; way >= 0; way--) {
|
||||||
|
mPath.rewind();
|
||||||
|
// switch (shapePaintContainer.shapeContainer.getShapeType()) {
|
||||||
|
//
|
||||||
|
// case WAY:
|
||||||
|
WayDataContainer wayDataContainer = (WayDataContainer) levelContainer.mShapeContainers.get(way);
|
||||||
|
// (WayDataContainer) shapePaintContainer.shapeContainer;
|
||||||
|
|
||||||
|
// if (wayDataContainer.closed) {
|
||||||
|
for (int i = 0, n = wayDataContainer.length.length; i < n; i++) {
|
||||||
|
|
||||||
|
int len = wayDataContainer.length[i];
|
||||||
|
int pos = wayDataContainer.position[i];
|
||||||
|
if (len > 2) {
|
||||||
|
mPath.moveTo(coords[pos], coords[pos + 1]);
|
||||||
|
|
||||||
|
for (int j = pos + 2; j < len + pos; j += 2)
|
||||||
|
mPath.lineTo(coords[j], coords[j + 1]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
mCanvas.drawPath(mPath, levelContainer.mPaint[0]);
|
||||||
|
if (levelContainer.mPaint[1] != null)
|
||||||
|
mCanvas.drawPath(mPath, levelContainer.mPaint[1]);
|
||||||
|
|
||||||
|
// }else {
|
||||||
|
// for (int i = 0, n = wayDataContainer.length.length; i < n; i++) {
|
||||||
|
// // levelContainer.mPaint[0].setStrokeJoin(Join.ROUND);
|
||||||
|
//
|
||||||
|
// int len = wayDataContainer.length[i];
|
||||||
|
// int pos = wayDataContainer.position[i];
|
||||||
|
// if (len > 2) {
|
||||||
|
// mCanvas.drawPoints(coords, pos, len, levelContainer.mPaint[0]);
|
||||||
|
// if (levelContainer.mPaint[1] != null)
|
||||||
|
// mCanvas.drawPoints(coords, pos, len, levelContainer.mPaint[1]);
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// break;
|
||||||
|
|
||||||
|
// case CIRCLE:
|
||||||
|
// CircleContainer circleContainer =
|
||||||
|
// (CircleContainer) shapePaintContainer.shapeContainer;
|
||||||
|
//
|
||||||
|
// mPath.rewind();
|
||||||
|
//
|
||||||
|
// mPath.addCircle(circleContainer.mX, circleContainer.mY,
|
||||||
|
// circleContainer.mRadius, Path.Direction.CCW);
|
||||||
|
//
|
||||||
|
// mCanvas.drawPath(mPath, shapePaintContainer.paint);
|
||||||
|
// break;
|
||||||
|
// }
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void fill(int color) {
|
||||||
|
mCanvas.drawColor(color);
|
||||||
|
}
|
||||||
|
|
||||||
|
void setCanvasBitmap(Bitmap bitmap, float scale) {
|
||||||
|
mCanvas.setBitmap(bitmap);
|
||||||
|
// add some extra pixels to avoid < 1px blank edges while scaling
|
||||||
|
mCanvas.clipRect(0, 0, Tile.TILE_SIZE * scale + 2, Tile.TILE_SIZE * scale + 2);
|
||||||
|
mScaleFactor = scale;
|
||||||
|
}
|
||||||
|
}
|
||||||
33
src/org/mapsforge/android/swrenderer/CircleContainer.java
Normal file
33
src/org/mapsforge/android/swrenderer/CircleContainer.java
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010, 2011, 2012 mapsforge.org
|
||||||
|
*
|
||||||
|
* 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.mapsforge.android.swrenderer;
|
||||||
|
|
||||||
|
|
||||||
|
class CircleContainer implements ShapeContainer {
|
||||||
|
final float mRadius;
|
||||||
|
final float mX;
|
||||||
|
final float mY;
|
||||||
|
|
||||||
|
CircleContainer(float x, float y, float radius) {
|
||||||
|
mX = x;
|
||||||
|
mY = y;
|
||||||
|
mRadius = radius;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ShapeType getShapeType() {
|
||||||
|
return ShapeType.CIRCLE;
|
||||||
|
}
|
||||||
|
}
|
||||||
581
src/org/mapsforge/android/swrenderer/DatabaseRenderer.java
Normal file
581
src/org/mapsforge/android/swrenderer/DatabaseRenderer.java
Normal file
@@ -0,0 +1,581 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010, 2011, 2012 mapsforge.org
|
||||||
|
*
|
||||||
|
* 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.mapsforge.android.swrenderer;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import javax.xml.parsers.ParserConfigurationException;
|
||||||
|
|
||||||
|
import org.mapsforge.android.MapView;
|
||||||
|
import org.mapsforge.android.mapgenerator.JobTheme;
|
||||||
|
import org.mapsforge.android.mapgenerator.MapGenerator;
|
||||||
|
import org.mapsforge.android.mapgenerator.MapGeneratorJob;
|
||||||
|
import org.mapsforge.android.rendertheme.RenderCallback;
|
||||||
|
import org.mapsforge.android.rendertheme.RenderTheme;
|
||||||
|
import org.mapsforge.android.rendertheme.RenderThemeHandler;
|
||||||
|
import org.mapsforge.android.rendertheme.renderinstruction.Area;
|
||||||
|
import org.mapsforge.android.rendertheme.renderinstruction.Line;
|
||||||
|
import org.mapsforge.core.GeoPoint;
|
||||||
|
import org.mapsforge.core.Tag;
|
||||||
|
import org.mapsforge.core.Tile;
|
||||||
|
import org.mapsforge.mapdatabase.IMapDatabase;
|
||||||
|
import org.mapsforge.mapdatabase.IMapDatabaseCallback;
|
||||||
|
import org.mapsforge.mapdatabase.MapFileInfo;
|
||||||
|
import org.mapsforge.mapdatabase.mapfile.MapDatabase;
|
||||||
|
import org.xml.sax.SAXException;
|
||||||
|
|
||||||
|
import android.graphics.Bitmap;
|
||||||
|
import android.graphics.Color;
|
||||||
|
import android.graphics.Paint;
|
||||||
|
import android.util.FloatMath;
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A DatabaseRenderer renders map tiles by reading from a {@link MapDatabase}.
|
||||||
|
*/
|
||||||
|
public class DatabaseRenderer implements MapGenerator, RenderCallback, IMapDatabaseCallback {
|
||||||
|
private static String TAG = DatabaseRenderer.class.getName();
|
||||||
|
private static final Byte DEFAULT_START_ZOOM_LEVEL = Byte.valueOf((byte) 12);
|
||||||
|
private static final byte LAYERS = 11;
|
||||||
|
private static final Paint PAINT_WATER_TILE_HIGHTLIGHT = new Paint(Paint.ANTI_ALIAS_FLAG);
|
||||||
|
private static final double STROKE_INCREASE = 1.5;
|
||||||
|
private static final byte STROKE_MIN_ZOOM_LEVEL = 12;
|
||||||
|
|
||||||
|
private static final byte ZOOM_MAX = 22;
|
||||||
|
|
||||||
|
// private static MapRenderer mMapRenderer;
|
||||||
|
|
||||||
|
private static RenderTheme getRenderTheme(JobTheme jobTheme) {
|
||||||
|
InputStream inputStream = null;
|
||||||
|
try {
|
||||||
|
inputStream = jobTheme.getRenderThemeAsStream();
|
||||||
|
return RenderThemeHandler.getRenderTheme(inputStream);
|
||||||
|
} catch (ParserConfigurationException e) {
|
||||||
|
Log.e(TAG, e.getMessage());
|
||||||
|
} catch (SAXException e) {
|
||||||
|
Log.e(TAG, e.getMessage());
|
||||||
|
} catch (IOException e) {
|
||||||
|
Log.e(TAG, e.getMessage());
|
||||||
|
} finally {
|
||||||
|
try {
|
||||||
|
if (inputStream != null) {
|
||||||
|
inputStream.close();
|
||||||
|
}
|
||||||
|
} catch (IOException e) {
|
||||||
|
Log.e(TAG, e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static byte getValidLayer(byte layer) {
|
||||||
|
if (layer < 0) {
|
||||||
|
return 0;
|
||||||
|
} else if (layer >= LAYERS) {
|
||||||
|
return LAYERS - 1;
|
||||||
|
} else {
|
||||||
|
return layer;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private final CanvasRasterer mCanvasRasterer;
|
||||||
|
|
||||||
|
private LayerContainer mDrawingLayer;
|
||||||
|
private final LabelPlacement mLabelPlacement;
|
||||||
|
private IMapDatabase mMapDatabase;
|
||||||
|
private List<PointTextContainer> mNodes;
|
||||||
|
private float mPoiX;
|
||||||
|
private float mPoiY;
|
||||||
|
private JobTheme mPreviousJobTheme;
|
||||||
|
private float mPreviousTextScale;
|
||||||
|
private byte mPreviousZoomLevel;
|
||||||
|
private static RenderTheme renderTheme;
|
||||||
|
|
||||||
|
private final List<WayTextContainer> mWayNames;
|
||||||
|
private final LayerContainer[] mWays;
|
||||||
|
private final List<SymbolContainer> mWaySymbols;
|
||||||
|
private final List<SymbolContainer> mPointSymbols;
|
||||||
|
private final List<PointTextContainer> mAreaLabels;
|
||||||
|
|
||||||
|
// private float mLat1, mLat2, mLon1, mLon2;
|
||||||
|
// private float mTileWidth, mTileHeight;
|
||||||
|
private float mScale;
|
||||||
|
|
||||||
|
// private float[] mCoordinates;
|
||||||
|
private WayDataContainer mWayDataContainer;
|
||||||
|
private final Bitmap mTileBitmap;
|
||||||
|
|
||||||
|
private static float PI180 = (float) (Math.PI / 180) / 1000000.0f;
|
||||||
|
private static float PIx4 = (float) Math.PI * 4;
|
||||||
|
|
||||||
|
private Tile mCurrentTile;
|
||||||
|
private static long mCurrentTileY;
|
||||||
|
private static long mCurrentTileX;
|
||||||
|
private static long mCurrentTileZoom;
|
||||||
|
|
||||||
|
private float[] mCoords = null;
|
||||||
|
|
||||||
|
// private long _renderTime;
|
||||||
|
private int _nodes, _nodesDropped;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a new DatabaseRenderer.
|
||||||
|
*/
|
||||||
|
public DatabaseRenderer() {
|
||||||
|
mCanvasRasterer = new CanvasRasterer();
|
||||||
|
mLabelPlacement = new LabelPlacement();
|
||||||
|
|
||||||
|
mWays = new LayerContainer[LAYERS];
|
||||||
|
mWayNames = new ArrayList<WayTextContainer>(64);
|
||||||
|
mNodes = new ArrayList<PointTextContainer>(64);
|
||||||
|
mAreaLabels = new ArrayList<PointTextContainer>(64);
|
||||||
|
mWaySymbols = new ArrayList<SymbolContainer>(64);
|
||||||
|
mPointSymbols = new ArrayList<SymbolContainer>(64);
|
||||||
|
|
||||||
|
PAINT_WATER_TILE_HIGHTLIGHT.setStyle(Paint.Style.FILL);
|
||||||
|
PAINT_WATER_TILE_HIGHTLIGHT.setColor(Color.CYAN);
|
||||||
|
// mCoordinates = new float[1024];
|
||||||
|
|
||||||
|
mTileBitmap = Bitmap.createBitmap(Tile.TILE_SIZE * 2, Tile.TILE_SIZE * 2, Bitmap.Config.RGB_565);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void cleanup() {
|
||||||
|
mTileBitmap.recycle();
|
||||||
|
if (DatabaseRenderer.renderTheme != null) {
|
||||||
|
DatabaseRenderer.renderTheme.destroy();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean executeJob(MapGeneratorJob mapGeneratorJob) {
|
||||||
|
long time_load = System.currentTimeMillis();
|
||||||
|
_nodes = 0;
|
||||||
|
_nodesDropped = 0;
|
||||||
|
// _renderTime = 0;
|
||||||
|
|
||||||
|
mCurrentTile = mapGeneratorJob.tile;
|
||||||
|
mCurrentTileZoom = ((long) Tile.TILE_SIZE << mCurrentTile.zoomLevel);
|
||||||
|
mCurrentTileX = mCurrentTile.pixelX;
|
||||||
|
mCurrentTileY = mCurrentTile.pixelY;
|
||||||
|
|
||||||
|
// mLon1 = (float) MercatorProjection.pixelXToLongitude(mCurrentTileX, mCurrentTile.zoomLevel) * 1000000;
|
||||||
|
// mLat1 = (float) MercatorProjection.pixelYToLatitude(mCurrentTileY, mCurrentTile.zoomLevel) * 1000000;
|
||||||
|
// mLon2 = (float) MercatorProjection.pixelXToLongitude(mCurrentTileX + Tile.TILE_SIZE, mCurrentTile.zoomLevel)
|
||||||
|
// * 1000000;
|
||||||
|
// mLat2 = (float) MercatorProjection.pixelYToLatitude(mCurrentTileY + Tile.TILE_SIZE, mCurrentTile.zoomLevel) *
|
||||||
|
// 1000000;
|
||||||
|
//
|
||||||
|
// mTileWidth = mLon2 - mLon1;
|
||||||
|
// mTileHeight = mLat1 - mLat2;
|
||||||
|
mScale = mapGeneratorJob.getScale();
|
||||||
|
|
||||||
|
JobTheme jobTheme = mapGeneratorJob.jobParameters.jobTheme;
|
||||||
|
if (!jobTheme.equals(mPreviousJobTheme)) {
|
||||||
|
if (DatabaseRenderer.renderTheme == null)
|
||||||
|
DatabaseRenderer.renderTheme = getRenderTheme(jobTheme);
|
||||||
|
if (DatabaseRenderer.renderTheme == null) {
|
||||||
|
mPreviousJobTheme = null;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
createWayLists();
|
||||||
|
mPreviousJobTheme = jobTheme;
|
||||||
|
mPreviousZoomLevel = Byte.MIN_VALUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
byte zoomLevel = mCurrentTile.zoomLevel;
|
||||||
|
if (zoomLevel != mPreviousZoomLevel) {
|
||||||
|
setScaleStrokeWidth(zoomLevel);
|
||||||
|
mPreviousZoomLevel = zoomLevel;
|
||||||
|
}
|
||||||
|
|
||||||
|
float textScale = mapGeneratorJob.jobParameters.textScale;
|
||||||
|
if (textScale != mPreviousTextScale) {
|
||||||
|
DatabaseRenderer.renderTheme.scaleTextSize(textScale);
|
||||||
|
mPreviousTextScale = textScale;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mMapDatabase != null) {
|
||||||
|
mMapDatabase.executeQuery(mCurrentTile, this);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
time_load = System.currentTimeMillis() - time_load;
|
||||||
|
|
||||||
|
mNodes = mLabelPlacement.placeLabels(mNodes, mPointSymbols, mAreaLabels, mCurrentTile);
|
||||||
|
|
||||||
|
long time_draw = System.currentTimeMillis();
|
||||||
|
|
||||||
|
// FIXME mCoords = mMapDatabase.getCoordinates();
|
||||||
|
|
||||||
|
mCanvasRasterer.setCanvasBitmap(mTileBitmap, mScale);
|
||||||
|
mCanvasRasterer.fill(DatabaseRenderer.renderTheme.getMapBackground());
|
||||||
|
mCanvasRasterer.drawWays(mCoords, mWays);
|
||||||
|
mCanvasRasterer.drawSymbols(mWaySymbols);
|
||||||
|
mCanvasRasterer.drawSymbols(mPointSymbols);
|
||||||
|
mCanvasRasterer.drawWayNames(mCoords, mWayNames);
|
||||||
|
mCanvasRasterer.drawNodes(mNodes);
|
||||||
|
mCanvasRasterer.drawNodes(mAreaLabels);
|
||||||
|
time_draw = System.currentTimeMillis() - time_draw;
|
||||||
|
|
||||||
|
if (mapGeneratorJob.debugSettings.mDrawTileFrames) {
|
||||||
|
mCanvasRasterer.drawTileFrame();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mapGeneratorJob.debugSettings.mDrawTileCoordinates) {
|
||||||
|
mCanvasRasterer.drawTileCoordinates(mCurrentTile, time_load, time_draw, _nodes, _nodesDropped);
|
||||||
|
}
|
||||||
|
|
||||||
|
clearLists();
|
||||||
|
|
||||||
|
mapGeneratorJob.setBitmap(mTileBitmap);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public GeoPoint getStartPoint() {
|
||||||
|
if (mMapDatabase != null && mMapDatabase.hasOpenFile()) {
|
||||||
|
MapFileInfo mapFileInfo = mMapDatabase.getMapFileInfo();
|
||||||
|
if (mapFileInfo.startPosition != null) {
|
||||||
|
return mapFileInfo.startPosition;
|
||||||
|
} else if (mapFileInfo.mapCenter != null) {
|
||||||
|
return mapFileInfo.mapCenter;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Byte getStartZoomLevel() {
|
||||||
|
if (mMapDatabase != null && mMapDatabase.hasOpenFile()) {
|
||||||
|
MapFileInfo mapFileInfo = mMapDatabase.getMapFileInfo();
|
||||||
|
if (mapFileInfo.startZoomLevel != null) {
|
||||||
|
return mapFileInfo.startZoomLevel;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return DEFAULT_START_ZOOM_LEVEL;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public byte getZoomLevelMax() {
|
||||||
|
return ZOOM_MAX;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void renderAreaCaption(String textKey, float verticalOffset, Paint paint, Paint stroke) {
|
||||||
|
// mapDatabase.readTag(caption);
|
||||||
|
// if (caption.value != null) {
|
||||||
|
// float[] centerPosition = GeometryUtils
|
||||||
|
// .calculateCenterOfBoundingBox(coordinates[0]);
|
||||||
|
// areaLabels.add(new PointTextContainer(caption.value,
|
||||||
|
// centerPosition[0],
|
||||||
|
// centerPosition[1],
|
||||||
|
// paint, stroke));
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void renderAreaSymbol(Bitmap symbol) {
|
||||||
|
// float[] centerPosition = GeometryUtils
|
||||||
|
// .calculateCenterOfBoundingBox(coordinates[0]);
|
||||||
|
// pointSymbols.add(new SymbolContainer(symbol, centerPosition[0]
|
||||||
|
// - (symbol.getWidth() >> 1), centerPosition[1]
|
||||||
|
// - (symbol.getHeight() >> 1)));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void renderPointOfInterest(byte layer, int latitude, int longitude, Tag[] tags) {
|
||||||
|
mDrawingLayer = mWays[getValidLayer(layer)];
|
||||||
|
mPoiX = scaleLongitude(longitude);
|
||||||
|
mPoiY = scaleLatitude(latitude);
|
||||||
|
DatabaseRenderer.renderTheme.matchNode(this, tags, mCurrentTile.zoomLevel);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void renderPointOfInterestCaption(String textKey, float verticalOffset, Paint paint, Paint stroke) {
|
||||||
|
// mapDatabase.readTag(caption);
|
||||||
|
// if (caption.value != null) {
|
||||||
|
// nodes.add(new PointTextContainer(caption.value, poiX, poiY + verticalOffset, paint, stroke));
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void renderPointOfInterestCircle(float radius, Paint outline, int level) {
|
||||||
|
|
||||||
|
mDrawingLayer.add(level, new CircleContainer(mPoiX, mPoiY, radius), outline);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void renderPointOfInterestSymbol(Bitmap symbol) {
|
||||||
|
mPointSymbols.add(new SymbolContainer(symbol, mPoiX - (symbol.getWidth() >> 1), mPoiY
|
||||||
|
- (symbol.getHeight() >> 1)));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void renderWaterBackground() {
|
||||||
|
// if (mCoords == null)
|
||||||
|
// mCoords = mMapDatabase.getCoordinates();
|
||||||
|
|
||||||
|
// float[] coords = mCoords;
|
||||||
|
//
|
||||||
|
// mDrawingLayer = mWays[5];
|
||||||
|
//
|
||||||
|
// int len = wayData.length[0];
|
||||||
|
// int pos = wayData.position[0];
|
||||||
|
//
|
||||||
|
// for (int j = pos, m = pos + len; j < m; j += 2) {
|
||||||
|
// coords[j] = coords[j] * mScale;
|
||||||
|
// coords[j + 1] = coords[j + 1] * mScale;
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// mWayDataContainer = wayData;
|
||||||
|
//
|
||||||
|
// Log.i("mapsforge", "render water");
|
||||||
|
//
|
||||||
|
// DatabaseRenderer.renderTheme.matchWay(this, tags, mCurrentTile.zoomLevel, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
// private boolean mPrevClosed = false;
|
||||||
|
// private byte mPrevLayer = 0;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void renderWay(byte layer, Tag[] tags, float[] wayNodes, int[] wayLengths, boolean changed) {
|
||||||
|
// if (mCoords == null)
|
||||||
|
// mCoords = mMapDatabase.getCoordinates();
|
||||||
|
|
||||||
|
// float[] coords = mCoords;
|
||||||
|
//
|
||||||
|
// boolean closed = false;
|
||||||
|
// boolean added = false;
|
||||||
|
//
|
||||||
|
// // coordinatesLength = wayData.length.length;
|
||||||
|
// if (mCurrentTile.zoomLevel < 6) {
|
||||||
|
// long x = mCurrentTileX;
|
||||||
|
// long y = mCurrentTileY;
|
||||||
|
// long z = mCurrentTileZoom;
|
||||||
|
// float s = mScale;
|
||||||
|
//
|
||||||
|
// added = true;
|
||||||
|
//
|
||||||
|
// for (int i = wayData.length.length - 1; i >= 0; i--) {
|
||||||
|
// int len = wayData.length[i];
|
||||||
|
// int pos = wayData.position[i];
|
||||||
|
//
|
||||||
|
// if (i == 0)
|
||||||
|
// closed = (coords[pos] == coords[(pos + len) - 2] &&
|
||||||
|
// coords[pos + 1] == coords[(pos + len) - 1]);
|
||||||
|
//
|
||||||
|
// for (int j = pos, m = pos + len; j < m; j += 2) {
|
||||||
|
//
|
||||||
|
// coords[j] = (float) (((coords[j] / 1000000.0 + 180) / 360 * z) - x) * s;
|
||||||
|
//
|
||||||
|
// double sinLat = Math.sin(coords[j + 1] * PI180);
|
||||||
|
// coords[j + 1] = (float) ((0.5 - Math.log((1 + sinLat) / (1 - sinLat)) / PIx4) * z - y) * s;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// } else {
|
||||||
|
// // use linear approximation on high zoom levels.
|
||||||
|
// float ssize = Tile.TILE_SIZE * mScale;
|
||||||
|
// float sw = ssize / mTileWidth;
|
||||||
|
// float sh = ssize / mTileHeight;
|
||||||
|
// int j, o;
|
||||||
|
// float x, y;
|
||||||
|
//
|
||||||
|
// int min = 1;
|
||||||
|
// if (mCurrentTile.zoomLevel < 14)
|
||||||
|
// min = 3;
|
||||||
|
// else if (mCurrentTile.zoomLevel < 9)
|
||||||
|
// min = 5;
|
||||||
|
//
|
||||||
|
// for (int i = wayData.length.length - 1; i >= 0; i--) {
|
||||||
|
//
|
||||||
|
// int len = wayData.length[i];
|
||||||
|
// int pos = wayData.position[i];
|
||||||
|
// _nodes += len / 2;
|
||||||
|
//
|
||||||
|
// if (i == 0) {
|
||||||
|
// closed = (coords[pos] == coords[(pos + len) - 2] &&
|
||||||
|
// coords[pos + 1] == coords[(pos + len) - 1]);
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// coords[pos] = (coords[pos] - mLon1) * sw;
|
||||||
|
// coords[pos + 1] = ssize - (coords[pos + 1] - mLat2) * sh;
|
||||||
|
//
|
||||||
|
// j = o = pos + 2;
|
||||||
|
//
|
||||||
|
// // drop intermediate nodes with less than 'min' distance.
|
||||||
|
// for (int m = pos + len - 2; j < m; j += 2) {
|
||||||
|
// x = (coords[j] - mLon1) * sw;
|
||||||
|
// y = ssize - (coords[j + 1] - mLat2) * sh;
|
||||||
|
//
|
||||||
|
// if (x > coords[o - 2] + min || x < coords[o - 2] - min ||
|
||||||
|
// y > coords[o - 1] + min || y < coords[o - 1] - min) {
|
||||||
|
//
|
||||||
|
// coords[o++] = x;
|
||||||
|
// coords[o++] = y;
|
||||||
|
// } else
|
||||||
|
// _nodesDropped++;
|
||||||
|
// }
|
||||||
|
// coords[o] = (coords[j] - mLon1) * sw;
|
||||||
|
// coords[o + 1] = ssize - (coords[j + 1] - mLat2) * sh;
|
||||||
|
// o += 2;
|
||||||
|
//
|
||||||
|
// wayData.length[i] = o - pos;
|
||||||
|
//
|
||||||
|
// if (!closed || (o - pos) > 4)
|
||||||
|
// added = true;
|
||||||
|
// else
|
||||||
|
// wayData.length[i] = 0;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// if (!added && !changed)
|
||||||
|
// return;
|
||||||
|
//
|
||||||
|
// mWayDataContainer = wayData;
|
||||||
|
//
|
||||||
|
// mDrawingLayer = mWays[getValidLayer(layer)];
|
||||||
|
//
|
||||||
|
// if (changed || (closed != mPrevClosed) || (layer != mPrevLayer)) {
|
||||||
|
// mCurLevelContainer1 = null;
|
||||||
|
// mCurLevelContainer2 = null;
|
||||||
|
// DatabaseRenderer.renderTheme.matchWay(this, tags, mCurrentTile.zoomLevel, closed);
|
||||||
|
// } else {
|
||||||
|
// if (mCurLevelContainer1 != null)
|
||||||
|
// mCurLevelContainer1.add(mWayDataContainer);
|
||||||
|
// if (mCurLevelContainer2 != null)
|
||||||
|
// mCurLevelContainer2.add(mWayDataContainer);
|
||||||
|
// }
|
||||||
|
// mPrevClosed = closed;
|
||||||
|
// mPrevLayer = layer;
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<ShapeContainer> mCurLevelContainer1;
|
||||||
|
private List<ShapeContainer> mCurLevelContainer2;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void renderWay(Line line) {
|
||||||
|
List<ShapeContainer> c = mDrawingLayer.add(line.level, mWayDataContainer, line.paint);
|
||||||
|
|
||||||
|
if (mCurLevelContainer1 == null)
|
||||||
|
mCurLevelContainer1 = c;
|
||||||
|
else if (mCurLevelContainer2 == null)
|
||||||
|
mCurLevelContainer2 = c;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void renderArea(Area area) {
|
||||||
|
if (area.paintFill != null)
|
||||||
|
mCurLevelContainer1 = mDrawingLayer.add(area.level, mWayDataContainer, area.paintFill);
|
||||||
|
if (area.paintOutline != null)
|
||||||
|
mCurLevelContainer1 = mDrawingLayer.add(area.level, mWayDataContainer, area.paintOutline);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void renderWaySymbol(Bitmap symbolBitmap, boolean alignCenter, boolean repeatSymbol) {
|
||||||
|
// WayDecorator.renderSymbol(symbolBitmap, alignCenter, repeatSymbol,
|
||||||
|
// coordinates,
|
||||||
|
// waySymbols);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void renderWayText(String textKey, Paint paint, Paint outline) {
|
||||||
|
// if (mWayDataContainer.textPos[0] >= 0)
|
||||||
|
// WayDecorator.renderText(this, paint, outline, mCoords, mWayDataContainer, mWayNames);
|
||||||
|
}
|
||||||
|
|
||||||
|
String getWayName() {
|
||||||
|
return mMapDatabase.readString(mWayDataContainer.textPos[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean requiresInternetConnection() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setMapDatabase(IMapDatabase mapDatabase) {
|
||||||
|
mMapDatabase = mapDatabase;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void clearLists() {
|
||||||
|
for (int i = LAYERS - 1; i >= 0; --i) {
|
||||||
|
mWays[i].clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
mAreaLabels.clear();
|
||||||
|
mNodes.clear();
|
||||||
|
mPointSymbols.clear();
|
||||||
|
mWayNames.clear();
|
||||||
|
mWaySymbols.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void createWayLists() {
|
||||||
|
int levels = DatabaseRenderer.renderTheme.getLevels();
|
||||||
|
for (byte i = LAYERS - 1; i >= 0; --i) {
|
||||||
|
mWays[i] = new LayerContainer(levels);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts a latitude value into an Y coordinate on the current tile.
|
||||||
|
*
|
||||||
|
* @param latitude
|
||||||
|
* the latitude value.
|
||||||
|
* @return the Y coordinate on the current tile.
|
||||||
|
*/
|
||||||
|
private static float scaleLatitude(float latitude) {
|
||||||
|
double sinLatitude = FloatMath.sin(latitude * PI180);
|
||||||
|
|
||||||
|
return (float) (0.5 - Math.log((1 + sinLatitude) / (1 - sinLatitude)) / PIx4) * mCurrentTileZoom
|
||||||
|
- mCurrentTileY;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts a longitude value into an X coordinate on the current tile.
|
||||||
|
*
|
||||||
|
* @param longitude
|
||||||
|
* the longitude value.
|
||||||
|
* @return the X coordinate on the current tile.
|
||||||
|
*/
|
||||||
|
|
||||||
|
private static float scaleLongitude(float longitude) {
|
||||||
|
return (float) ((longitude / 1000000.0 + 180) / 360 * mCurrentTileZoom) - mCurrentTileX;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the scale stroke factor for the given zoom level.
|
||||||
|
*
|
||||||
|
* @param zoomLevel
|
||||||
|
* the zoom level for which the scale stroke factor should be set.
|
||||||
|
*/
|
||||||
|
private static void setScaleStrokeWidth(byte zoomLevel) {
|
||||||
|
int zoomLevelDiff = Math.max(zoomLevel - STROKE_MIN_ZOOM_LEVEL, 0);
|
||||||
|
DatabaseRenderer.renderTheme.scaleStrokeWidth((float) Math.pow(STROKE_INCREASE, zoomLevelDiff));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public MapRenderer getMapRenderer(MapView mapView) {
|
||||||
|
return new MapRenderer(mapView);
|
||||||
|
}
|
||||||
|
}
|
||||||
985
src/org/mapsforge/android/swrenderer/DependencyCache.java
Normal file
985
src/org/mapsforge/android/swrenderer/DependencyCache.java
Normal file
@@ -0,0 +1,985 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010, 2011, 2012 mapsforge.org
|
||||||
|
*
|
||||||
|
* 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.mapsforge.android.swrenderer;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Hashtable;
|
||||||
|
import java.util.LinkedList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import org.mapsforge.core.Tile;
|
||||||
|
|
||||||
|
import android.graphics.Bitmap;
|
||||||
|
import android.graphics.Paint;
|
||||||
|
import android.graphics.Rect;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This class process the methods for the Dependency Cache. It's connected with the LabelPlacement class. The main goal
|
||||||
|
* is, to remove double labels and symbols that are already rendered, from the actual tile. Labels and symbols that,
|
||||||
|
* would be rendered on an already drawn Tile, will be deleted too.
|
||||||
|
*/
|
||||||
|
class DependencyCache {
|
||||||
|
/**
|
||||||
|
* The class holds the data for a symbol with dependencies on other tiles.
|
||||||
|
*
|
||||||
|
* @param <Type>
|
||||||
|
* only two types are reasonable. The DependencySymbol or DependencyText class.
|
||||||
|
*/
|
||||||
|
private static class Dependency<Type> {
|
||||||
|
ImmutablePoint point;
|
||||||
|
final Type value;
|
||||||
|
|
||||||
|
Dependency(Type value, ImmutablePoint point) {
|
||||||
|
this.value = value;
|
||||||
|
this.point = point;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This class holds all the information off the possible dependencies on a tile.
|
||||||
|
*/
|
||||||
|
private static class DependencyOnTile {
|
||||||
|
boolean drawn;
|
||||||
|
List<Dependency<DependencyText>> labels;
|
||||||
|
List<Dependency<DependencySymbol>> symbols;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize label, symbol and drawn.
|
||||||
|
*/
|
||||||
|
DependencyOnTile() {
|
||||||
|
this.labels = null;
|
||||||
|
this.symbols = null;
|
||||||
|
this.drawn = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param toAdd
|
||||||
|
* a dependency Symbol
|
||||||
|
*/
|
||||||
|
void addSymbol(Dependency<DependencySymbol> toAdd) {
|
||||||
|
if (this.symbols == null) {
|
||||||
|
this.symbols = new ArrayList<Dependency<DependencySymbol>>();
|
||||||
|
}
|
||||||
|
this.symbols.add(toAdd);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param toAdd
|
||||||
|
* a Dependency Text
|
||||||
|
*/
|
||||||
|
void addText(Dependency<DependencyText> toAdd) {
|
||||||
|
if (this.labels == null) {
|
||||||
|
this.labels = new ArrayList<Dependency<DependencyText>>();
|
||||||
|
}
|
||||||
|
this.labels.add(toAdd);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The class holds the data for a symbol with dependencies on other tiles.
|
||||||
|
*/
|
||||||
|
private static class DependencySymbol {
|
||||||
|
private final List<Tile> tiles;
|
||||||
|
Bitmap symbol;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a symbol dependency element for the dependency cache.
|
||||||
|
*
|
||||||
|
* @param symbol
|
||||||
|
* reference on the dependency symbol.
|
||||||
|
* @param tile
|
||||||
|
* dependency tile.
|
||||||
|
*/
|
||||||
|
DependencySymbol(Bitmap symbol, Tile tile) {
|
||||||
|
this.symbol = symbol;
|
||||||
|
this.tiles = new LinkedList<Tile>();
|
||||||
|
this.tiles.add(tile);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds an additional tile, which has an dependency with this symbol.
|
||||||
|
*
|
||||||
|
* @param tile
|
||||||
|
* additional tile.
|
||||||
|
*/
|
||||||
|
void addTile(Tile tile) {
|
||||||
|
this.tiles.add(tile);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The class holds the data for a label with dependencies on other tiles.
|
||||||
|
*/
|
||||||
|
private static class DependencyText {
|
||||||
|
final Rect boundary;
|
||||||
|
final Paint paintBack;
|
||||||
|
final Paint paintFront;
|
||||||
|
final String text;
|
||||||
|
List<Tile> tiles;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a text dependency in the dependency cache.
|
||||||
|
*
|
||||||
|
* @param paintFront
|
||||||
|
* paint element from the front.
|
||||||
|
* @param paintBack
|
||||||
|
* paint element form the background of the text.
|
||||||
|
* @param text
|
||||||
|
* the text of the element.
|
||||||
|
* @param boundary
|
||||||
|
* the fixed boundary with width and height.
|
||||||
|
* @param tile
|
||||||
|
* all tile in where the element has an influence.
|
||||||
|
*/
|
||||||
|
DependencyText(Paint paintFront, Paint paintBack, String text, Rect boundary, Tile tile) {
|
||||||
|
this.paintFront = paintFront;
|
||||||
|
this.paintBack = paintBack;
|
||||||
|
this.text = text;
|
||||||
|
this.tiles = new LinkedList<Tile>();
|
||||||
|
this.tiles.add(tile);
|
||||||
|
this.boundary = boundary;
|
||||||
|
}
|
||||||
|
|
||||||
|
void addTile(Tile tile) {
|
||||||
|
this.tiles.add(tile);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private DependencyOnTile currentDependencyOnTile;
|
||||||
|
private Tile currentTile;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Hash table, that connects the Tiles with their entries in the dependency cache.
|
||||||
|
*/
|
||||||
|
final Map<Tile, DependencyOnTile> dependencyTable;
|
||||||
|
Dependency<DependencyText> depLabel;
|
||||||
|
Rect rect1;
|
||||||
|
Rect rect2;
|
||||||
|
SymbolContainer smb;
|
||||||
|
DependencyOnTile tmp;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor for this class, that creates a hashtable for the dependencies.
|
||||||
|
*/
|
||||||
|
DependencyCache() {
|
||||||
|
this.dependencyTable = new Hashtable<Tile, DependencyOnTile>(60);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void addLabelsFromDependencyOnTile(List<PointTextContainer> labels) {
|
||||||
|
for (int i = 0; i < this.currentDependencyOnTile.labels.size(); i++) {
|
||||||
|
this.depLabel = this.currentDependencyOnTile.labels.get(i);
|
||||||
|
if (this.depLabel.value.paintBack != null) {
|
||||||
|
labels.add(new PointTextContainer(this.depLabel.value.text, this.depLabel.point.pointX,
|
||||||
|
this.depLabel.point.pointY, this.depLabel.value.paintFront, this.depLabel.value.paintBack));
|
||||||
|
} else {
|
||||||
|
labels.add(new PointTextContainer(this.depLabel.value.text, this.depLabel.point.pointX,
|
||||||
|
this.depLabel.point.pointY, this.depLabel.value.paintFront));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void addSymbolsFromDependencyOnTile(List<SymbolContainer> symbols) {
|
||||||
|
for (Dependency<DependencySymbol> depSmb : this.currentDependencyOnTile.symbols) {
|
||||||
|
symbols.add(new SymbolContainer(depSmb.value.symbol, depSmb.point.pointX, depSmb.point.pointY));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fills the dependency entry from the tile and the neighbor tiles with the dependency information, that are
|
||||||
|
* necessary for drawing. To do that every label and symbol that will be drawn, will be checked if it produces
|
||||||
|
* dependencies with other tiles.
|
||||||
|
*
|
||||||
|
* @param pTC
|
||||||
|
* list of the labels
|
||||||
|
*/
|
||||||
|
private void fillDependencyLabels(List<PointTextContainer> pTC) {
|
||||||
|
Tile left = new Tile(this.currentTile.tileX - 1, this.currentTile.tileY, this.currentTile.zoomLevel);
|
||||||
|
Tile right = new Tile(this.currentTile.tileX + 1, this.currentTile.tileY, this.currentTile.zoomLevel);
|
||||||
|
Tile up = new Tile(this.currentTile.tileX, this.currentTile.tileY - 1, this.currentTile.zoomLevel);
|
||||||
|
Tile down = new Tile(this.currentTile.tileX, this.currentTile.tileY + 1, this.currentTile.zoomLevel);
|
||||||
|
|
||||||
|
Tile leftup = new Tile(this.currentTile.tileX - 1, this.currentTile.tileY - 1, this.currentTile.zoomLevel);
|
||||||
|
Tile leftdown = new Tile(this.currentTile.tileX - 1, this.currentTile.tileY + 1, this.currentTile.zoomLevel);
|
||||||
|
Tile rightup = new Tile(this.currentTile.tileX + 1, this.currentTile.tileY - 1, this.currentTile.zoomLevel);
|
||||||
|
Tile rightdown = new Tile(this.currentTile.tileX + 1, this.currentTile.tileY + 1, this.currentTile.zoomLevel);
|
||||||
|
|
||||||
|
PointTextContainer label;
|
||||||
|
DependencyOnTile linkedDep;
|
||||||
|
DependencyText toAdd;
|
||||||
|
|
||||||
|
for (int i = 0; i < pTC.size(); i++) {
|
||||||
|
|
||||||
|
label = pTC.get(i);
|
||||||
|
|
||||||
|
toAdd = null;
|
||||||
|
|
||||||
|
// up
|
||||||
|
if ((label.y - label.boundary.height() < 0.0f) && (!this.dependencyTable.get(up).drawn)) {
|
||||||
|
linkedDep = this.dependencyTable.get(up);
|
||||||
|
|
||||||
|
toAdd = new DependencyText(label.paintFront, label.paintBack, label.text, label.boundary,
|
||||||
|
this.currentTile);
|
||||||
|
|
||||||
|
this.currentDependencyOnTile.addText(new Dependency<DependencyText>(toAdd, new ImmutablePoint(label.x,
|
||||||
|
label.y)));
|
||||||
|
|
||||||
|
linkedDep.addText(new Dependency<DependencyText>(toAdd, new ImmutablePoint(label.x, label.y
|
||||||
|
+ Tile.TILE_SIZE)));
|
||||||
|
|
||||||
|
toAdd.addTile(up);
|
||||||
|
|
||||||
|
if ((label.x < 0.0f) && (!this.dependencyTable.get(leftup).drawn)) {
|
||||||
|
linkedDep = this.dependencyTable.get(leftup);
|
||||||
|
|
||||||
|
linkedDep.addText(new Dependency<DependencyText>(toAdd, new ImmutablePoint(
|
||||||
|
label.x + Tile.TILE_SIZE, label.y + Tile.TILE_SIZE)));
|
||||||
|
|
||||||
|
toAdd.addTile(leftup);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((label.x + label.boundary.width() > Tile.TILE_SIZE) && (!this.dependencyTable.get(rightup).drawn)) {
|
||||||
|
linkedDep = this.dependencyTable.get(rightup);
|
||||||
|
|
||||||
|
linkedDep.addText(new Dependency<DependencyText>(toAdd, new ImmutablePoint(
|
||||||
|
label.x - Tile.TILE_SIZE, label.y + Tile.TILE_SIZE)));
|
||||||
|
|
||||||
|
toAdd.addTile(rightup);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// down
|
||||||
|
if ((label.y > Tile.TILE_SIZE) && (!this.dependencyTable.get(down).drawn)) {
|
||||||
|
|
||||||
|
linkedDep = this.dependencyTable.get(down);
|
||||||
|
|
||||||
|
if (toAdd == null) {
|
||||||
|
toAdd = new DependencyText(label.paintFront, label.paintBack, label.text, label.boundary,
|
||||||
|
this.currentTile);
|
||||||
|
|
||||||
|
this.currentDependencyOnTile.addText(new Dependency<DependencyText>(toAdd, new ImmutablePoint(
|
||||||
|
label.x, label.y)));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
linkedDep.addText(new Dependency<DependencyText>(toAdd, new ImmutablePoint(label.x, label.y
|
||||||
|
- Tile.TILE_SIZE)));
|
||||||
|
|
||||||
|
toAdd.addTile(down);
|
||||||
|
|
||||||
|
if ((label.x < 0.0f) && (!this.dependencyTable.get(leftdown).drawn)) {
|
||||||
|
linkedDep = this.dependencyTable.get(leftdown);
|
||||||
|
|
||||||
|
linkedDep.addText(new Dependency<DependencyText>(toAdd, new ImmutablePoint(
|
||||||
|
label.x + Tile.TILE_SIZE, label.y - Tile.TILE_SIZE)));
|
||||||
|
|
||||||
|
toAdd.addTile(leftdown);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((label.x + label.boundary.width() > Tile.TILE_SIZE) && (!this.dependencyTable.get(rightdown).drawn)) {
|
||||||
|
|
||||||
|
linkedDep = this.dependencyTable.get(rightdown);
|
||||||
|
|
||||||
|
linkedDep.addText(new Dependency<DependencyText>(toAdd, new ImmutablePoint(
|
||||||
|
label.x - Tile.TILE_SIZE, label.y - Tile.TILE_SIZE)));
|
||||||
|
|
||||||
|
toAdd.addTile(rightdown);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// left
|
||||||
|
|
||||||
|
if ((label.x < 0.0f) && (!this.dependencyTable.get(left).drawn)) {
|
||||||
|
linkedDep = this.dependencyTable.get(left);
|
||||||
|
|
||||||
|
if (toAdd == null) {
|
||||||
|
toAdd = new DependencyText(label.paintFront, label.paintBack, label.text, label.boundary,
|
||||||
|
this.currentTile);
|
||||||
|
|
||||||
|
this.currentDependencyOnTile.addText(new Dependency<DependencyText>(toAdd, new ImmutablePoint(
|
||||||
|
label.x, label.y)));
|
||||||
|
}
|
||||||
|
|
||||||
|
linkedDep.addText(new Dependency<DependencyText>(toAdd, new ImmutablePoint(label.x + Tile.TILE_SIZE,
|
||||||
|
label.y)));
|
||||||
|
|
||||||
|
toAdd.addTile(left);
|
||||||
|
}
|
||||||
|
// right
|
||||||
|
if ((label.x + label.boundary.width() > Tile.TILE_SIZE) && (!this.dependencyTable.get(right).drawn)) {
|
||||||
|
linkedDep = this.dependencyTable.get(right);
|
||||||
|
|
||||||
|
if (toAdd == null) {
|
||||||
|
toAdd = new DependencyText(label.paintFront, label.paintBack, label.text, label.boundary,
|
||||||
|
this.currentTile);
|
||||||
|
|
||||||
|
this.currentDependencyOnTile.addText(new Dependency<DependencyText>(toAdd, new ImmutablePoint(
|
||||||
|
label.x, label.y)));
|
||||||
|
}
|
||||||
|
|
||||||
|
linkedDep.addText(new Dependency<DependencyText>(toAdd, new ImmutablePoint(label.x - Tile.TILE_SIZE,
|
||||||
|
label.y)));
|
||||||
|
|
||||||
|
toAdd.addTile(right);
|
||||||
|
}
|
||||||
|
|
||||||
|
// check symbols
|
||||||
|
|
||||||
|
if ((label.symbol != null) && (toAdd == null)) {
|
||||||
|
|
||||||
|
if ((label.symbol.y <= 0.0f) && (!this.dependencyTable.get(up).drawn)) {
|
||||||
|
linkedDep = this.dependencyTable.get(up);
|
||||||
|
|
||||||
|
toAdd = new DependencyText(label.paintFront, label.paintBack, label.text, label.boundary,
|
||||||
|
this.currentTile);
|
||||||
|
|
||||||
|
this.currentDependencyOnTile.addText(new Dependency<DependencyText>(toAdd, new ImmutablePoint(
|
||||||
|
label.x, label.y)));
|
||||||
|
|
||||||
|
linkedDep.addText(new Dependency<DependencyText>(toAdd, new ImmutablePoint(label.x, label.y
|
||||||
|
+ Tile.TILE_SIZE)));
|
||||||
|
|
||||||
|
toAdd.addTile(up);
|
||||||
|
|
||||||
|
if ((label.symbol.x < 0.0f) && (!this.dependencyTable.get(leftup).drawn)) {
|
||||||
|
linkedDep = this.dependencyTable.get(leftup);
|
||||||
|
|
||||||
|
linkedDep.addText(new Dependency<DependencyText>(toAdd, new ImmutablePoint(label.x
|
||||||
|
+ Tile.TILE_SIZE, label.y + Tile.TILE_SIZE)));
|
||||||
|
|
||||||
|
toAdd.addTile(leftup);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((label.symbol.x + label.symbol.symbol.getWidth() > Tile.TILE_SIZE)
|
||||||
|
&& (!this.dependencyTable.get(rightup).drawn)) {
|
||||||
|
linkedDep = this.dependencyTable.get(rightup);
|
||||||
|
|
||||||
|
linkedDep.addText(new Dependency<DependencyText>(toAdd, new ImmutablePoint(label.x
|
||||||
|
- Tile.TILE_SIZE, label.y + Tile.TILE_SIZE)));
|
||||||
|
|
||||||
|
toAdd.addTile(rightup);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((label.symbol.y + label.symbol.symbol.getHeight() >= Tile.TILE_SIZE)
|
||||||
|
&& (!this.dependencyTable.get(down).drawn)) {
|
||||||
|
|
||||||
|
linkedDep = this.dependencyTable.get(down);
|
||||||
|
|
||||||
|
if (toAdd == null) {
|
||||||
|
toAdd = new DependencyText(label.paintFront, label.paintBack, label.text, label.boundary,
|
||||||
|
this.currentTile);
|
||||||
|
|
||||||
|
this.currentDependencyOnTile.addText(new Dependency<DependencyText>(toAdd, new ImmutablePoint(
|
||||||
|
label.x, label.y)));
|
||||||
|
}
|
||||||
|
|
||||||
|
linkedDep.addText(new Dependency<DependencyText>(toAdd, new ImmutablePoint(label.x, label.y
|
||||||
|
+ Tile.TILE_SIZE)));
|
||||||
|
|
||||||
|
toAdd.addTile(up);
|
||||||
|
|
||||||
|
if ((label.symbol.x < 0.0f) && (!this.dependencyTable.get(leftdown).drawn)) {
|
||||||
|
linkedDep = this.dependencyTable.get(leftdown);
|
||||||
|
|
||||||
|
linkedDep.addText(new Dependency<DependencyText>(toAdd, new ImmutablePoint(label.x
|
||||||
|
+ Tile.TILE_SIZE, label.y - Tile.TILE_SIZE)));
|
||||||
|
|
||||||
|
toAdd.addTile(leftdown);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((label.symbol.x + label.symbol.symbol.getWidth() > Tile.TILE_SIZE)
|
||||||
|
&& (!this.dependencyTable.get(rightdown).drawn)) {
|
||||||
|
|
||||||
|
linkedDep = this.dependencyTable.get(rightdown);
|
||||||
|
|
||||||
|
linkedDep.addText(new Dependency<DependencyText>(toAdd, new ImmutablePoint(label.x
|
||||||
|
- Tile.TILE_SIZE, label.y - Tile.TILE_SIZE)));
|
||||||
|
|
||||||
|
toAdd.addTile(rightdown);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((label.symbol.x <= 0.0f) && (!this.dependencyTable.get(left).drawn)) {
|
||||||
|
linkedDep = this.dependencyTable.get(left);
|
||||||
|
|
||||||
|
if (toAdd == null) {
|
||||||
|
toAdd = new DependencyText(label.paintFront, label.paintBack, label.text, label.boundary,
|
||||||
|
this.currentTile);
|
||||||
|
|
||||||
|
this.currentDependencyOnTile.addText(new Dependency<DependencyText>(toAdd, new ImmutablePoint(
|
||||||
|
label.x, label.y)));
|
||||||
|
}
|
||||||
|
|
||||||
|
linkedDep.addText(new Dependency<DependencyText>(toAdd, new ImmutablePoint(
|
||||||
|
label.x - Tile.TILE_SIZE, label.y)));
|
||||||
|
|
||||||
|
toAdd.addTile(left);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((label.symbol.x + label.symbol.symbol.getWidth() >= Tile.TILE_SIZE)
|
||||||
|
&& (!this.dependencyTable.get(right).drawn)) {
|
||||||
|
linkedDep = this.dependencyTable.get(right);
|
||||||
|
|
||||||
|
if (toAdd == null) {
|
||||||
|
toAdd = new DependencyText(label.paintFront, label.paintBack, label.text, label.boundary,
|
||||||
|
this.currentTile);
|
||||||
|
|
||||||
|
this.currentDependencyOnTile.addText(new Dependency<DependencyText>(toAdd, new ImmutablePoint(
|
||||||
|
label.x, label.y)));
|
||||||
|
}
|
||||||
|
|
||||||
|
linkedDep.addText(new Dependency<DependencyText>(toAdd, new ImmutablePoint(
|
||||||
|
label.x + Tile.TILE_SIZE, label.y)));
|
||||||
|
|
||||||
|
toAdd.addTile(right);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void fillDependencyOnTile2(List<PointTextContainer> labels, List<SymbolContainer> symbols,
|
||||||
|
List<PointTextContainer> areaLabels) {
|
||||||
|
Tile left = new Tile(this.currentTile.tileX - 1, this.currentTile.tileY, this.currentTile.zoomLevel);
|
||||||
|
Tile right = new Tile(this.currentTile.tileX + 1, this.currentTile.tileY, this.currentTile.zoomLevel);
|
||||||
|
Tile up = new Tile(this.currentTile.tileX, this.currentTile.tileY - 1, this.currentTile.zoomLevel);
|
||||||
|
Tile down = new Tile(this.currentTile.tileX, this.currentTile.tileY + 1, this.currentTile.zoomLevel);
|
||||||
|
|
||||||
|
Tile leftup = new Tile(this.currentTile.tileX - 1, this.currentTile.tileY - 1, this.currentTile.zoomLevel);
|
||||||
|
Tile leftdown = new Tile(this.currentTile.tileX - 1, this.currentTile.tileY + 1, this.currentTile.zoomLevel);
|
||||||
|
Tile rightup = new Tile(this.currentTile.tileX + 1, this.currentTile.tileY - 1, this.currentTile.zoomLevel);
|
||||||
|
Tile rightdown = new Tile(this.currentTile.tileX + 1, this.currentTile.tileY + 1, this.currentTile.zoomLevel);
|
||||||
|
|
||||||
|
if (this.dependencyTable.get(up) == null) {
|
||||||
|
this.dependencyTable.put(up, new DependencyOnTile());
|
||||||
|
}
|
||||||
|
if (this.dependencyTable.get(down) == null) {
|
||||||
|
this.dependencyTable.put(down, new DependencyOnTile());
|
||||||
|
}
|
||||||
|
if (this.dependencyTable.get(left) == null) {
|
||||||
|
this.dependencyTable.put(left, new DependencyOnTile());
|
||||||
|
}
|
||||||
|
if (this.dependencyTable.get(right) == null) {
|
||||||
|
this.dependencyTable.put(right, new DependencyOnTile());
|
||||||
|
}
|
||||||
|
if (this.dependencyTable.get(leftdown) == null) {
|
||||||
|
this.dependencyTable.put(leftdown, new DependencyOnTile());
|
||||||
|
}
|
||||||
|
if (this.dependencyTable.get(rightup) == null) {
|
||||||
|
this.dependencyTable.put(rightup, new DependencyOnTile());
|
||||||
|
}
|
||||||
|
if (this.dependencyTable.get(leftup) == null) {
|
||||||
|
this.dependencyTable.put(leftup, new DependencyOnTile());
|
||||||
|
}
|
||||||
|
if (this.dependencyTable.get(rightdown) == null) {
|
||||||
|
this.dependencyTable.put(rightdown, new DependencyOnTile());
|
||||||
|
}
|
||||||
|
|
||||||
|
fillDependencyLabels(labels);
|
||||||
|
fillDependencyLabels(areaLabels);
|
||||||
|
|
||||||
|
DependencyOnTile linkedDep;
|
||||||
|
DependencySymbol addSmb;
|
||||||
|
|
||||||
|
for (SymbolContainer symbol : symbols) {
|
||||||
|
addSmb = null;
|
||||||
|
|
||||||
|
// up
|
||||||
|
if ((symbol.y < 0.0f) && (!this.dependencyTable.get(up).drawn)) {
|
||||||
|
linkedDep = this.dependencyTable.get(up);
|
||||||
|
|
||||||
|
addSmb = new DependencySymbol(symbol.symbol, this.currentTile);
|
||||||
|
this.currentDependencyOnTile.addSymbol(new Dependency<DependencySymbol>(addSmb, new ImmutablePoint(
|
||||||
|
symbol.x, symbol.y)));
|
||||||
|
|
||||||
|
linkedDep.addSymbol(new Dependency<DependencySymbol>(addSmb, new ImmutablePoint(symbol.x, symbol.y
|
||||||
|
+ Tile.TILE_SIZE)));
|
||||||
|
addSmb.addTile(up);
|
||||||
|
|
||||||
|
if ((symbol.x < 0.0f) && (!this.dependencyTable.get(leftup).drawn)) {
|
||||||
|
linkedDep = this.dependencyTable.get(leftup);
|
||||||
|
|
||||||
|
linkedDep.addSymbol(new Dependency<DependencySymbol>(addSmb, new ImmutablePoint(symbol.x
|
||||||
|
+ Tile.TILE_SIZE, symbol.y + Tile.TILE_SIZE)));
|
||||||
|
addSmb.addTile(leftup);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((symbol.x + symbol.symbol.getWidth() > Tile.TILE_SIZE)
|
||||||
|
&& (!this.dependencyTable.get(rightup).drawn)) {
|
||||||
|
linkedDep = this.dependencyTable.get(rightup);
|
||||||
|
|
||||||
|
linkedDep.addSymbol(new Dependency<DependencySymbol>(addSmb, new ImmutablePoint(symbol.x
|
||||||
|
- Tile.TILE_SIZE, symbol.y + Tile.TILE_SIZE)));
|
||||||
|
addSmb.addTile(rightup);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// down
|
||||||
|
if ((symbol.y + symbol.symbol.getHeight() > Tile.TILE_SIZE) && (!this.dependencyTable.get(down).drawn)) {
|
||||||
|
|
||||||
|
linkedDep = this.dependencyTable.get(down);
|
||||||
|
|
||||||
|
if (addSmb == null) {
|
||||||
|
addSmb = new DependencySymbol(symbol.symbol, this.currentTile);
|
||||||
|
this.currentDependencyOnTile.addSymbol(new Dependency<DependencySymbol>(addSmb, new ImmutablePoint(
|
||||||
|
symbol.x, symbol.y)));
|
||||||
|
}
|
||||||
|
|
||||||
|
linkedDep.addSymbol(new Dependency<DependencySymbol>(addSmb, new ImmutablePoint(symbol.x, symbol.y
|
||||||
|
- Tile.TILE_SIZE)));
|
||||||
|
addSmb.addTile(down);
|
||||||
|
|
||||||
|
if ((symbol.x < 0.0f) && (!this.dependencyTable.get(leftdown).drawn)) {
|
||||||
|
linkedDep = this.dependencyTable.get(leftdown);
|
||||||
|
|
||||||
|
linkedDep.addSymbol(new Dependency<DependencySymbol>(addSmb, new ImmutablePoint(symbol.x
|
||||||
|
+ Tile.TILE_SIZE, symbol.y - Tile.TILE_SIZE)));
|
||||||
|
addSmb.addTile(leftdown);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((symbol.x + symbol.symbol.getWidth() > Tile.TILE_SIZE)
|
||||||
|
&& (!this.dependencyTable.get(rightdown).drawn)) {
|
||||||
|
|
||||||
|
linkedDep = this.dependencyTable.get(rightdown);
|
||||||
|
|
||||||
|
linkedDep.addSymbol(new Dependency<DependencySymbol>(addSmb, new ImmutablePoint(symbol.x
|
||||||
|
- Tile.TILE_SIZE, symbol.y - Tile.TILE_SIZE)));
|
||||||
|
addSmb.addTile(rightdown);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// left
|
||||||
|
if ((symbol.x < 0.0f) && (!this.dependencyTable.get(left).drawn)) {
|
||||||
|
linkedDep = this.dependencyTable.get(left);
|
||||||
|
|
||||||
|
if (addSmb == null) {
|
||||||
|
addSmb = new DependencySymbol(symbol.symbol, this.currentTile);
|
||||||
|
this.currentDependencyOnTile.addSymbol(new Dependency<DependencySymbol>(addSmb, new ImmutablePoint(
|
||||||
|
symbol.x, symbol.y)));
|
||||||
|
}
|
||||||
|
|
||||||
|
linkedDep.addSymbol(new Dependency<DependencySymbol>(addSmb, new ImmutablePoint(symbol.x
|
||||||
|
+ Tile.TILE_SIZE, symbol.y)));
|
||||||
|
addSmb.addTile(left);
|
||||||
|
}
|
||||||
|
|
||||||
|
// right
|
||||||
|
if ((symbol.x + symbol.symbol.getWidth() > Tile.TILE_SIZE) && (!this.dependencyTable.get(right).drawn)) {
|
||||||
|
linkedDep = this.dependencyTable.get(right);
|
||||||
|
if (addSmb == null) {
|
||||||
|
addSmb = new DependencySymbol(symbol.symbol, this.currentTile);
|
||||||
|
this.currentDependencyOnTile.addSymbol(new Dependency<DependencySymbol>(addSmb, new ImmutablePoint(
|
||||||
|
symbol.x, symbol.y)));
|
||||||
|
}
|
||||||
|
|
||||||
|
linkedDep.addSymbol(new Dependency<DependencySymbol>(addSmb, new ImmutablePoint(symbol.x
|
||||||
|
- Tile.TILE_SIZE, symbol.y)));
|
||||||
|
addSmb.addTile(right);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void removeOverlappingAreaLabelsWithDependencyLabels(List<PointTextContainer> areaLabels) {
|
||||||
|
PointTextContainer pTC;
|
||||||
|
|
||||||
|
for (int i = 0; i < this.currentDependencyOnTile.labels.size(); i++) {
|
||||||
|
this.depLabel = this.currentDependencyOnTile.labels.get(i);
|
||||||
|
this.rect1 = new android.graphics.Rect((int) (this.depLabel.point.pointX),
|
||||||
|
(int) (this.depLabel.point.pointY - this.depLabel.value.boundary.height()),
|
||||||
|
(int) (this.depLabel.point.pointX + this.depLabel.value.boundary.width()),
|
||||||
|
(int) (this.depLabel.point.pointY));
|
||||||
|
|
||||||
|
for (int x = 0; x < areaLabels.size(); x++) {
|
||||||
|
pTC = areaLabels.get(x);
|
||||||
|
|
||||||
|
this.rect2 = new android.graphics.Rect((int) pTC.x, (int) pTC.y - pTC.boundary.height(), (int) pTC.x
|
||||||
|
+ pTC.boundary.width(), (int) pTC.y);
|
||||||
|
|
||||||
|
if (android.graphics.Rect.intersects(this.rect2, this.rect1)) {
|
||||||
|
areaLabels.remove(x);
|
||||||
|
x--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void removeOverlappingAreaLabelsWithDependencySymbols(List<PointTextContainer> areaLabels) {
|
||||||
|
PointTextContainer label;
|
||||||
|
|
||||||
|
for (Dependency<DependencySymbol> depSmb : this.currentDependencyOnTile.symbols) {
|
||||||
|
|
||||||
|
this.rect1 = new android.graphics.Rect((int) depSmb.point.pointX, (int) depSmb.point.pointY,
|
||||||
|
(int) depSmb.point.pointX + depSmb.value.symbol.getWidth(), (int) depSmb.point.pointY
|
||||||
|
+ depSmb.value.symbol.getHeight());
|
||||||
|
|
||||||
|
for (int x = 0; x < areaLabels.size(); x++) {
|
||||||
|
label = areaLabels.get(x);
|
||||||
|
|
||||||
|
this.rect2 = new android.graphics.Rect((int) (label.x), (int) (label.y - label.boundary.height()),
|
||||||
|
(int) (label.x + label.boundary.width()), (int) (label.y));
|
||||||
|
|
||||||
|
if (android.graphics.Rect.intersects(this.rect2, this.rect1)) {
|
||||||
|
areaLabels.remove(x);
|
||||||
|
x--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void removeOverlappingLabelsWithDependencyLabels(List<PointTextContainer> labels) {
|
||||||
|
for (int i = 0; i < this.currentDependencyOnTile.labels.size(); i++) {
|
||||||
|
for (int x = 0; x < labels.size(); x++) {
|
||||||
|
if ((labels.get(x).text.equals(this.currentDependencyOnTile.labels.get(i).value.text))
|
||||||
|
&& (labels.get(x).paintFront
|
||||||
|
.equals(this.currentDependencyOnTile.labels.get(i).value.paintFront))
|
||||||
|
&& (labels.get(x).paintBack.equals(this.currentDependencyOnTile.labels.get(i).value.paintBack))) {
|
||||||
|
labels.remove(x);
|
||||||
|
i--;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void removeOverlappingSymbolsWithDepencySymbols(List<SymbolContainer> symbols, int dis) {
|
||||||
|
SymbolContainer sym;
|
||||||
|
Dependency<DependencySymbol> sym2;
|
||||||
|
|
||||||
|
for (int x = 0; x < this.currentDependencyOnTile.symbols.size(); x++) {
|
||||||
|
sym2 = this.currentDependencyOnTile.symbols.get(x);
|
||||||
|
this.rect1 = new android.graphics.Rect((int) sym2.point.pointX - dis, (int) sym2.point.pointY - dis,
|
||||||
|
(int) sym2.point.pointX + sym2.value.symbol.getWidth() + dis, (int) sym2.point.pointY
|
||||||
|
+ sym2.value.symbol.getHeight() + dis);
|
||||||
|
|
||||||
|
for (int y = 0; y < symbols.size(); y++) {
|
||||||
|
|
||||||
|
sym = symbols.get(y);
|
||||||
|
this.rect2 = new android.graphics.Rect((int) sym.x, (int) sym.y, (int) sym.x + sym.symbol.getWidth(),
|
||||||
|
(int) sym.y + sym.symbol.getHeight());
|
||||||
|
|
||||||
|
if (android.graphics.Rect.intersects(this.rect2, this.rect1)) {
|
||||||
|
symbols.remove(y);
|
||||||
|
y--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void removeOverlappingSymbolsWithDependencyLabels(List<SymbolContainer> symbols) {
|
||||||
|
for (int i = 0; i < this.currentDependencyOnTile.labels.size(); i++) {
|
||||||
|
this.depLabel = this.currentDependencyOnTile.labels.get(i);
|
||||||
|
this.rect1 = new android.graphics.Rect((int) (this.depLabel.point.pointX),
|
||||||
|
(int) (this.depLabel.point.pointY - this.depLabel.value.boundary.height()),
|
||||||
|
(int) (this.depLabel.point.pointX + this.depLabel.value.boundary.width()),
|
||||||
|
(int) (this.depLabel.point.pointY));
|
||||||
|
|
||||||
|
for (int x = 0; x < symbols.size(); x++) {
|
||||||
|
this.smb = symbols.get(x);
|
||||||
|
|
||||||
|
this.rect2 = new android.graphics.Rect((int) this.smb.x, (int) this.smb.y, (int) this.smb.x
|
||||||
|
+ this.smb.symbol.getWidth(), (int) this.smb.y + this.smb.symbol.getHeight());
|
||||||
|
|
||||||
|
if (android.graphics.Rect.intersects(this.rect2, this.rect1)) {
|
||||||
|
symbols.remove(x);
|
||||||
|
x--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method fills the entries in the dependency cache of the tiles, if their dependencies.
|
||||||
|
*
|
||||||
|
* @param labels
|
||||||
|
* current labels, that will be displayed.
|
||||||
|
* @param symbols
|
||||||
|
* current symbols, that will be displayed.
|
||||||
|
* @param areaLabels
|
||||||
|
* current areaLabels, that will be displayed.
|
||||||
|
*/
|
||||||
|
void fillDependencyOnTile(List<PointTextContainer> labels, List<SymbolContainer> symbols,
|
||||||
|
List<PointTextContainer> areaLabels) {
|
||||||
|
this.currentDependencyOnTile.drawn = true;
|
||||||
|
|
||||||
|
if ((!labels.isEmpty()) || (!symbols.isEmpty()) || (!areaLabels.isEmpty())) {
|
||||||
|
fillDependencyOnTile2(labels, symbols, areaLabels);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.currentDependencyOnTile.labels != null) {
|
||||||
|
addLabelsFromDependencyOnTile(labels);
|
||||||
|
}
|
||||||
|
if (this.currentDependencyOnTile.symbols != null) {
|
||||||
|
addSymbolsFromDependencyOnTile(symbols);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method must be called, before the dependencies will be handled correctly. Because it sets the actual Tile
|
||||||
|
* and looks if it has already dependencies.
|
||||||
|
*
|
||||||
|
* @param tile
|
||||||
|
* the current Tile
|
||||||
|
*/
|
||||||
|
void generateTileAndDependencyOnTile(Tile tile) {
|
||||||
|
this.currentTile = new Tile(tile.tileX, tile.tileY, tile.zoomLevel);
|
||||||
|
this.currentDependencyOnTile = this.dependencyTable.get(this.currentTile);
|
||||||
|
|
||||||
|
if (this.currentDependencyOnTile == null) {
|
||||||
|
this.dependencyTable.put(this.currentTile, new DependencyOnTile());
|
||||||
|
this.currentDependencyOnTile = this.dependencyTable.get(this.currentTile);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes the are labels from the actual list, that would be rendered in a Tile that has already be drawn.
|
||||||
|
*
|
||||||
|
* @param areaLabels
|
||||||
|
* current area Labels, that will be displayed
|
||||||
|
*/
|
||||||
|
void removeAreaLabelsInAlreadyDrawnAreas(List<PointTextContainer> areaLabels) {
|
||||||
|
Tile lefttmp = new Tile(this.currentTile.tileX - 1, this.currentTile.tileY, this.currentTile.zoomLevel);
|
||||||
|
Tile righttmp = new Tile(this.currentTile.tileX + 1, this.currentTile.tileY, this.currentTile.zoomLevel);
|
||||||
|
Tile uptmp = new Tile(this.currentTile.tileX, this.currentTile.tileY - 1, this.currentTile.zoomLevel);
|
||||||
|
Tile downtmp = new Tile(this.currentTile.tileX, this.currentTile.tileY + 1, this.currentTile.zoomLevel);
|
||||||
|
|
||||||
|
boolean up;
|
||||||
|
boolean left;
|
||||||
|
boolean right;
|
||||||
|
boolean down;
|
||||||
|
|
||||||
|
this.tmp = this.dependencyTable.get(lefttmp);
|
||||||
|
left = this.tmp == null ? false : this.tmp.drawn;
|
||||||
|
|
||||||
|
this.tmp = this.dependencyTable.get(righttmp);
|
||||||
|
right = this.tmp == null ? false : this.tmp.drawn;
|
||||||
|
|
||||||
|
this.tmp = this.dependencyTable.get(uptmp);
|
||||||
|
up = this.tmp == null ? false : this.tmp.drawn;
|
||||||
|
|
||||||
|
this.tmp = this.dependencyTable.get(downtmp);
|
||||||
|
down = this.tmp == null ? false : this.tmp.drawn;
|
||||||
|
|
||||||
|
PointTextContainer label;
|
||||||
|
|
||||||
|
for (int i = 0; i < areaLabels.size(); i++) {
|
||||||
|
label = areaLabels.get(i);
|
||||||
|
|
||||||
|
if (up && label.y - label.boundary.height() < 0.0f) {
|
||||||
|
areaLabels.remove(i);
|
||||||
|
i--;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (down && label.y > Tile.TILE_SIZE) {
|
||||||
|
areaLabels.remove(i);
|
||||||
|
i--;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (left && label.x < 0.0f) {
|
||||||
|
areaLabels.remove(i);
|
||||||
|
i--;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (right && label.x + label.boundary.width() > Tile.TILE_SIZE) {
|
||||||
|
areaLabels.remove(i);
|
||||||
|
i--;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes all objects that overlaps with the objects from the dependency cache.
|
||||||
|
*
|
||||||
|
* @param labels
|
||||||
|
* labels from the current tile
|
||||||
|
* @param areaLabels
|
||||||
|
* area labels from the current tile
|
||||||
|
* @param symbols
|
||||||
|
* symbols from the current tile
|
||||||
|
*/
|
||||||
|
void removeOverlappingObjectsWithDependencyOnTile(List<PointTextContainer> labels,
|
||||||
|
List<PointTextContainer> areaLabels, List<SymbolContainer> symbols) {
|
||||||
|
if (this.currentDependencyOnTile.labels != null && this.currentDependencyOnTile.labels.size() != 0) {
|
||||||
|
removeOverlappingLabelsWithDependencyLabels(labels);
|
||||||
|
removeOverlappingSymbolsWithDependencyLabels(symbols);
|
||||||
|
removeOverlappingAreaLabelsWithDependencyLabels(areaLabels);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.currentDependencyOnTile.symbols != null && this.currentDependencyOnTile.symbols.size() != 0) {
|
||||||
|
removeOverlappingSymbolsWithDepencySymbols(symbols, 2);
|
||||||
|
removeOverlappingAreaLabelsWithDependencySymbols(areaLabels);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* When the LabelPlacement class generates potential label positions for an POI, there should be no possible
|
||||||
|
* positions, that collide with existing symbols or labels in the dependency Cache. This class implements this
|
||||||
|
* functionality.
|
||||||
|
*
|
||||||
|
* @param refPos
|
||||||
|
* possible label positions form the two or four point Greedy
|
||||||
|
*/
|
||||||
|
void removeReferencePointsFromDependencyCache(LabelPlacement.ReferencePosition[] refPos) {
|
||||||
|
Tile lefttmp = new Tile(this.currentTile.tileX - 1, this.currentTile.tileY, this.currentTile.zoomLevel);
|
||||||
|
Tile righttmp = new Tile(this.currentTile.tileX + 1, this.currentTile.tileY, this.currentTile.zoomLevel);
|
||||||
|
Tile uptmp = new Tile(this.currentTile.tileX, this.currentTile.tileY - 1, this.currentTile.zoomLevel);
|
||||||
|
Tile downtmp = new Tile(this.currentTile.tileX, this.currentTile.tileY + 1, this.currentTile.zoomLevel);
|
||||||
|
|
||||||
|
boolean up;
|
||||||
|
boolean left;
|
||||||
|
boolean right;
|
||||||
|
boolean down;
|
||||||
|
|
||||||
|
this.tmp = this.dependencyTable.get(lefttmp);
|
||||||
|
left = this.tmp == null ? false : this.tmp.drawn;
|
||||||
|
|
||||||
|
this.tmp = this.dependencyTable.get(righttmp);
|
||||||
|
right = this.tmp == null ? false : this.tmp.drawn;
|
||||||
|
|
||||||
|
this.tmp = this.dependencyTable.get(uptmp);
|
||||||
|
up = this.tmp == null ? false : this.tmp.drawn;
|
||||||
|
|
||||||
|
this.tmp = this.dependencyTable.get(downtmp);
|
||||||
|
down = this.tmp == null ? false : this.tmp.drawn;
|
||||||
|
|
||||||
|
LabelPlacement.ReferencePosition ref;
|
||||||
|
|
||||||
|
for (int i = 0; i < refPos.length; i++) {
|
||||||
|
ref = refPos[i];
|
||||||
|
|
||||||
|
if (ref == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (up && ref.y - ref.height < 0) {
|
||||||
|
refPos[i] = null;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (down && ref.y >= Tile.TILE_SIZE) {
|
||||||
|
refPos[i] = null;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (left && ref.x < 0) {
|
||||||
|
refPos[i] = null;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (right && ref.x + ref.width > Tile.TILE_SIZE) {
|
||||||
|
refPos[i] = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// removes all Reverence Points that intersects with Labels from the Dependency Cache
|
||||||
|
|
||||||
|
int dis = 2;
|
||||||
|
if (this.currentDependencyOnTile != null) {
|
||||||
|
if (this.currentDependencyOnTile.labels != null) {
|
||||||
|
for (int i = 0; i < this.currentDependencyOnTile.labels.size(); i++) {
|
||||||
|
this.depLabel = this.currentDependencyOnTile.labels.get(i);
|
||||||
|
this.rect1 = new android.graphics.Rect((int) this.depLabel.point.pointX - dis,
|
||||||
|
(int) (this.depLabel.point.pointY - this.depLabel.value.boundary.height()) - dis,
|
||||||
|
(int) (this.depLabel.point.pointX + this.depLabel.value.boundary.width() + dis),
|
||||||
|
(int) (this.depLabel.point.pointY + dis));
|
||||||
|
|
||||||
|
for (int y = 0; y < refPos.length; y++) {
|
||||||
|
if (refPos[y] != null) {
|
||||||
|
this.rect2 = new android.graphics.Rect((int) refPos[y].x,
|
||||||
|
(int) (refPos[y].y - refPos[y].height), (int) (refPos[y].x + refPos[y].width),
|
||||||
|
(int) (refPos[y].y));
|
||||||
|
|
||||||
|
if (android.graphics.Rect.intersects(this.rect2, this.rect1)) {
|
||||||
|
refPos[y] = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (this.currentDependencyOnTile.symbols != null) {
|
||||||
|
for (Dependency<DependencySymbol> symbols2 : this.currentDependencyOnTile.symbols) {
|
||||||
|
|
||||||
|
this.rect1 = new android.graphics.Rect((int) symbols2.point.pointX, (int) (symbols2.point.pointY),
|
||||||
|
(int) (symbols2.point.pointX + symbols2.value.symbol.getWidth()),
|
||||||
|
(int) (symbols2.point.pointY + symbols2.value.symbol.getHeight()));
|
||||||
|
|
||||||
|
for (int y = 0; y < refPos.length; y++) {
|
||||||
|
if (refPos[y] != null) {
|
||||||
|
this.rect2 = new android.graphics.Rect((int) refPos[y].x,
|
||||||
|
(int) (refPos[y].y - refPos[y].height), (int) (refPos[y].x + refPos[y].width),
|
||||||
|
(int) (refPos[y].y));
|
||||||
|
|
||||||
|
if (android.graphics.Rect.intersects(this.rect2, this.rect1)) {
|
||||||
|
refPos[y] = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void removeSymbolsFromDrawnAreas(List<SymbolContainer> symbols) {
|
||||||
|
Tile lefttmp = new Tile(this.currentTile.tileX - 1, this.currentTile.tileY, this.currentTile.zoomLevel);
|
||||||
|
Tile righttmp = new Tile(this.currentTile.tileX + 1, this.currentTile.tileY, this.currentTile.zoomLevel);
|
||||||
|
Tile uptmp = new Tile(this.currentTile.tileX, this.currentTile.tileY - 1, this.currentTile.zoomLevel);
|
||||||
|
Tile downtmp = new Tile(this.currentTile.tileX, this.currentTile.tileY + 1, this.currentTile.zoomLevel);
|
||||||
|
|
||||||
|
boolean up;
|
||||||
|
boolean left;
|
||||||
|
boolean right;
|
||||||
|
boolean down;
|
||||||
|
|
||||||
|
this.tmp = this.dependencyTable.get(lefttmp);
|
||||||
|
left = this.tmp == null ? false : this.tmp.drawn;
|
||||||
|
|
||||||
|
this.tmp = this.dependencyTable.get(righttmp);
|
||||||
|
right = this.tmp == null ? false : this.tmp.drawn;
|
||||||
|
|
||||||
|
this.tmp = this.dependencyTable.get(uptmp);
|
||||||
|
up = this.tmp == null ? false : this.tmp.drawn;
|
||||||
|
|
||||||
|
this.tmp = this.dependencyTable.get(downtmp);
|
||||||
|
down = this.tmp == null ? false : this.tmp.drawn;
|
||||||
|
|
||||||
|
SymbolContainer ref;
|
||||||
|
|
||||||
|
for (int i = 0; i < symbols.size(); i++) {
|
||||||
|
ref = symbols.get(i);
|
||||||
|
|
||||||
|
if (up && ref.y < 0) {
|
||||||
|
symbols.remove(i);
|
||||||
|
i--;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (down && ref.y + ref.symbol.getHeight() > Tile.TILE_SIZE) {
|
||||||
|
symbols.remove(i);
|
||||||
|
i--;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (left && ref.x < 0) {
|
||||||
|
symbols.remove(i);
|
||||||
|
i--;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (right && ref.x + ref.symbol.getWidth() > Tile.TILE_SIZE) {
|
||||||
|
symbols.remove(i);
|
||||||
|
i--;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
83
src/org/mapsforge/android/swrenderer/GLMapTile.java
Normal file
83
src/org/mapsforge/android/swrenderer/GLMapTile.java
Normal file
@@ -0,0 +1,83 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2012 Hannes Janetzek
|
||||||
|
*
|
||||||
|
* 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.mapsforge.android.swrenderer;
|
||||||
|
|
||||||
|
import org.mapsforge.android.mapgenerator.MapTile;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class GLMapTile extends MapTile {
|
||||||
|
private float mScale;
|
||||||
|
|
||||||
|
final GLMapTile[] child = { null, null, null, null };
|
||||||
|
GLMapTile parent;
|
||||||
|
|
||||||
|
// private long mLoadTime;
|
||||||
|
private int mTextureID;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param tileX
|
||||||
|
* ...
|
||||||
|
* @param tileY
|
||||||
|
* ...
|
||||||
|
* @param zoomLevel
|
||||||
|
* ..
|
||||||
|
*/
|
||||||
|
public GLMapTile(long tileX, long tileY, byte zoomLevel) {
|
||||||
|
super(tileX, tileY, zoomLevel);
|
||||||
|
mScale = 1;
|
||||||
|
isDrawn = false;
|
||||||
|
mTextureID = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return ...
|
||||||
|
*/
|
||||||
|
public int getTexture() {
|
||||||
|
return mTextureID;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param mTextureID
|
||||||
|
* ...
|
||||||
|
*/
|
||||||
|
public void setTexture(int mTextureID) {
|
||||||
|
this.mTextureID = mTextureID;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return ...
|
||||||
|
*/
|
||||||
|
public boolean hasTexture() {
|
||||||
|
return mTextureID >= 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return ...
|
||||||
|
*/
|
||||||
|
public float getScale() {
|
||||||
|
return mScale;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param scale
|
||||||
|
* ...
|
||||||
|
*/
|
||||||
|
public void setScale(float scale) {
|
||||||
|
mScale = scale;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
116
src/org/mapsforge/android/swrenderer/ImmutablePoint.java
Normal file
116
src/org/mapsforge/android/swrenderer/ImmutablePoint.java
Normal file
@@ -0,0 +1,116 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010, 2011, 2012 mapsforge.org
|
||||||
|
*
|
||||||
|
* 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.mapsforge.android.swrenderer;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An ImmutablePoint represents an fixed pair of float coordinates.
|
||||||
|
*/
|
||||||
|
class ImmutablePoint implements Comparable<ImmutablePoint> {
|
||||||
|
/**
|
||||||
|
* Subtracts the x and y coordinates of one point from another point.
|
||||||
|
*
|
||||||
|
* @param minuend
|
||||||
|
* the minuend.
|
||||||
|
* @param subtrahend
|
||||||
|
* the subtrahend.
|
||||||
|
* @return a new Point object.
|
||||||
|
*/
|
||||||
|
static ImmutablePoint substract(ImmutablePoint minuend, ImmutablePoint subtrahend) {
|
||||||
|
return new ImmutablePoint(minuend.pointX - subtrahend.pointX, minuend.pointY - subtrahend.pointY);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stores the hash code of this object.
|
||||||
|
*/
|
||||||
|
private final int hashCodeValue;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* X coordinate of this point.
|
||||||
|
*/
|
||||||
|
final float pointX;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Y coordinate of this point.
|
||||||
|
*/
|
||||||
|
final float pointY;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param x
|
||||||
|
* the x coordinate of the point.
|
||||||
|
* @param y
|
||||||
|
* the y coordinate of the point.
|
||||||
|
*/
|
||||||
|
ImmutablePoint(float x, float y) {
|
||||||
|
this.pointX = x;
|
||||||
|
this.pointY = y;
|
||||||
|
this.hashCodeValue = calculateHashCode();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int compareTo(ImmutablePoint point) {
|
||||||
|
if (this.pointX > point.pointX) {
|
||||||
|
return 1;
|
||||||
|
} else if (this.pointX < point.pointX) {
|
||||||
|
return -1;
|
||||||
|
} else if (this.pointY > point.pointY) {
|
||||||
|
return 1;
|
||||||
|
} else if (this.pointY < point.pointY) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object obj) {
|
||||||
|
if (this == obj) {
|
||||||
|
return true;
|
||||||
|
} else if (!(obj instanceof ImmutablePoint)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
ImmutablePoint other = (ImmutablePoint) obj;
|
||||||
|
if (this.pointX != other.pointX) {
|
||||||
|
return false;
|
||||||
|
} else if (this.pointY != other.pointY) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return this.hashCodeValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
StringBuilder stringBuilder = new StringBuilder();
|
||||||
|
stringBuilder.append("ImmutablePoint [x=");
|
||||||
|
stringBuilder.append(this.pointX);
|
||||||
|
stringBuilder.append(", y=");
|
||||||
|
stringBuilder.append(this.pointY);
|
||||||
|
stringBuilder.append("]");
|
||||||
|
return stringBuilder.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the hash code of this object.
|
||||||
|
*/
|
||||||
|
private int calculateHashCode() {
|
||||||
|
int result = 7;
|
||||||
|
result = 31 * result + Float.floatToIntBits(this.pointX);
|
||||||
|
result = 31 * result + Float.floatToIntBits(this.pointY);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
766
src/org/mapsforge/android/swrenderer/LabelPlacement.java
Normal file
766
src/org/mapsforge/android/swrenderer/LabelPlacement.java
Normal file
@@ -0,0 +1,766 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010, 2011, 2012 mapsforge.org
|
||||||
|
*
|
||||||
|
* 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.mapsforge.android.swrenderer;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Comparator;
|
||||||
|
import java.util.LinkedList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.PriorityQueue;
|
||||||
|
|
||||||
|
import org.mapsforge.core.Tile;
|
||||||
|
|
||||||
|
import android.graphics.Rect;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This class place the labels form POIs, area labels and normal labels. The main target is avoiding collisions of these
|
||||||
|
* different labels.
|
||||||
|
*/
|
||||||
|
class LabelPlacement {
|
||||||
|
/**
|
||||||
|
* This class holds the reference positions for the two and four point greedy algorithms.
|
||||||
|
*/
|
||||||
|
static class ReferencePosition {
|
||||||
|
final float height;
|
||||||
|
final int nodeNumber;
|
||||||
|
SymbolContainer symbol;
|
||||||
|
final float width;
|
||||||
|
final float x;
|
||||||
|
final float y;
|
||||||
|
|
||||||
|
ReferencePosition(float x, float y, int nodeNumber, float width, float height, SymbolContainer symbol) {
|
||||||
|
this.x = x;
|
||||||
|
this.y = y;
|
||||||
|
this.nodeNumber = nodeNumber;
|
||||||
|
this.width = width;
|
||||||
|
this.height = height;
|
||||||
|
this.symbol = symbol;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static final class ReferencePositionHeightComparator implements Comparator<ReferencePosition>, Serializable {
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
static final ReferencePositionHeightComparator INSTANCE = new ReferencePositionHeightComparator();
|
||||||
|
|
||||||
|
private ReferencePositionHeightComparator() {
|
||||||
|
// do nothing
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int compare(ReferencePosition x, ReferencePosition y) {
|
||||||
|
if (x.y - x.height < y.y - y.height) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (x.y - x.height > y.y - y.height) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static final class ReferencePositionWidthComparator implements Comparator<ReferencePosition>, Serializable {
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
static final ReferencePositionWidthComparator INSTANCE = new ReferencePositionWidthComparator();
|
||||||
|
|
||||||
|
private ReferencePositionWidthComparator() {
|
||||||
|
// do nothing
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int compare(ReferencePosition x, ReferencePosition y) {
|
||||||
|
if (x.x + x.width < y.x + y.width) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (x.x + x.width > y.x + y.width) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static final class ReferencePositionXComparator implements Comparator<ReferencePosition>, Serializable {
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
static final ReferencePositionXComparator INSTANCE = new ReferencePositionXComparator();
|
||||||
|
|
||||||
|
private ReferencePositionXComparator() {
|
||||||
|
// do nothing
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int compare(ReferencePosition x, ReferencePosition y) {
|
||||||
|
if (x.x < y.x) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (x.x > y.x) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static final class ReferencePositionYComparator implements Comparator<ReferencePosition>, Serializable {
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
static final ReferencePositionYComparator INSTANCE = new ReferencePositionYComparator();
|
||||||
|
|
||||||
|
private ReferencePositionYComparator() {
|
||||||
|
// do nothing
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int compare(ReferencePosition x, ReferencePosition y) {
|
||||||
|
if (x.y < y.y) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (x.y > y.y) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final int PLACEMENT_MODEL = 1;
|
||||||
|
private int mLabelDistanceToLabel = 2;
|
||||||
|
private int mLabelDistanceToSymbol = 2;
|
||||||
|
// You can choose between 2 Position and 4 Position
|
||||||
|
// placement Model 0 - 2-Position 1 - 4 Position
|
||||||
|
// distance adjustments
|
||||||
|
private int mStartDistanceToSymbols = 4;
|
||||||
|
private int mSymbolDistanceToSymbol = 2;
|
||||||
|
|
||||||
|
final DependencyCache mDependencyCache;
|
||||||
|
PointTextContainer mLabel;
|
||||||
|
Rect mRect1;
|
||||||
|
Rect mRect2;
|
||||||
|
ReferencePosition mReferencePosition;
|
||||||
|
SymbolContainer mSymbolContainer;
|
||||||
|
|
||||||
|
LabelPlacement() {
|
||||||
|
mDependencyCache = new DependencyCache();
|
||||||
|
mRect1 = new Rect();
|
||||||
|
mRect2 = new Rect();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Centers the labels.
|
||||||
|
*
|
||||||
|
* @param labels
|
||||||
|
* labels to center
|
||||||
|
*/
|
||||||
|
private void centerLabels(List<PointTextContainer> labels) {
|
||||||
|
for (int i = 0; i < labels.size(); i++) {
|
||||||
|
mLabel = labels.get(i);
|
||||||
|
mLabel.x = mLabel.x - mLabel.boundary.width() / 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void preprocessAreaLabels(List<PointTextContainer> areaLabels) {
|
||||||
|
centerLabels(areaLabels);
|
||||||
|
|
||||||
|
removeOutOfTileAreaLabels(areaLabels);
|
||||||
|
|
||||||
|
removeOverlappingAreaLabels(areaLabels);
|
||||||
|
|
||||||
|
if (!areaLabels.isEmpty()) {
|
||||||
|
mDependencyCache.removeAreaLabelsInAlreadyDrawnAreas(areaLabels);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void preprocessLabels(List<PointTextContainer> labels) {
|
||||||
|
removeOutOfTileLabels(labels);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void preprocessSymbols(List<SymbolContainer> symbols) {
|
||||||
|
removeOutOfTileSymbols(symbols);
|
||||||
|
removeOverlappingSymbols(symbols);
|
||||||
|
mDependencyCache.removeSymbolsFromDrawnAreas(symbols);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method uses an adapted greedy strategy for the fixed four position model, above, under left and right form
|
||||||
|
* the point of interest. It uses no priority search tree, because it will not function with symbols only with
|
||||||
|
* points. Instead it uses two minimum heaps. They work similar to a sweep line algorithm but have not a O(n log n
|
||||||
|
* +k) runtime. To find the rectangle that has the top edge, I use also a minimum Heap. The rectangles are sorted by
|
||||||
|
* their y coordinates.
|
||||||
|
*
|
||||||
|
* @param labels
|
||||||
|
* label positions and text
|
||||||
|
* @param symbols
|
||||||
|
* symbol positions
|
||||||
|
* @param areaLabels
|
||||||
|
* area label positions and text
|
||||||
|
* @return list of labels without overlaps with symbols and other labels by the four fixed position greedy strategy
|
||||||
|
*/
|
||||||
|
private List<PointTextContainer> processFourPointGreedy(List<PointTextContainer> labels,
|
||||||
|
List<SymbolContainer> symbols, List<PointTextContainer> areaLabels) {
|
||||||
|
List<PointTextContainer> resolutionSet = new ArrayList<PointTextContainer>();
|
||||||
|
|
||||||
|
// Array for the generated reference positions around the points of
|
||||||
|
// interests
|
||||||
|
ReferencePosition[] refPos = new ReferencePosition[(labels.size()) * 4];
|
||||||
|
|
||||||
|
// lists that sorts the reference points after the minimum top edge y
|
||||||
|
// position
|
||||||
|
PriorityQueue<ReferencePosition> priorUp = new PriorityQueue<ReferencePosition>(labels.size() * 4 * 2
|
||||||
|
+ labels.size() / 10 * 2, ReferencePositionYComparator.INSTANCE);
|
||||||
|
// lists that sorts the reference points after the minimum bottom edge y
|
||||||
|
// position
|
||||||
|
PriorityQueue<ReferencePosition> priorDown = new PriorityQueue<ReferencePosition>(labels.size() * 4 * 2
|
||||||
|
+ labels.size() / 10 * 2, ReferencePositionHeightComparator.INSTANCE);
|
||||||
|
|
||||||
|
PointTextContainer tmp;
|
||||||
|
int dis = mStartDistanceToSymbols;
|
||||||
|
|
||||||
|
// creates the reference positions
|
||||||
|
for (int z = 0; z < labels.size(); z++) {
|
||||||
|
if (labels.get(z) != null) {
|
||||||
|
if (labels.get(z).symbol != null) {
|
||||||
|
tmp = labels.get(z);
|
||||||
|
|
||||||
|
// up
|
||||||
|
refPos[z * 4] = new ReferencePosition(tmp.x - tmp.boundary.width() / 2, tmp.y
|
||||||
|
- tmp.symbol.symbol.getHeight() / 2 - dis, z, tmp.boundary.width(), tmp.boundary.height(),
|
||||||
|
tmp.symbol);
|
||||||
|
// down
|
||||||
|
refPos[z * 4 + 1] = new ReferencePosition(tmp.x - tmp.boundary.width() / 2, tmp.y
|
||||||
|
+ tmp.symbol.symbol.getHeight() / 2 + tmp.boundary.height() + dis, z, tmp.boundary.width(),
|
||||||
|
tmp.boundary.height(), tmp.symbol);
|
||||||
|
// left
|
||||||
|
refPos[z * 4 + 2] = new ReferencePosition(tmp.x - tmp.symbol.symbol.getWidth() / 2
|
||||||
|
- tmp.boundary.width() - dis, tmp.y + tmp.boundary.height() / 2, z, tmp.boundary.width(),
|
||||||
|
tmp.boundary.height(), tmp.symbol);
|
||||||
|
// right
|
||||||
|
refPos[z * 4 + 3] = new ReferencePosition(tmp.x + tmp.symbol.symbol.getWidth() / 2 + dis, tmp.y
|
||||||
|
+ tmp.boundary.height() / 2 - 0.1f, z, tmp.boundary.width(), tmp.boundary.height(),
|
||||||
|
tmp.symbol);
|
||||||
|
} else {
|
||||||
|
refPos[z * 4] = new ReferencePosition(labels.get(z).x - ((labels.get(z).boundary.width()) / 2),
|
||||||
|
labels.get(z).y, z, labels.get(z).boundary.width(), labels.get(z).boundary.height(), null);
|
||||||
|
refPos[z * 4 + 1] = null;
|
||||||
|
refPos[z * 4 + 2] = null;
|
||||||
|
refPos[z * 4 + 3] = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
removeNonValidateReferencePosition(refPos, symbols, areaLabels);
|
||||||
|
|
||||||
|
// do while it gives reference positions
|
||||||
|
for (int i = 0; i < refPos.length; i++) {
|
||||||
|
mReferencePosition = refPos[i];
|
||||||
|
if (mReferencePosition != null) {
|
||||||
|
priorUp.add(mReferencePosition);
|
||||||
|
priorDown.add(mReferencePosition);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
while (priorUp.size() != 0) {
|
||||||
|
mReferencePosition = priorUp.remove();
|
||||||
|
|
||||||
|
mLabel = labels.get(mReferencePosition.nodeNumber);
|
||||||
|
|
||||||
|
resolutionSet.add(new PointTextContainer(mLabel.text, mReferencePosition.x,
|
||||||
|
mReferencePosition.y, mLabel.paintFront, mLabel.paintBack, mLabel.symbol));
|
||||||
|
|
||||||
|
if (priorUp.size() == 0) {
|
||||||
|
return resolutionSet;
|
||||||
|
}
|
||||||
|
|
||||||
|
priorUp.remove(refPos[mReferencePosition.nodeNumber * 4 + 0]);
|
||||||
|
priorUp.remove(refPos[mReferencePosition.nodeNumber * 4 + 1]);
|
||||||
|
priorUp.remove(refPos[mReferencePosition.nodeNumber * 4 + 2]);
|
||||||
|
priorUp.remove(refPos[mReferencePosition.nodeNumber * 4 + 3]);
|
||||||
|
|
||||||
|
priorDown.remove(refPos[mReferencePosition.nodeNumber * 4 + 0]);
|
||||||
|
priorDown.remove(refPos[mReferencePosition.nodeNumber * 4 + 1]);
|
||||||
|
priorDown.remove(refPos[mReferencePosition.nodeNumber * 4 + 2]);
|
||||||
|
priorDown.remove(refPos[mReferencePosition.nodeNumber * 4 + 3]);
|
||||||
|
|
||||||
|
LinkedList<ReferencePosition> linkedRef = new LinkedList<ReferencePosition>();
|
||||||
|
|
||||||
|
while (priorDown.size() != 0) {
|
||||||
|
if (priorDown.peek().x < mReferencePosition.x + mReferencePosition.width) {
|
||||||
|
linkedRef.add(priorDown.remove());
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// brute Force collision test (faster then sweep line for a small
|
||||||
|
// amount of
|
||||||
|
// objects)
|
||||||
|
for (int i = 0; i < linkedRef.size(); i++) {
|
||||||
|
if ((linkedRef.get(i).x <= mReferencePosition.x + mReferencePosition.width)
|
||||||
|
&& (linkedRef.get(i).y >= mReferencePosition.y - linkedRef.get(i).height)
|
||||||
|
&& (linkedRef.get(i).y <= mReferencePosition.y + linkedRef.get(i).height)) {
|
||||||
|
priorUp.remove(linkedRef.get(i));
|
||||||
|
linkedRef.remove(i);
|
||||||
|
i--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
priorDown.addAll(linkedRef);
|
||||||
|
}
|
||||||
|
|
||||||
|
return resolutionSet;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method uses an adapted greedy strategy for the fixed two position model, above and under. It uses no
|
||||||
|
* priority search tree, because it will not function with symbols only with points. Instead it uses two minimum
|
||||||
|
* heaps. They work similar to a sweep line algorithm but have not a O(n log n +k) runtime. To find the rectangle
|
||||||
|
* that has the leftest edge, I use also a minimum Heap. The rectangles are sorted by their x coordinates.
|
||||||
|
*
|
||||||
|
* @param labels
|
||||||
|
* label positions and text
|
||||||
|
* @param symbols
|
||||||
|
* symbol positions
|
||||||
|
* @param areaLabels
|
||||||
|
* area label positions and text
|
||||||
|
* @return list of labels without overlaps with symbols and other labels by the two fixed position greedy strategy
|
||||||
|
*/
|
||||||
|
private List<PointTextContainer> processTwoPointGreedy(List<PointTextContainer> labels,
|
||||||
|
List<SymbolContainer> symbols, List<PointTextContainer> areaLabels) {
|
||||||
|
List<PointTextContainer> resolutionSet = new ArrayList<PointTextContainer>();
|
||||||
|
// Array for the generated reference positions around the points of
|
||||||
|
// interests
|
||||||
|
ReferencePosition[] refPos = new ReferencePosition[labels.size() * 2];
|
||||||
|
|
||||||
|
// lists that sorts the reference points after the minimum right edge x
|
||||||
|
// position
|
||||||
|
PriorityQueue<ReferencePosition> priorRight = new PriorityQueue<ReferencePosition>(labels.size() * 2
|
||||||
|
+ labels.size() / 10 * 2, ReferencePositionWidthComparator.INSTANCE);
|
||||||
|
// lists that sorts the reference points after the minimum left edge x
|
||||||
|
// position
|
||||||
|
PriorityQueue<ReferencePosition> priorLeft = new PriorityQueue<ReferencePosition>(labels.size() * 2
|
||||||
|
+ labels.size() / 10 * 2, ReferencePositionXComparator.INSTANCE);
|
||||||
|
|
||||||
|
// creates the reference positions
|
||||||
|
for (int z = 0; z < labels.size(); z++) {
|
||||||
|
mLabel = labels.get(z);
|
||||||
|
|
||||||
|
if (mLabel.symbol != null) {
|
||||||
|
refPos[z * 2] = new ReferencePosition(mLabel.x - (mLabel.boundary.width() / 2) - 0.1f,
|
||||||
|
mLabel.y - mLabel.boundary.height() - mStartDistanceToSymbols, z,
|
||||||
|
mLabel.boundary.width(), mLabel.boundary.height(), mLabel.symbol);
|
||||||
|
refPos[z * 2 + 1] = new ReferencePosition(mLabel.x - (mLabel.boundary.width() / 2),
|
||||||
|
mLabel.y + mLabel.symbol.symbol.getHeight() + mStartDistanceToSymbols, z,
|
||||||
|
mLabel.boundary.width(), mLabel.boundary.height(), mLabel.symbol);
|
||||||
|
} else {
|
||||||
|
refPos[z * 2] = new ReferencePosition(mLabel.x - (mLabel.boundary.width() / 2) - 0.1f,
|
||||||
|
mLabel.y, z, mLabel.boundary.width(), mLabel.boundary.height(), null);
|
||||||
|
refPos[z * 2 + 1] = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// removes reference positions that overlaps with other symbols or
|
||||||
|
// dependency objects
|
||||||
|
removeNonValidateReferencePosition(refPos, symbols, areaLabels);
|
||||||
|
|
||||||
|
for (int i = 0; i < refPos.length; i++) {
|
||||||
|
mReferencePosition = refPos[i];
|
||||||
|
if (mReferencePosition != null) {
|
||||||
|
priorLeft.add(mReferencePosition);
|
||||||
|
priorRight.add(mReferencePosition);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
while (priorRight.size() != 0) {
|
||||||
|
mReferencePosition = priorRight.remove();
|
||||||
|
|
||||||
|
mLabel = labels.get(mReferencePosition.nodeNumber);
|
||||||
|
|
||||||
|
resolutionSet.add(new PointTextContainer(mLabel.text, mReferencePosition.x,
|
||||||
|
mReferencePosition.y, mLabel.paintFront, mLabel.paintBack,
|
||||||
|
mReferencePosition.symbol));
|
||||||
|
|
||||||
|
// Removes the other position that is a possible position for the label
|
||||||
|
// of one point
|
||||||
|
// of interest
|
||||||
|
|
||||||
|
priorRight.remove(refPos[mReferencePosition.nodeNumber * 2 + 1]);
|
||||||
|
|
||||||
|
if (priorRight.size() == 0) {
|
||||||
|
return resolutionSet;
|
||||||
|
}
|
||||||
|
|
||||||
|
priorLeft.remove(mReferencePosition);
|
||||||
|
priorLeft.remove(refPos[mReferencePosition.nodeNumber * 2 + 1]);
|
||||||
|
|
||||||
|
// find overlapping labels and deletes the reference points and delete
|
||||||
|
// them
|
||||||
|
LinkedList<ReferencePosition> linkedRef = new LinkedList<ReferencePosition>();
|
||||||
|
|
||||||
|
while (priorLeft.size() != 0) {
|
||||||
|
if (priorLeft.peek().x < mReferencePosition.x + mReferencePosition.width) {
|
||||||
|
linkedRef.add(priorLeft.remove());
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// brute Force collision test (faster then sweep line for a small
|
||||||
|
// amount of
|
||||||
|
// objects)
|
||||||
|
for (int i = 0; i < linkedRef.size(); i++) {
|
||||||
|
if ((linkedRef.get(i).x <= mReferencePosition.x + mReferencePosition.width)
|
||||||
|
&& (linkedRef.get(i).y >= mReferencePosition.y - linkedRef.get(i).height)
|
||||||
|
&& (linkedRef.get(i).y <= mReferencePosition.y + linkedRef.get(i).height)) {
|
||||||
|
priorRight.remove(linkedRef.get(i));
|
||||||
|
linkedRef.remove(i);
|
||||||
|
i--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
priorLeft.addAll(linkedRef);
|
||||||
|
}
|
||||||
|
|
||||||
|
return resolutionSet;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void removeEmptySymbolReferences(List<PointTextContainer> nodes, List<SymbolContainer> symbols) {
|
||||||
|
for (int i = 0; i < nodes.size(); i++) {
|
||||||
|
mLabel = nodes.get(i);
|
||||||
|
if (!symbols.contains(mLabel.symbol)) {
|
||||||
|
mLabel.symbol = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The greedy algorithms need possible label positions, to choose the best among them. This method removes the
|
||||||
|
* reference points, that are not validate. Not validate means, that the Reference overlap with another symbol or
|
||||||
|
* label or is outside of the tile.
|
||||||
|
*
|
||||||
|
* @param refPos
|
||||||
|
* list of the potential positions
|
||||||
|
* @param symbols
|
||||||
|
* actual list of the symbols
|
||||||
|
* @param areaLabels
|
||||||
|
* actual list of the area labels
|
||||||
|
*/
|
||||||
|
private void removeNonValidateReferencePosition(ReferencePosition[] refPos, List<SymbolContainer> symbols,
|
||||||
|
List<PointTextContainer> areaLabels) {
|
||||||
|
int dis = mLabelDistanceToSymbol;
|
||||||
|
|
||||||
|
for (int i = 0; i < symbols.size(); i++) {
|
||||||
|
mSymbolContainer = symbols.get(i);
|
||||||
|
mRect1.set((int) mSymbolContainer.x - dis, (int) mSymbolContainer.y - dis,
|
||||||
|
(int) mSymbolContainer.x + mSymbolContainer.symbol.getWidth() + dis,
|
||||||
|
(int) mSymbolContainer.y + mSymbolContainer.symbol.getHeight() + dis);
|
||||||
|
|
||||||
|
for (int y = 0; y < refPos.length; y++) {
|
||||||
|
if (refPos[y] != null) {
|
||||||
|
|
||||||
|
mRect2.set((int) refPos[y].x, (int) (refPos[y].y - refPos[y].height),
|
||||||
|
(int) (refPos[y].x + refPos[y].width), (int) (refPos[y].y));
|
||||||
|
|
||||||
|
if (android.graphics.Rect.intersects(mRect2, mRect1)) {
|
||||||
|
refPos[y] = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
dis = mLabelDistanceToLabel;
|
||||||
|
|
||||||
|
for (PointTextContainer areaLabel : areaLabels) {
|
||||||
|
|
||||||
|
mRect1.set((int) areaLabel.x - dis, (int) areaLabel.y - areaLabel.boundary.height() - dis,
|
||||||
|
(int) areaLabel.x + areaLabel.boundary.width() + dis, (int) areaLabel.y + dis);
|
||||||
|
|
||||||
|
for (int y = 0; y < refPos.length; y++) {
|
||||||
|
if (refPos[y] != null) {
|
||||||
|
|
||||||
|
mRect2.set((int) refPos[y].x, (int) (refPos[y].y - refPos[y].height),
|
||||||
|
(int) (refPos[y].x + refPos[y].width), (int) (refPos[y].y));
|
||||||
|
|
||||||
|
if (android.graphics.Rect.intersects(mRect2, mRect1)) {
|
||||||
|
refPos[y] = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mDependencyCache.removeReferencePointsFromDependencyCache(refPos);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method removes the area labels, that are not visible in the actual tile.
|
||||||
|
*
|
||||||
|
* @param areaLabels
|
||||||
|
* area Labels from the actual tile
|
||||||
|
*/
|
||||||
|
private void removeOutOfTileAreaLabels(List<PointTextContainer> areaLabels) {
|
||||||
|
for (int i = 0; i < areaLabels.size(); i++) {
|
||||||
|
mLabel = areaLabels.get(i);
|
||||||
|
|
||||||
|
if (mLabel.x > Tile.TILE_SIZE) {
|
||||||
|
areaLabels.remove(i);
|
||||||
|
|
||||||
|
i--;
|
||||||
|
} else if (mLabel.y - mLabel.boundary.height() > Tile.TILE_SIZE) {
|
||||||
|
areaLabels.remove(i);
|
||||||
|
|
||||||
|
i--;
|
||||||
|
} else if (mLabel.x + mLabel.boundary.width() < 0.0f) {
|
||||||
|
areaLabels.remove(i);
|
||||||
|
|
||||||
|
i--;
|
||||||
|
} else if (mLabel.y + mLabel.boundary.height() < 0.0f) {
|
||||||
|
areaLabels.remove(i);
|
||||||
|
|
||||||
|
i--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method removes the labels, that are not visible in the actual tile.
|
||||||
|
*
|
||||||
|
* @param labels
|
||||||
|
* Labels from the actual tile
|
||||||
|
*/
|
||||||
|
private void removeOutOfTileLabels(List<PointTextContainer> labels) {
|
||||||
|
for (int i = 0; i < labels.size();) {
|
||||||
|
mLabel = labels.get(i);
|
||||||
|
|
||||||
|
if (mLabel.x - mLabel.boundary.width() / 2 > Tile.TILE_SIZE) {
|
||||||
|
labels.remove(i);
|
||||||
|
mLabel = null;
|
||||||
|
} else if (mLabel.y - mLabel.boundary.height() > Tile.TILE_SIZE) {
|
||||||
|
labels.remove(i);
|
||||||
|
mLabel = null;
|
||||||
|
} else if ((mLabel.x - mLabel.boundary.width() / 2 + mLabel.boundary.width()) < 0.0f) {
|
||||||
|
labels.remove(i);
|
||||||
|
mLabel = null;
|
||||||
|
} else if (mLabel.y < 0.0f) {
|
||||||
|
labels.remove(i);
|
||||||
|
mLabel = null;
|
||||||
|
} else {
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method removes the Symbols, that are not visible in the actual tile.
|
||||||
|
*
|
||||||
|
* @param symbols
|
||||||
|
* Symbols from the actual tile
|
||||||
|
*/
|
||||||
|
private void removeOutOfTileSymbols(List<SymbolContainer> symbols) {
|
||||||
|
for (int i = 0; i < symbols.size();) {
|
||||||
|
mSymbolContainer = symbols.get(i);
|
||||||
|
|
||||||
|
if (mSymbolContainer.x > Tile.TILE_SIZE) {
|
||||||
|
symbols.remove(i);
|
||||||
|
} else if (mSymbolContainer.y > Tile.TILE_SIZE) {
|
||||||
|
symbols.remove(i);
|
||||||
|
} else if (mSymbolContainer.x + mSymbolContainer.symbol.getWidth() < 0.0f) {
|
||||||
|
symbols.remove(i);
|
||||||
|
} else if (mSymbolContainer.y + mSymbolContainer.symbol.getHeight() < 0.0f) {
|
||||||
|
symbols.remove(i);
|
||||||
|
} else {
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method removes all the area labels, that overlap each other. So that the output is collision free
|
||||||
|
*
|
||||||
|
* @param areaLabels
|
||||||
|
* area labels from the actual tile
|
||||||
|
*/
|
||||||
|
private void removeOverlappingAreaLabels(List<PointTextContainer> areaLabels) {
|
||||||
|
int dis = mLabelDistanceToLabel;
|
||||||
|
|
||||||
|
for (int x = 0; x < areaLabels.size(); x++) {
|
||||||
|
mLabel = areaLabels.get(x);
|
||||||
|
mRect1.set((int) mLabel.x - dis, (int) mLabel.y - dis,
|
||||||
|
(int) (mLabel.x + mLabel.boundary.width()) + dis,
|
||||||
|
(int) (mLabel.y + mLabel.boundary.height() + dis));
|
||||||
|
|
||||||
|
for (int y = x + 1; y < areaLabels.size(); y++) {
|
||||||
|
if (y != x) {
|
||||||
|
mLabel = areaLabels.get(y);
|
||||||
|
mRect2.set((int) mLabel.x, (int) mLabel.y,
|
||||||
|
(int) (mLabel.x + mLabel.boundary.width()),
|
||||||
|
(int) (mLabel.y + mLabel.boundary.height()));
|
||||||
|
|
||||||
|
if (android.graphics.Rect.intersects(mRect1, mRect2)) {
|
||||||
|
areaLabels.remove(y);
|
||||||
|
|
||||||
|
y--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes the the symbols that overlap with area labels.
|
||||||
|
*
|
||||||
|
* @param symbols
|
||||||
|
* list of symbols
|
||||||
|
* @param pTC
|
||||||
|
* list of labels
|
||||||
|
*/
|
||||||
|
private void removeOverlappingSymbolsWithAreaLabels(List<SymbolContainer> symbols, List<PointTextContainer> pTC) {
|
||||||
|
int dis = mLabelDistanceToSymbol;
|
||||||
|
|
||||||
|
for (int x = 0; x < pTC.size(); x++) {
|
||||||
|
mLabel = pTC.get(x);
|
||||||
|
|
||||||
|
mRect1.set((int) mLabel.x - dis, (int) (mLabel.y - mLabel.boundary.height()) - dis,
|
||||||
|
(int) (mLabel.x + mLabel.boundary.width() + dis), (int) (mLabel.y + dis));
|
||||||
|
|
||||||
|
for (int y = 0; y < symbols.size(); y++) {
|
||||||
|
mSymbolContainer = symbols.get(y);
|
||||||
|
|
||||||
|
mRect2.set((int) mSymbolContainer.x, (int) mSymbolContainer.y,
|
||||||
|
(int) (mSymbolContainer.x + mSymbolContainer.symbol.getWidth()),
|
||||||
|
(int) (mSymbolContainer.y + mSymbolContainer.symbol.getHeight()));
|
||||||
|
|
||||||
|
if (android.graphics.Rect.intersects(mRect1, mRect2)) {
|
||||||
|
symbols.remove(y);
|
||||||
|
y--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int getLabelDistanceToLabel() {
|
||||||
|
return mLabelDistanceToLabel;
|
||||||
|
}
|
||||||
|
|
||||||
|
int getLabelDistanceToSymbol() {
|
||||||
|
return mLabelDistanceToSymbol;
|
||||||
|
}
|
||||||
|
|
||||||
|
int getPlacementOption() {
|
||||||
|
return PLACEMENT_MODEL;
|
||||||
|
}
|
||||||
|
|
||||||
|
int getStartDistanceToSymbols() {
|
||||||
|
return mStartDistanceToSymbols;
|
||||||
|
}
|
||||||
|
|
||||||
|
int getSymbolDistanceToSymbol() {
|
||||||
|
return mSymbolDistanceToSymbol;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The inputs are all the label and symbol objects of the current tile. The output is overlap free label and symbol
|
||||||
|
* placement with the greedy strategy. The placement model is either the two fixed point or the four fixed point
|
||||||
|
* model.
|
||||||
|
*
|
||||||
|
* @param labels
|
||||||
|
* labels from the current tile.
|
||||||
|
* @param symbols
|
||||||
|
* symbols of the current tile.
|
||||||
|
* @param areaLabels
|
||||||
|
* area labels from the current tile.
|
||||||
|
* @param cT
|
||||||
|
* current tile with the x,y- coordinates and the zoom level.
|
||||||
|
* @return the processed list of labels.
|
||||||
|
*/
|
||||||
|
List<PointTextContainer> placeLabels(List<PointTextContainer> labels, List<SymbolContainer> symbols,
|
||||||
|
List<PointTextContainer> areaLabels, Tile cT) {
|
||||||
|
List<PointTextContainer> returnLabels = labels;
|
||||||
|
mDependencyCache.generateTileAndDependencyOnTile(cT);
|
||||||
|
|
||||||
|
preprocessAreaLabels(areaLabels);
|
||||||
|
|
||||||
|
preprocessLabels(returnLabels);
|
||||||
|
|
||||||
|
preprocessSymbols(symbols);
|
||||||
|
|
||||||
|
removeEmptySymbolReferences(returnLabels, symbols);
|
||||||
|
|
||||||
|
removeOverlappingSymbolsWithAreaLabels(symbols, areaLabels);
|
||||||
|
|
||||||
|
mDependencyCache.removeOverlappingObjectsWithDependencyOnTile(returnLabels, areaLabels, symbols);
|
||||||
|
|
||||||
|
if (!returnLabels.isEmpty()) {
|
||||||
|
switch (PLACEMENT_MODEL) {
|
||||||
|
case 0:
|
||||||
|
returnLabels = processTwoPointGreedy(returnLabels, symbols, areaLabels);
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
returnLabels = processFourPointGreedy(returnLabels, symbols, areaLabels);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mDependencyCache.fillDependencyOnTile(returnLabels, symbols, areaLabels);
|
||||||
|
|
||||||
|
return returnLabels;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method removes all the Symbols, that overlap each other. So that the output is collision free.
|
||||||
|
*
|
||||||
|
* @param symbols
|
||||||
|
* symbols from the actual tile
|
||||||
|
*/
|
||||||
|
void removeOverlappingSymbols(List<SymbolContainer> symbols) {
|
||||||
|
int dis = mSymbolDistanceToSymbol;
|
||||||
|
|
||||||
|
for (int x = 0; x < symbols.size(); x++) {
|
||||||
|
mSymbolContainer = symbols.get(x);
|
||||||
|
mRect1.set((int) mSymbolContainer.x - dis, (int) mSymbolContainer.y - dis,
|
||||||
|
(int) mSymbolContainer.x + mSymbolContainer.symbol.getWidth() + dis,
|
||||||
|
(int) mSymbolContainer.y + mSymbolContainer.symbol.getHeight() + dis);
|
||||||
|
|
||||||
|
for (int y = x + 1; y < symbols.size(); y++) {
|
||||||
|
if (y != x) {
|
||||||
|
mSymbolContainer = symbols.get(y);
|
||||||
|
mRect2.set((int) mSymbolContainer.x, (int) mSymbolContainer.y,
|
||||||
|
(int) mSymbolContainer.x + mSymbolContainer.symbol.getWidth(),
|
||||||
|
(int) mSymbolContainer.y + mSymbolContainer.symbol.getHeight());
|
||||||
|
|
||||||
|
if (android.graphics.Rect.intersects(mRect2, mRect1)) {
|
||||||
|
symbols.remove(y);
|
||||||
|
y--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void setLabelDistanceToLabel(int labelDistanceToLabel) {
|
||||||
|
mLabelDistanceToLabel = labelDistanceToLabel;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setLabelDistanceToSymbol(int labelDistanceToSymbol) {
|
||||||
|
mLabelDistanceToSymbol = labelDistanceToSymbol;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setStartDistanceToSymbols(int startDistanceToSymbols) {
|
||||||
|
mStartDistanceToSymbols = startDistanceToSymbols;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setSymbolDistanceToSymbol(int symbolDistanceToSymbol) {
|
||||||
|
mSymbolDistanceToSymbol = symbolDistanceToSymbol;
|
||||||
|
}
|
||||||
|
}
|
||||||
63
src/org/mapsforge/android/swrenderer/LayerContainer.java
Normal file
63
src/org/mapsforge/android/swrenderer/LayerContainer.java
Normal file
@@ -0,0 +1,63 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010, 2011, 2012 mapsforge.org
|
||||||
|
*
|
||||||
|
* 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.mapsforge.android.swrenderer;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
|
||||||
|
import android.graphics.Paint;
|
||||||
|
|
||||||
|
class LayerContainer {
|
||||||
|
|
||||||
|
final LevelContainer[] mLevels;
|
||||||
|
final boolean[] mLevelActive;
|
||||||
|
boolean mActive;
|
||||||
|
|
||||||
|
LayerContainer(int levels) {
|
||||||
|
mLevels = new LevelContainer[levels];
|
||||||
|
mLevelActive = new boolean[levels];
|
||||||
|
mActive = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
List<ShapeContainer> add(int level, ShapeContainer shapeContainer, Paint paint) {
|
||||||
|
mActive = true;
|
||||||
|
LevelContainer levelContainer = mLevels[level];
|
||||||
|
if (levelContainer == null) {
|
||||||
|
levelContainer = new LevelContainer();
|
||||||
|
mLevels[level] = levelContainer;
|
||||||
|
}
|
||||||
|
|
||||||
|
levelContainer.add(shapeContainer, paint);
|
||||||
|
|
||||||
|
mLevelActive[level] = true;
|
||||||
|
|
||||||
|
return levelContainer.mShapeContainers;
|
||||||
|
}
|
||||||
|
|
||||||
|
void clear() {
|
||||||
|
if (!mActive)
|
||||||
|
return;
|
||||||
|
|
||||||
|
mActive = false;
|
||||||
|
|
||||||
|
for (int level = mLevels.length - 1; level >= 0; level--) {
|
||||||
|
if (mLevelActive[level]) {
|
||||||
|
LevelContainer levelContainer = mLevels[level];
|
||||||
|
mLevelActive[level] = false;
|
||||||
|
levelContainer.clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
45
src/org/mapsforge/android/swrenderer/LevelContainer.java
Normal file
45
src/org/mapsforge/android/swrenderer/LevelContainer.java
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010, 2011, 2012 mapsforge.org
|
||||||
|
*
|
||||||
|
* 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.mapsforge.android.swrenderer;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
|
||||||
|
|
||||||
|
import android.graphics.Paint;
|
||||||
|
|
||||||
|
class LevelContainer {
|
||||||
|
final ArrayList<ShapeContainer> mShapeContainers;
|
||||||
|
Paint[] mPaint;
|
||||||
|
|
||||||
|
LevelContainer() {
|
||||||
|
mShapeContainers = new ArrayList<ShapeContainer>(20);
|
||||||
|
mPaint = new Paint[2];
|
||||||
|
}
|
||||||
|
|
||||||
|
void add(ShapeContainer shapeContainer, Paint paint) {
|
||||||
|
if (mPaint[0] == null)
|
||||||
|
mPaint[0] = paint;
|
||||||
|
else if (mPaint[0] != paint)
|
||||||
|
mPaint[1] = paint;
|
||||||
|
|
||||||
|
mShapeContainers.add(shapeContainer);
|
||||||
|
}
|
||||||
|
|
||||||
|
void clear() {
|
||||||
|
mShapeContainers.clear();
|
||||||
|
mPaint[0] = null;
|
||||||
|
mPaint[1] = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
643
src/org/mapsforge/android/swrenderer/MapRenderer.java
Normal file
643
src/org/mapsforge/android/swrenderer/MapRenderer.java
Normal file
@@ -0,0 +1,643 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2011 The Android Open Source Project
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.mapsforge.android.swrenderer;
|
||||||
|
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
import java.nio.ByteOrder;
|
||||||
|
import java.nio.FloatBuffer;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.LinkedHashMap;
|
||||||
|
|
||||||
|
import javax.microedition.khronos.egl.EGLConfig;
|
||||||
|
import javax.microedition.khronos.opengles.GL10;
|
||||||
|
|
||||||
|
import org.mapsforge.android.DebugSettings;
|
||||||
|
import org.mapsforge.android.MapView;
|
||||||
|
import org.mapsforge.android.mapgenerator.JobParameters;
|
||||||
|
import org.mapsforge.android.mapgenerator.MapGenerator;
|
||||||
|
import org.mapsforge.android.mapgenerator.MapGeneratorJob;
|
||||||
|
import org.mapsforge.android.mapgenerator.MapWorker;
|
||||||
|
import org.mapsforge.android.mapgenerator.TileCacheKey;
|
||||||
|
import org.mapsforge.android.mapgenerator.TileDistanceSort;
|
||||||
|
import org.mapsforge.android.utils.GlUtils;
|
||||||
|
import org.mapsforge.core.MapPosition;
|
||||||
|
import org.mapsforge.core.MercatorProjection;
|
||||||
|
import org.mapsforge.core.Tile;
|
||||||
|
|
||||||
|
import android.opengl.GLES20;
|
||||||
|
import android.opengl.GLUtils;
|
||||||
|
import android.opengl.Matrix;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class MapRenderer implements org.mapsforge.android.MapRenderer {
|
||||||
|
// private static String TAG = "MapRenderer";
|
||||||
|
|
||||||
|
private static final int FLOAT_SIZE_BYTES = 4;
|
||||||
|
private static final int TRIANGLE_VERTICES_DATA_POS_OFFSET = 0;
|
||||||
|
private static final int TRIANGLE_VERTICES_DATA_UV_OFFSET = 3;
|
||||||
|
|
||||||
|
private int mProgram;
|
||||||
|
private int muMVPMatrixHandle;
|
||||||
|
private int maPositionHandle;
|
||||||
|
private int maTextureHandle;
|
||||||
|
private int muScaleHandle;
|
||||||
|
private FloatBuffer mVertices;
|
||||||
|
private float[] mMatrix = new float[16];
|
||||||
|
|
||||||
|
private int mWidth, mHeight;
|
||||||
|
private double mDrawX, mDrawY;
|
||||||
|
private long mTileX, mTileY;
|
||||||
|
private float mMapScale;
|
||||||
|
private DebugSettings mDebugSettings;
|
||||||
|
private JobParameters mJobParameter;
|
||||||
|
private MapPosition mMapPosition, mPrevMapPosition;
|
||||||
|
|
||||||
|
private ArrayList<MapGeneratorJob> mJobList;
|
||||||
|
|
||||||
|
ArrayList<Integer> mTextures;
|
||||||
|
MapWorker mMapWorker;
|
||||||
|
MapView mMapView;
|
||||||
|
|
||||||
|
GLMapTile[] currentTiles;
|
||||||
|
GLMapTile[] newTiles;
|
||||||
|
int currentTileCnt = 0;
|
||||||
|
|
||||||
|
private TileCacheKey mTileCacheKey;
|
||||||
|
private LinkedHashMap<TileCacheKey, GLMapTile> mTiles;
|
||||||
|
private ArrayList<GLMapTile> mTileList;
|
||||||
|
|
||||||
|
private boolean processedTile = true;
|
||||||
|
|
||||||
|
private static final int TRIANGLE_VERTICES_DATA_STRIDE_BYTES = 5 * FLOAT_SIZE_BYTES;
|
||||||
|
|
||||||
|
private boolean mInitial;
|
||||||
|
|
||||||
|
private final TileDistanceSort tileDistanceSort = new TileDistanceSort();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param mapView
|
||||||
|
* the MapView
|
||||||
|
*/
|
||||||
|
public MapRenderer(MapView mapView) {
|
||||||
|
mMapView = mapView;
|
||||||
|
mMapWorker = mapView.getMapWorker();
|
||||||
|
mDebugSettings = mapView.getDebugSettings();
|
||||||
|
mMapScale = 1;
|
||||||
|
|
||||||
|
float[] vertices = {
|
||||||
|
0, 0, 0, 0, 0.5f,
|
||||||
|
0, 1, 0, 0, 0,
|
||||||
|
1, 0, 0, 0.5f, 0.5f,
|
||||||
|
1, 1, 0, 0.5f, 0 };
|
||||||
|
|
||||||
|
mVertices = ByteBuffer.allocateDirect(4 * TRIANGLE_VERTICES_DATA_STRIDE_BYTES)
|
||||||
|
.order(ByteOrder.nativeOrder()).asFloatBuffer();
|
||||||
|
mVertices.put(vertices);
|
||||||
|
|
||||||
|
mTextures = new ArrayList<Integer>();
|
||||||
|
mJobList = new ArrayList<MapGeneratorJob>();
|
||||||
|
|
||||||
|
mTiles = new LinkedHashMap<TileCacheKey, GLMapTile>(100);
|
||||||
|
mTileList = new ArrayList<GLMapTile>();
|
||||||
|
|
||||||
|
mTileCacheKey = new TileCacheKey();
|
||||||
|
mInitial = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void limitCache(byte zoom, int remove) {
|
||||||
|
long x = mTileX;
|
||||||
|
long y = mTileY;
|
||||||
|
int diff;
|
||||||
|
|
||||||
|
for (GLMapTile t : mTileList) {
|
||||||
|
|
||||||
|
diff = (t.zoomLevel - zoom);
|
||||||
|
|
||||||
|
if (diff != 0)
|
||||||
|
{
|
||||||
|
float z = (diff > 0) ? (1 << diff) : 1.0f / (1 << -diff);
|
||||||
|
t.distance = (long) (Math.abs((t.tileX) * z - x) + Math.abs((t.tileY) * z - y));
|
||||||
|
t.distance *= 2 * diff * diff;
|
||||||
|
} else {
|
||||||
|
t.distance = (Math.abs(t.tileX - x) + Math.abs(t.tileY - y));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Collections.sort(mTileList, tileDistanceSort);
|
||||||
|
|
||||||
|
for (int j = mTileList.size() - 1, cnt = 0; cnt < remove; j--, cnt++) {
|
||||||
|
GLMapTile t = mTileList.remove(j);
|
||||||
|
|
||||||
|
mTileCacheKey.set(t.tileX, t.tileY, t.zoomLevel);
|
||||||
|
mTiles.remove(mTileCacheKey);
|
||||||
|
|
||||||
|
for (int i = 0; i < 4; i++) {
|
||||||
|
if (t.child[i] != null)
|
||||||
|
t.child[i].parent = null;
|
||||||
|
}
|
||||||
|
if (t.parent != null) {
|
||||||
|
for (int i = 0; i < 4; i++) {
|
||||||
|
if (t.parent.child[i] == t)
|
||||||
|
t.parent.child[i] = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (t.hasTexture()) {
|
||||||
|
synchronized (mTextures) {
|
||||||
|
mTextures.add(new Integer(t.getTexture()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean updateVisibleList(long x, long y, byte zoomLevel) {
|
||||||
|
float scale = mMapPosition.scale;
|
||||||
|
double add = 1.0f / scale;
|
||||||
|
int offsetX = (int) ((mWidth >> 1) * add);
|
||||||
|
int offsetY = (int) ((mHeight >> 1) * add);
|
||||||
|
|
||||||
|
long pixelRight = x + offsetX;
|
||||||
|
long pixelBottom = y + offsetY;
|
||||||
|
long pixelLeft = x - offsetX;
|
||||||
|
long pixelTop = y - offsetY;
|
||||||
|
|
||||||
|
long tileLeft = MercatorProjection.pixelXToTileX(pixelLeft, zoomLevel);
|
||||||
|
long tileTop = MercatorProjection.pixelYToTileY(pixelTop, zoomLevel);
|
||||||
|
long tileRight = MercatorProjection.pixelXToTileX(pixelRight, zoomLevel);
|
||||||
|
long tileBottom = MercatorProjection.pixelYToTileY(pixelBottom, zoomLevel);
|
||||||
|
|
||||||
|
mJobList.clear();
|
||||||
|
|
||||||
|
MapGenerator mapGenerator = mMapView.getMapGenerator();
|
||||||
|
int tiles = 0;
|
||||||
|
for (long tileY = tileTop - 1; tileY <= tileBottom + 1; tileY++) {
|
||||||
|
for (long tileX = tileLeft - 1; tileX <= tileRight + 1; tileX++) {
|
||||||
|
|
||||||
|
GLMapTile tile = mTiles.get(mTileCacheKey.set(tileX, tileY, zoomLevel));
|
||||||
|
|
||||||
|
if (tile == null) {
|
||||||
|
tile = new GLMapTile(tileX, tileY, zoomLevel);
|
||||||
|
TileCacheKey key = new TileCacheKey(mTileCacheKey);
|
||||||
|
mTiles.put(key, tile);
|
||||||
|
|
||||||
|
mTileCacheKey.set((tileX >> 1), (tileY >> 1), (byte) (zoomLevel - 1));
|
||||||
|
tile.parent = mTiles.get(mTileCacheKey);
|
||||||
|
|
||||||
|
long xx = tileX << 1;
|
||||||
|
long yy = tileY << 1;
|
||||||
|
byte z = (byte) (zoomLevel + 1);
|
||||||
|
|
||||||
|
tile.child[0] = mTiles.get(mTileCacheKey.set(xx, yy, z));
|
||||||
|
tile.child[1] = mTiles.get(mTileCacheKey.set(xx + 1, yy, z));
|
||||||
|
tile.child[2] = mTiles.get(mTileCacheKey.set(xx, yy + 1, z));
|
||||||
|
tile.child[3] = mTiles.get(mTileCacheKey.set(xx + 1, yy + 1, z));
|
||||||
|
|
||||||
|
mTileList.add(tile);
|
||||||
|
}
|
||||||
|
|
||||||
|
newTiles[tiles++] = tile;
|
||||||
|
|
||||||
|
if (!tile.isDrawn || (tile.getScale() != scale)) {
|
||||||
|
tile.isLoading = true;
|
||||||
|
// approximation for TileScheduler
|
||||||
|
if (tileY < tileTop || tileY > tileBottom || tileX < tileLeft || tileX > tileRight)
|
||||||
|
tile.isVisible = false;
|
||||||
|
else
|
||||||
|
tile.isVisible = true;
|
||||||
|
|
||||||
|
MapGeneratorJob job = new MapGeneratorJob(tile, mapGenerator,
|
||||||
|
mJobParameter, mDebugSettings);
|
||||||
|
job.setScale(scale);
|
||||||
|
mJobList.add(job);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
synchronized (this) {
|
||||||
|
|
||||||
|
limitCache(zoomLevel, (mTiles.size() - 200));
|
||||||
|
|
||||||
|
for (int i = 0; i < tiles; i++)
|
||||||
|
currentTiles[i] = newTiles[i];
|
||||||
|
currentTileCnt = tiles;
|
||||||
|
|
||||||
|
mDrawX = x;
|
||||||
|
mDrawY = y;
|
||||||
|
mMapScale = scale;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mJobList.size() > 0) {
|
||||||
|
mMapView.getJobQueue().setJobs(mJobList);
|
||||||
|
synchronized (mMapWorker) {
|
||||||
|
mMapWorker.notify();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public synchronized void redrawTiles(boolean clear) {
|
||||||
|
|
||||||
|
boolean update = false;
|
||||||
|
|
||||||
|
mMapPosition = mMapView.getMapPosition().getMapPosition();
|
||||||
|
|
||||||
|
long x = (long) MercatorProjection.longitudeToPixelX(mMapPosition.geoPoint.getLongitude(),
|
||||||
|
mMapPosition.zoomLevel);
|
||||||
|
long y = (long) MercatorProjection
|
||||||
|
.latitudeToPixelY(mMapPosition.geoPoint.getLatitude(), mMapPosition.zoomLevel);
|
||||||
|
|
||||||
|
long tileX = MercatorProjection.pixelXToTileX(x, mMapPosition.zoomLevel);
|
||||||
|
long tileY = MercatorProjection.pixelYToTileY(y, mMapPosition.zoomLevel);
|
||||||
|
float scale = mMapPosition.scale;
|
||||||
|
|
||||||
|
if (mInitial) {
|
||||||
|
mInitial = false;
|
||||||
|
mPrevMapPosition = mMapPosition;
|
||||||
|
mTileX = tileX;
|
||||||
|
mTileY = tileY;
|
||||||
|
update = true;
|
||||||
|
} else if (mPrevMapPosition.zoomLevel != mMapPosition.zoomLevel) {
|
||||||
|
update = true;
|
||||||
|
} else if (mMapScale != scale) {
|
||||||
|
update = true;
|
||||||
|
} else if (tileX != mTileX || tileY != mTileY) {
|
||||||
|
update = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
mTileX = tileX;
|
||||||
|
mTileY = tileY;
|
||||||
|
|
||||||
|
if (update) {
|
||||||
|
// do not change list while drawing
|
||||||
|
// synchronized (this) {
|
||||||
|
mPrevMapPosition = mMapPosition;
|
||||||
|
updateVisibleList(x, y, mMapPosition.zoomLevel);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
synchronized (this) {
|
||||||
|
mDrawX = x;
|
||||||
|
mDrawY = y;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mMapView.requestRender();
|
||||||
|
}
|
||||||
|
|
||||||
|
private MapGeneratorJob mMapGeneratorJob = null;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean passTile(MapGeneratorJob mapGeneratorJob) {
|
||||||
|
|
||||||
|
mMapGeneratorJob = mapGeneratorJob;
|
||||||
|
processedTile = false;
|
||||||
|
mMapView.requestRender();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean drawTile(GLMapTile tile, int level, float height) {
|
||||||
|
|
||||||
|
// do not recurse more than two parents
|
||||||
|
if (level > 2)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
if (!tile.hasTexture()) {
|
||||||
|
// draw parent below current zoom level tiles
|
||||||
|
float h = height > 0 ? height * 2 : 0.1f;
|
||||||
|
|
||||||
|
if (level <= 2 && tile.parent != null)
|
||||||
|
return drawTile(tile.parent, level + 1, h);
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
float z = 1;
|
||||||
|
double drawX = mDrawX;
|
||||||
|
double drawY = mDrawY;
|
||||||
|
// translate all pixel coordinates * 'zoom factor difference'
|
||||||
|
// TODO clip tile when drawing parent
|
||||||
|
int diff = tile.zoomLevel - mMapPosition.zoomLevel;
|
||||||
|
if (diff != 0) {
|
||||||
|
if (diff > 0) {
|
||||||
|
z = (1 << diff);
|
||||||
|
} else {
|
||||||
|
z = 1.0f / (1 << -diff);
|
||||||
|
}
|
||||||
|
drawX = MercatorProjection
|
||||||
|
.longitudeToPixelX(mMapPosition.geoPoint.getLongitude(), tile.zoomLevel);
|
||||||
|
drawY = MercatorProjection
|
||||||
|
.latitudeToPixelY(mMapPosition.geoPoint.getLatitude(), tile.zoomLevel);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
float mapScale = mMapScale / z;
|
||||||
|
int tileSize = Tile.TILE_SIZE;
|
||||||
|
float size = tileSize * mapScale;
|
||||||
|
|
||||||
|
float x = (float) ((tile.pixelX) - drawX) * mapScale;
|
||||||
|
float y = (float) ((tile.pixelY + tileSize) - drawY) * mapScale;
|
||||||
|
|
||||||
|
if (x + size < -mWidth / 2 || x > mWidth / 2) {
|
||||||
|
// Log.i(TAG, tile + " skip X " + x + " " + y);
|
||||||
|
tile.isVisible = false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (y < -mHeight / 2 || y - size > mHeight / 2) {
|
||||||
|
// Log.i(TAG, tile + " skip Y " + x + " " + y);
|
||||||
|
tile.isVisible = false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Log.i(TAG, tile + " draw " + x + " " + y);
|
||||||
|
tile.isVisible = true;
|
||||||
|
|
||||||
|
// set drawn tile scale (texture size)
|
||||||
|
GLES20.glUniform1f(muScaleHandle, tile.getScale());
|
||||||
|
|
||||||
|
Matrix.setIdentityM(mMatrix, 0);
|
||||||
|
// map tile GL coordinates to screen coordinates
|
||||||
|
Matrix.scaleM(mMatrix, 0, 2.0f * (tileSize * z) / mWidth, 2.0f * (tileSize * z) / mHeight, 1);
|
||||||
|
|
||||||
|
// scale tile
|
||||||
|
Matrix.scaleM(mMatrix, 0, mapScale / z, mapScale / z, 1);
|
||||||
|
|
||||||
|
// translate tile
|
||||||
|
Matrix.translateM(mMatrix, 0, (x / size), -(y / size), height);
|
||||||
|
|
||||||
|
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, tile.getTexture());
|
||||||
|
// GlUtils.checkGlError("glBindTexture");
|
||||||
|
|
||||||
|
GLES20.glUniformMatrix4fv(muMVPMatrixHandle, 1, false, mMatrix, 0);
|
||||||
|
GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onDrawFrame(GL10 glUnused) {
|
||||||
|
boolean loadedTexture = false;
|
||||||
|
GLES20.glDisable(GLES20.GL_SCISSOR_TEST);
|
||||||
|
GLES20.glClearColor(0.95f, 0.95f, 0.94f, 1.0f);
|
||||||
|
// GLES20.glClear(GLES20.GL_DEPTH_BUFFER_BIT | GLES20.GL_COLOR_BUFFER_BIT);
|
||||||
|
GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);
|
||||||
|
|
||||||
|
GLES20.glUseProgram(mProgram);
|
||||||
|
GlUtils.checkGlError("glUseProgram");
|
||||||
|
|
||||||
|
mVertices.position(TRIANGLE_VERTICES_DATA_POS_OFFSET);
|
||||||
|
GLES20.glVertexAttribPointer(maPositionHandle, 3, GLES20.GL_FLOAT, false,
|
||||||
|
TRIANGLE_VERTICES_DATA_STRIDE_BYTES, mVertices);
|
||||||
|
GlUtils.checkGlError("glVertexAttribPointer maPosition");
|
||||||
|
|
||||||
|
GLES20.glEnableVertexAttribArray(maPositionHandle);
|
||||||
|
GlUtils.checkGlError("glEnableVertexAttribArray maPositionHandle");
|
||||||
|
|
||||||
|
mVertices.position(TRIANGLE_VERTICES_DATA_UV_OFFSET);
|
||||||
|
GLES20.glVertexAttribPointer(maTextureHandle, 2, GLES20.GL_FLOAT, false,
|
||||||
|
TRIANGLE_VERTICES_DATA_STRIDE_BYTES, mVertices);
|
||||||
|
GlUtils.checkGlError("glVertexAttribPointer maTextureHandle");
|
||||||
|
|
||||||
|
GLES20.glEnableVertexAttribArray(maTextureHandle);
|
||||||
|
GlUtils.checkGlError("glEnableVertexAttribArray maTextureHandle");
|
||||||
|
|
||||||
|
GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
|
||||||
|
|
||||||
|
GLMapTile tile, child, child2;
|
||||||
|
|
||||||
|
GLES20.glEnable(GLES20.GL_SCISSOR_TEST);
|
||||||
|
|
||||||
|
// lock position and currentTiles while drawing
|
||||||
|
synchronized (this) {
|
||||||
|
if (mMapGeneratorJob != null) {
|
||||||
|
|
||||||
|
tile = (GLMapTile) mMapGeneratorJob.tile;
|
||||||
|
// TODO tile bitmaps texture to smaller parts avoiding uploading full
|
||||||
|
// bitmap when not necessary
|
||||||
|
if (tile.getTexture() >= 0) {
|
||||||
|
// reuse tile texture
|
||||||
|
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, tile.getTexture());
|
||||||
|
GLUtils.texSubImage2D(GLES20.GL_TEXTURE_2D, 0, 0, 0, mMapGeneratorJob.getBitmap());
|
||||||
|
} else if (mTextures.size() > 0) {
|
||||||
|
// reuse texture from previous tiles
|
||||||
|
Integer texture;
|
||||||
|
texture = mTextures.remove(mTextures.size() - 1);
|
||||||
|
|
||||||
|
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, texture.intValue());
|
||||||
|
GLUtils.texSubImage2D(GLES20.GL_TEXTURE_2D, 0, 0, 0, mMapGeneratorJob.getBitmap());
|
||||||
|
tile.setTexture(texture.intValue());
|
||||||
|
} else {
|
||||||
|
// create texture
|
||||||
|
tile.setTexture(GlUtils.loadTextures(mMapGeneratorJob.getBitmap()));
|
||||||
|
}
|
||||||
|
|
||||||
|
tile.setScale(mMapGeneratorJob.getScale());
|
||||||
|
tile.isDrawn = true;
|
||||||
|
tile.isLoading = false;
|
||||||
|
|
||||||
|
mMapGeneratorJob = null;
|
||||||
|
processedTile = true;
|
||||||
|
loadedTexture = true;
|
||||||
|
}
|
||||||
|
int tileSize = (int) (Tile.TILE_SIZE * mMapScale);
|
||||||
|
int hWidth = mWidth >> 1;
|
||||||
|
int hHeight = mHeight >> 1;
|
||||||
|
for (int i = 0, n = currentTileCnt; i < n; i++) {
|
||||||
|
tile = currentTiles[i];
|
||||||
|
|
||||||
|
float x = (float) (tile.pixelX - mDrawX);
|
||||||
|
float y = (float) (tile.pixelY - mDrawY);
|
||||||
|
|
||||||
|
// clip rendering to tile boundaries
|
||||||
|
GLES20.glScissor(
|
||||||
|
hWidth + (int) (x * mMapScale) - 2,
|
||||||
|
hHeight - (int) (y * mMapScale) - tileSize - 2,
|
||||||
|
tileSize + 4, tileSize + 4);
|
||||||
|
|
||||||
|
if (drawTile(tile, 0, 0.0f))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// or two zoom level above
|
||||||
|
for (int k = 0; k < 4; k++) {
|
||||||
|
if (((child = tile.child[k]) != null)) {
|
||||||
|
|
||||||
|
if (drawTile(child, 2, 0.1f))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
for (int j = 0; j < 4; j++)
|
||||||
|
if ((child2 = child.child[j]) != null)
|
||||||
|
drawTile(child2, 2, 0.1f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (loadedTexture) {
|
||||||
|
synchronized (mMapWorker) {
|
||||||
|
mMapWorker.notify();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onSurfaceChanged(GL10 glUnused, int width, int height) {
|
||||||
|
mWidth = width;
|
||||||
|
mHeight = height;
|
||||||
|
|
||||||
|
int tiles = (mWidth / Tile.TILE_SIZE + 4) * (mHeight / Tile.TILE_SIZE + 4);
|
||||||
|
currentTiles = new GLMapTile[tiles];
|
||||||
|
newTiles = new GLMapTile[tiles];
|
||||||
|
|
||||||
|
GLES20.glViewport(0, 0, width, height);
|
||||||
|
|
||||||
|
mDebugSettings = mMapView.getDebugSettings();
|
||||||
|
mJobParameter = mMapView.getJobParameters();
|
||||||
|
|
||||||
|
mTiles.clear();
|
||||||
|
mTileList.clear();
|
||||||
|
mTextures.clear();
|
||||||
|
mInitial = true;
|
||||||
|
mMapView.redrawTiles();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onSurfaceCreated(GL10 glUnused, EGLConfig config) {
|
||||||
|
|
||||||
|
mProgram = GlUtils.createProgram(mVertexShader, mFragmentShader);
|
||||||
|
if (mProgram == 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
maPositionHandle = GLES20.glGetAttribLocation(mProgram, "aPosition");
|
||||||
|
GlUtils.checkGlError("glGetAttribLocation aPosition");
|
||||||
|
if (maPositionHandle == -1) {
|
||||||
|
throw new RuntimeException("Could not get attrib location for aPosition");
|
||||||
|
}
|
||||||
|
maTextureHandle = GLES20.glGetAttribLocation(mProgram, "aTextureCoord");
|
||||||
|
GlUtils.checkGlError("glGetAttribLocation aTextureCoord");
|
||||||
|
if (maTextureHandle == -1) {
|
||||||
|
throw new RuntimeException("Could not get attrib location for aTextureCoord");
|
||||||
|
}
|
||||||
|
muScaleHandle = GLES20.glGetUniformLocation(mProgram, "uScale");
|
||||||
|
GlUtils.checkGlError("glGetAttribLocation uScale");
|
||||||
|
if (muScaleHandle == -1) {
|
||||||
|
throw new RuntimeException("Could not get attrib location for uScale");
|
||||||
|
}
|
||||||
|
|
||||||
|
muMVPMatrixHandle = GLES20.glGetUniformLocation(mProgram, "uMVPMatrix");
|
||||||
|
GlUtils.checkGlError("glGetUniformLocation uMVPMatrix");
|
||||||
|
if (muMVPMatrixHandle == -1) {
|
||||||
|
throw new RuntimeException("Could not get attrib location for uMVPMatrix");
|
||||||
|
}
|
||||||
|
|
||||||
|
// GLES20.glEnable(GLES20.GL_DEPTH_TEST);
|
||||||
|
// GLES20.glDepthFunc(GLES20.GL_LEQUAL);
|
||||||
|
GLES20.glDisable(GLES20.GL_DEPTH_TEST);
|
||||||
|
|
||||||
|
GLES20.glCullFace(GLES20.GL_BACK);
|
||||||
|
GLES20.glFrontFace(GLES20.GL_CW);
|
||||||
|
GLES20.glEnable(GLES20.GL_CULL_FACE);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private final String mVertexShader = "precision highp float;\n" +
|
||||||
|
"uniform float uScale;\n" +
|
||||||
|
"uniform mat4 uMVPMatrix;\n" + "attribute vec4 aPosition;\n" +
|
||||||
|
"attribute vec2 aTextureCoord;\n" +
|
||||||
|
"varying vec2 vTextureCoord;\n" + "void main() {\n" +
|
||||||
|
" gl_Position = uMVPMatrix * aPosition;\n" +
|
||||||
|
" vTextureCoord = aTextureCoord * uScale;\n" +
|
||||||
|
"}\n";
|
||||||
|
|
||||||
|
private final String mFragmentShader = "precision highp float;\n" +
|
||||||
|
"uniform float uScale;\n" +
|
||||||
|
"varying vec2 vTextureCoord;\n" +
|
||||||
|
"uniform sampler2D sTexture;\n" +
|
||||||
|
"void main() {\n" +
|
||||||
|
" gl_FragColor = texture2D(sTexture, vTextureCoord); \n" +
|
||||||
|
"}\n";
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean processedTile() {
|
||||||
|
return processedTile;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// private void limitCache(long top, long bottom, long left, long right, byte zoom, int remove) {
|
||||||
|
// int cnt = 0;
|
||||||
|
// TileCacheKey[] keys = new TileCacheKey[remove];
|
||||||
|
//
|
||||||
|
// for (Entry<TileCacheKey, GLMapTile> e : mTiles.entrySet()) {
|
||||||
|
// GLMapTile t = e.getValue();
|
||||||
|
// if (t.zoomLevel == zoom && t.tileX >= left && t.tileX <= right &&
|
||||||
|
// t.tileY >= top && t.tileY <= bottom)
|
||||||
|
// continue;
|
||||||
|
//
|
||||||
|
// if (t.zoomLevel + 1 == zoom) {
|
||||||
|
// boolean found = false;
|
||||||
|
// for (int i = 0; i < 4; i++) {
|
||||||
|
// GLMapTile c = t.child[i];
|
||||||
|
// if (c != null && !c.hasTexture() && c.tileX >= left && c.tileX <= right &&
|
||||||
|
// c.tileY >= top && c.tileY <= bottom) {
|
||||||
|
// found = true;
|
||||||
|
// break;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// if (found)
|
||||||
|
// continue;
|
||||||
|
// }
|
||||||
|
// if (t.zoomLevel - 1 == zoom) {
|
||||||
|
// GLMapTile p = t.parent;
|
||||||
|
// if (p != null && !p.hasTexture() && p.tileX >= left && p.tileX <= right &&
|
||||||
|
// p.tileY >= top && p.tileY <= bottom) {
|
||||||
|
// continue;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// keys[cnt++] = e.getKey();
|
||||||
|
//
|
||||||
|
// if (cnt == remove)
|
||||||
|
// break;
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// for (TileCacheKey key : keys) {
|
||||||
|
// GLMapTile t = mTiles.remove(key);
|
||||||
|
// if (t == null)
|
||||||
|
// continue;
|
||||||
|
//
|
||||||
|
// for (int i = 0; i < 4; i++) {
|
||||||
|
// if (t.child[i] != null)
|
||||||
|
// t.child[i].parent = null;
|
||||||
|
// }
|
||||||
|
// if (t.parent != null) {
|
||||||
|
// for (int i = 0; i < 4; i++) {
|
||||||
|
// if (t.parent.child[i] == t)
|
||||||
|
// t.parent.child[i] = null;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// if (t.hasTexture()) {
|
||||||
|
// synchronized (mTextures) {
|
||||||
|
// mTextures.add(new Integer(t.getTexture()));
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
115
src/org/mapsforge/android/swrenderer/PointTextContainer.java
Normal file
115
src/org/mapsforge/android/swrenderer/PointTextContainer.java
Normal file
@@ -0,0 +1,115 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010, 2011, 2012 mapsforge.org
|
||||||
|
*
|
||||||
|
* 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.mapsforge.android.swrenderer;
|
||||||
|
|
||||||
|
import android.graphics.Paint;
|
||||||
|
import android.graphics.Rect;
|
||||||
|
|
||||||
|
class PointTextContainer {
|
||||||
|
final Rect boundary;
|
||||||
|
final Paint paintBack;
|
||||||
|
final Paint paintFront;
|
||||||
|
SymbolContainer symbol;
|
||||||
|
final String text;
|
||||||
|
float x;
|
||||||
|
float y;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new point container, that holds the x-y coordinates of a point, a text variable and one paint objects.
|
||||||
|
*
|
||||||
|
* @param text
|
||||||
|
* the text of the point.
|
||||||
|
* @param x
|
||||||
|
* the x coordinate of the point.
|
||||||
|
* @param y
|
||||||
|
* the y coordinate of the point.
|
||||||
|
* @param paintFront
|
||||||
|
* the paintFront for the point.
|
||||||
|
*/
|
||||||
|
PointTextContainer(String text, float x, float y, Paint paintFront) {
|
||||||
|
this.text = text;
|
||||||
|
this.x = x;
|
||||||
|
this.y = y;
|
||||||
|
this.paintFront = paintFront;
|
||||||
|
this.paintBack = null;
|
||||||
|
this.symbol = null;
|
||||||
|
|
||||||
|
this.boundary = new Rect();
|
||||||
|
paintFront.getTextBounds(text, 0, text.length(), this.boundary);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new point container, that holds the x-y coordinates of a point, a text variable and two paint objects.
|
||||||
|
*
|
||||||
|
* @param text
|
||||||
|
* the text of the point.
|
||||||
|
* @param x
|
||||||
|
* the x coordinate of the point.
|
||||||
|
* @param y
|
||||||
|
* the y coordinate of the point.
|
||||||
|
* @param paintFront
|
||||||
|
* the paintFront for the point.
|
||||||
|
* @param paintBack
|
||||||
|
* the paintBack for the point.
|
||||||
|
*/
|
||||||
|
PointTextContainer(String text, float x, float y, Paint paintFront, Paint paintBack) {
|
||||||
|
this.text = text;
|
||||||
|
this.x = x;
|
||||||
|
this.y = y;
|
||||||
|
this.paintFront = paintFront;
|
||||||
|
this.paintBack = paintBack;
|
||||||
|
this.symbol = null;
|
||||||
|
|
||||||
|
this.boundary = new Rect();
|
||||||
|
if (paintBack != null) {
|
||||||
|
paintBack.getTextBounds(text, 0, text.length(), this.boundary);
|
||||||
|
} else {
|
||||||
|
paintFront.getTextBounds(text, 0, text.length(), this.boundary);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new point container, that holds the x-y coordinates of a point, a text variable, two paint objects, and
|
||||||
|
* a reference on a symbol, if the text is connected with a POI.
|
||||||
|
*
|
||||||
|
* @param text
|
||||||
|
* the text of the point.
|
||||||
|
* @param x
|
||||||
|
* the x coordinate of the point.
|
||||||
|
* @param y
|
||||||
|
* the y coordinate of the point.
|
||||||
|
* @param paintFront
|
||||||
|
* the paintFront for the point.
|
||||||
|
* @param paintBack
|
||||||
|
* the paintBack for the point.
|
||||||
|
* @param symbol
|
||||||
|
* the connected Symbol.
|
||||||
|
*/
|
||||||
|
PointTextContainer(String text, float x, float y, Paint paintFront, Paint paintBack, SymbolContainer symbol) {
|
||||||
|
this.text = text;
|
||||||
|
this.x = x;
|
||||||
|
this.y = y;
|
||||||
|
this.paintFront = paintFront;
|
||||||
|
this.paintBack = paintBack;
|
||||||
|
this.symbol = symbol;
|
||||||
|
|
||||||
|
this.boundary = new Rect();
|
||||||
|
if (paintBack != null) {
|
||||||
|
paintBack.getTextBounds(text, 0, text.length(), this.boundary);
|
||||||
|
} else {
|
||||||
|
paintFront.getTextBounds(text, 0, text.length(), this.boundary);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user