- remove swrenderer

- rearchitect:
 now that MapView is a ViewGroup and MapRenderer is the GLSurfaceView.
- lock/unlock proxy tiles properly to not be removed from cache while in use
This commit is contained in:
Hannes Janetzek 2012-09-16 19:26:53 +02:00
parent caea9cd7c9
commit a1317a9de5
81 changed files with 5271 additions and 5408 deletions

View File

@ -8,7 +8,7 @@
<org.oscim.view.MapView <org.oscim.view.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"/>
<ToggleButton <ToggleButton
android:id="@+id/snapToLocationView" android:id="@+id/snapToLocationView"

View File

@ -6,7 +6,9 @@
<!-- <item>MAP_READER</item> --> <!-- <item>MAP_READER</item> -->
<!-- <item>POSTGIS_READER</item> --> <!-- <item>POSTGIS_READER</item> -->
<item>PBMAP_READER</item> <item>PBMAP_READER</item>
</string-array> <!-- <item>OSCIMAP_READER</item> -->
<item>TEST_READER</item>
</string-array>
<string name="preferences_map_database_default">PBMAP_READER</string> <string name="preferences_map_database_default">PBMAP_READER</string>

View File

@ -6,7 +6,9 @@
<!-- <item>Mapfile</item> --> <!-- <item>Mapfile</item> -->
<!-- <item>PostGIS</item> --> <!-- <item>PostGIS</item> -->
<item>OpenScienceMap</item> <item>OpenScienceMap</item>
</string-array> <!-- <item>OpenScienceMap2</item> -->
<item>Test</item>
</string-array>
<string-array name="preferences_scale_bar_unit_values"> <string-array name="preferences_scale_bar_unit_values">
<item>Imperial</item> <item>Imperial</item>
<item>Metric</item> <item>Metric</item>

View File

@ -12,10 +12,10 @@ import org.oscim.core.GeoPoint;
import org.oscim.core.MapPosition; import org.oscim.core.MapPosition;
import org.oscim.database.MapDatabases; import org.oscim.database.MapDatabases;
import org.oscim.theme.InternalRenderTheme; import org.oscim.theme.InternalRenderTheme;
import org.oscim.utils.AndroidUtils;
import org.oscim.view.DebugSettings; import org.oscim.view.DebugSettings;
import org.oscim.view.MapActivity; import org.oscim.view.MapActivity;
import org.oscim.view.MapView; import org.oscim.view.MapView;
import org.oscim.view.utils.AndroidUtils;
import android.annotation.TargetApi; import android.annotation.TargetApi;
import android.app.ActionBar; import android.app.ActionBar;
@ -82,6 +82,7 @@ public class TileMap extends MapActivity {
getMenuInflater().inflate(R.menu.options_menu, menu); getMenuInflater().inflate(R.menu.options_menu, menu);
else else
getMenuInflater().inflate(R.menu.options_menu_pre_honeycomb, menu); getMenuInflater().inflate(R.menu.options_menu_pre_honeycomb, menu);
mMenu = menu; mMenu = menu;
return true; return true;
@ -100,30 +101,22 @@ public class TileMap extends MapActivity {
case R.id.menu_rotation_enable: case R.id.menu_rotation_enable:
mMapView.enableRotation(true); mMapView.enableRotation(true);
toggleMenuRotation(mMenu, toggleMenuRotation();
mMapView.enableRotation,
mMapView.enableCompass);
return true; return true;
case R.id.menu_rotation_disable: case R.id.menu_rotation_disable:
mMapView.enableRotation(false); mMapView.enableRotation(false);
toggleMenuRotation(mMenu, toggleMenuRotation();
mMapView.enableRotation,
mMapView.enableCompass);
return true; return true;
case R.id.menu_compass_enable: case R.id.menu_compass_enable:
mMapView.enableCompass(true); mMapView.enableCompass(true);
toggleMenuRotation(mMenu, toggleMenuRotation();
mMapView.enableRotation,
mMapView.enableCompass);
return true; return true;
case R.id.menu_compass_disable: case R.id.menu_compass_disable:
mMapView.enableCompass(false); mMapView.enableCompass(false);
toggleMenuRotation(mMenu, toggleMenuRotation();
mMapView.enableRotation,
mMapView.enableCompass);
return true; return true;
case R.id.menu_position_my_location_enable: case R.id.menu_position_my_location_enable:
@ -187,16 +180,17 @@ public class TileMap extends MapActivity {
} }
} }
private static void toggleMenuRotation(Menu menu, boolean rotate, boolean compass) { private void toggleMenuRotation() {
toggleMenuItem(menu,
toggleMenuItem(mMenu,
R.id.menu_rotation_enable, R.id.menu_rotation_enable,
R.id.menu_rotation_disable, R.id.menu_rotation_disable,
!rotate); !mMapView.enableRotation);
toggleMenuItem(menu, toggleMenuItem(mMenu,
R.id.menu_compass_enable, R.id.menu_compass_enable,
R.id.menu_compass_disable, R.id.menu_compass_disable,
!compass); !mMapView.enableCompass);
} }
private static void toggleMenuItem(Menu menu, int id, int id2, boolean enable) { private static void toggleMenuItem(Menu menu, int id, int id2, boolean enable) {
@ -208,28 +202,17 @@ public class TileMap extends MapActivity {
@Override @Override
public boolean onPrepareOptionsMenu(Menu menu) { public boolean onPrepareOptionsMenu(Menu menu) {
menu.clear();
onCreateOptionsMenu(menu); if (!isPreHoneyComb()) {
menu.clear();
onCreateOptionsMenu(menu);
}
toggleMenuItem(menu, toggleMenuItem(menu,
R.id.menu_position_my_location_enable, R.id.menu_position_my_location_enable,
R.id.menu_position_my_location_disable, R.id.menu_position_my_location_disable,
!mLocation.isShowMyLocationEnabled()); !mLocation.isShowMyLocationEnabled());
// if (mLocation.isShowMyLocationEnabled()) {
// menu.findItem(R.id.menu_position_my_location_enable).setVisible(false);
// menu.findItem(R.id.menu_position_my_location_enable).setEnabled(false);
// menu.findItem(R.id.menu_position_my_location_disable).setVisible(true);
// menu.findItem(R.id.menu_position_my_location_disable).setEnabled(true);
// } else {
// menu.findItem(R.id.menu_position_my_location_enable).setVisible(true);
// menu.findItem(R.id.menu_position_my_location_enable).setEnabled(true);
// menu.findItem(R.id.menu_position_my_location_disable).setVisible(false);
// menu.findItem(R.id.menu_position_my_location_disable).setEnabled(false);
// }
menu.findItem(R.id.menu_render_theme).setEnabled(true);
if (mMapDatabase == MapDatabases.MAP_READER) { if (mMapDatabase == MapDatabases.MAP_READER) {
menu.findItem(R.id.menu_mapfile).setVisible(true); menu.findItem(R.id.menu_mapfile).setVisible(true);
menu.findItem(R.id.menu_position_map_center).setVisible(true); menu.findItem(R.id.menu_position_map_center).setVisible(true);
@ -238,15 +221,7 @@ public class TileMap extends MapActivity {
menu.findItem(R.id.menu_position_map_center).setVisible(false); menu.findItem(R.id.menu_position_map_center).setVisible(false);
} }
toggleMenuItem(menu, toggleMenuRotation();
R.id.menu_compass_enable,
R.id.menu_compass_disable,
!mMapView.enableCompass);
toggleMenuItem(mMenu,
R.id.menu_rotation_enable,
R.id.menu_rotation_disable,
!mMapView.enableRotation);
return super.onPrepareOptionsMenu(menu); return super.onPrepareOptionsMenu(menu);
} }
@ -257,13 +232,6 @@ public class TileMap extends MapActivity {
return mMapView.onTrackballEvent(event); return mMapView.onTrackballEvent(event);
} }
private void configureMapView() {
// configure the MapView and activate the zoomLevel buttons
mMapView.setClickable(true);
// mMapView.setBuiltInZoomControls(true);
mMapView.setFocusable(true);
}
private void startMapFilePicker() { private void startMapFilePicker() {
FilePicker.setFileDisplayFilter(FILE_FILTER_EXTENSION_MAP); FilePicker.setFileDisplayFilter(FILE_FILTER_EXTENSION_MAP);
FilePicker.setFileSelectFilter(new ValidMapFile()); FilePicker.setFileSelectFilter(new ValidMapFile());
@ -306,12 +274,16 @@ public class TileMap extends MapActivity {
} }
} }
static boolean isPreHoneyComb() {
return Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB;
}
@TargetApi(11) @TargetApi(11)
@Override @Override
protected void onCreate(Bundle savedInstanceState) { protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) { if (!isPreHoneyComb()) {
mSpinnerAdapter = ArrayAdapter.createFromResource(this, mSpinnerAdapter = ArrayAdapter.createFromResource(this,
R.array.view_sections, R.array.view_sections,
android.R.layout.simple_spinner_dropdown_item); android.R.layout.simple_spinner_dropdown_item);
@ -325,11 +297,12 @@ public class TileMap extends MapActivity {
// set up the layout views // set up the layout views
setContentView(R.layout.activity_tilemap); setContentView(R.layout.activity_tilemap);
// getActionBar().setDisplayOptions(ActionBar.NAVIGATION_MODE_TABS);
mMapView = (MapView) findViewById(R.id.mapView); mMapView = (MapView) findViewById(R.id.mapView);
configureMapView(); // configure the MapView and activate the zoomLevel buttons
mMapView.setClickable(true);
// mMapView.setBuiltInZoomControls(true);
mMapView.setFocusable(true);
mLocation = new LocationHandler(this); mLocation = new LocationHandler(this);
@ -605,7 +578,6 @@ public class TileMap extends MapActivity {
if (Build.VERSION.SDK_INT >= 11) { if (Build.VERSION.SDK_INT >= 11) {
VersionHelper.refreshActionBarMenu(this); VersionHelper.refreshActionBarMenu(this);
} }
} }
static class VersionHelper { static class VersionHelper {

View File

@ -14,7 +14,6 @@
*/ */
package org.oscim.core; package org.oscim.core;
/** /**
* A GeoPoint represents an immutable pair of latitude and longitude coordinates. * A GeoPoint represents an immutable pair of latitude and longitude coordinates.
*/ */
@ -119,10 +118,10 @@ public class GeoPoint implements Comparable<GeoPoint> {
@Override @Override
public String toString() { public String toString() {
StringBuilder stringBuilder = new StringBuilder(); StringBuilder stringBuilder = new StringBuilder();
stringBuilder.append("GeoPoint [latitudeE6="); stringBuilder.append("GeoPoint [lat=");
stringBuilder.append(this.latitudeE6); stringBuilder.append(this.getLatitude());
stringBuilder.append(", longitudeE6="); stringBuilder.append(", lon=");
stringBuilder.append(this.longitudeE6); stringBuilder.append(this.getLongitude());
stringBuilder.append("]"); stringBuilder.append("]");
return stringBuilder.toString(); return stringBuilder.toString();
} }

View File

@ -22,22 +22,22 @@ public class Tag {
/** /**
* The key of the house number OpenStreetMap tag. * The key of the house number OpenStreetMap tag.
*/ */
public static final String TAG_KEY_HOUSE_NUMBER = "addr:housenumber"; public static final String TAG_KEY_HOUSE_NUMBER = "addr:housenumber".intern();
/** /**
* The key of the name OpenStreetMap tag. * The key of the name OpenStreetMap tag.
*/ */
public static final String TAG_KEY_NAME = "name"; public static final String TAG_KEY_NAME = "name".intern();
/** /**
* The key of the reference OpenStreetMap tag. * The key of the reference OpenStreetMap tag.
*/ */
public static final String TAG_KEY_REF = "ref"; public static final String TAG_KEY_REF = "ref".intern();
/** /**
* The key of the elevation OpenStreetMap tag. * The key of the elevation OpenStreetMap tag.
*/ */
public static final String TAG_KEY_ELE = "ele"; public static final String TAG_KEY_ELE = "ele".intern();
/** /**
* The key of this tag. * The key of this tag.
@ -102,8 +102,8 @@ public class Tag {
this.value = (value == null ? null : value.intern()); this.value = (value == null ? null : value.intern());
} }
else { else {
this.key = (key == null ? null : key); this.key = key;
this.value = (value == null ? null : value); this.value = value;
} }
} }

View File

@ -16,7 +16,7 @@ package org.oscim.database;
import java.util.Map; import java.util.Map;
import org.oscim.view.mapgenerator.JobTile; import org.oscim.view.generator.JobTile;
/** /**
* *

View File

@ -26,14 +26,14 @@ public interface IMapDatabaseCallback {
* *
* @param layer * @param layer
* the layer of the node. * the layer of the node.
* @param tags
* the tags of the node.
* @param latitude * @param latitude
* the latitude of the node. * the latitude of the node.
* @param longitude * @param longitude
* the longitude of the node. * the longitude of the node.
* @param tags
* the tags of the node.
*/ */
void renderPointOfInterest(byte layer, float latitude, float longitude, Tag[] tags); void renderPointOfInterest(byte layer, Tag[] tags, float latitude, float longitude);
/** /**
* Renders water background for the current tile. * Renders water background for the current tile.
@ -51,12 +51,21 @@ public interface IMapDatabaseCallback {
* the geographical coordinates of the way nodes in the order longitude/latitude. * the geographical coordinates of the way nodes in the order longitude/latitude.
* @param wayLength * @param wayLength
* length of way data in wayNodes * length of way data in wayNodes
* @param changed * @param closed
* tags have changed since last call (just an optional hint) * way is closed (means need to add endpoint == startpoint)
*/ */
void renderWay(byte layer, Tag[] tags, float[] wayNodes, short[] wayLength, void renderWay(byte layer, Tag[] tags, float[] wayNodes, short[] wayLength,
boolean changed); boolean closed);
/**
* TBD: check if way will be rendered before decoding
*
* @param tags
* ...
* @param closed
* ...
* @return true if the way will be rendered (i.e. found match in RenderTheme)
*/
boolean checkWay(Tag[] tags, boolean closed); boolean checkWay(Tag[] tags, boolean closed);
} }

View File

@ -14,7 +14,6 @@
*/ */
package org.oscim.database; package org.oscim.database;
import android.util.AttributeSet; import android.util.AttributeSet;
/** /**
@ -66,6 +65,8 @@ public final class MapDatabaseFactory {
return new org.oscim.database.postgis.MapDatabase(); return new org.oscim.database.postgis.MapDatabase();
case PBMAP_READER: case PBMAP_READER:
return new org.oscim.database.pbmap.MapDatabase(); return new org.oscim.database.pbmap.MapDatabase();
case OSCIMAP_READER:
return new org.oscim.database.oscimap.MapDatabase();
} }

View File

@ -37,4 +37,8 @@ public enum MapDatabases {
* ... * ...
*/ */
PBMAP_READER, PBMAP_READER,
/**
* ...
*/
OSCIMAP_READER,
} }

View File

@ -20,8 +20,8 @@ import java.util.Map;
import java.util.logging.Level; import java.util.logging.Level;
import java.util.logging.Logger; import java.util.logging.Logger;
import org.oscim.core.LRUCache;
import org.oscim.database.mapfile.header.SubFileParameter; import org.oscim.database.mapfile.header.SubFileParameter;
import org.oscim.utils.LRUCache;
/** /**
* A cache for database index blocks with a fixed size and LRU policy. * A cache for database index blocks with a fixed size and LRU policy.

View File

@ -30,7 +30,7 @@ import org.oscim.database.QueryResult;
import org.oscim.database.mapfile.header.MapFileHeader; import org.oscim.database.mapfile.header.MapFileHeader;
import org.oscim.database.mapfile.header.MapFileInfo; import org.oscim.database.mapfile.header.MapFileInfo;
import org.oscim.database.mapfile.header.SubFileParameter; import org.oscim.database.mapfile.header.SubFileParameter;
import org.oscim.view.mapgenerator.JobTile; import org.oscim.view.generator.JobTile;
/** /**
* A class for reading binary map files. * A class for reading binary map files.
@ -641,7 +641,7 @@ public class MapDatabase implements IMapDatabase {
// Integer.toString(mReadBuffer.readSignedInt()))); // Integer.toString(mReadBuffer.readSignedInt())));
} }
mapDatabaseCallback.renderPointOfInterest(layer, latitude, longitude, tags); mapDatabaseCallback.renderPointOfInterest(layer, tags, latitude, longitude);
} }

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -62,7 +62,7 @@ import org.oscim.database.IMapDatabaseCallback;
import org.oscim.database.MapInfo; import org.oscim.database.MapInfo;
import org.oscim.database.OpenResult; import org.oscim.database.OpenResult;
import org.oscim.database.QueryResult; import org.oscim.database.QueryResult;
import org.oscim.view.mapgenerator.JobTile; import org.oscim.view.generator.JobTile;
import android.os.Environment; import android.os.Environment;
import android.os.SystemClock; import android.os.SystemClock;
@ -604,7 +604,7 @@ public class MapDatabase implements IMapDatabase {
lastY = lat + lastY; lastY = lat + lastY;
mMapGenerator.renderPointOfInterest(layer, mMapGenerator.renderPointOfInterest(layer,
lastY / scale, lastX / scale, tags); tags, lastY / scale, lastX / scale);
cnt += 2; cnt += 2;
} }
return cnt; return cnt;

View File

@ -580,7 +580,7 @@ public class Tags {
private static final String s_boutique = "boutique".intern(); private static final String s_boutique = "boutique".intern();
private static final String s_boat_storage = "boat_storage".intern(); private static final String s_boat_storage = "boat_storage".intern();
public final static Tag[] tags = { public static final Tag[] tags = {
new Tag(s_building, s_yes, true), new Tag(s_highway, s_residential, true), new Tag(s_building, s_yes, true), new Tag(s_highway, s_residential, true),
new Tag(s_highway, s_service, true), new Tag(s_waterway, s_stream, true), new Tag(s_highway, s_service, true), new Tag(s_waterway, s_stream, true),

View File

@ -33,7 +33,7 @@ import org.oscim.database.IMapDatabaseCallback;
import org.oscim.database.MapInfo; import org.oscim.database.MapInfo;
import org.oscim.database.OpenResult; import org.oscim.database.OpenResult;
import org.oscim.database.QueryResult; import org.oscim.database.QueryResult;
import org.oscim.view.mapgenerator.JobTile; import org.oscim.view.generator.JobTile;
import org.postgresql.PGConnection; import org.postgresql.PGConnection;
import android.util.Log; import android.util.Log;
@ -176,8 +176,8 @@ public class MapDatabase implements IMapDatabase {
Log.d(TAG, "no index: skip way"); Log.d(TAG, "no index: skip way");
continue; continue;
} else if (mIndexPos == 1) { } else if (mIndexPos == 1) {
mapDatabaseCallback.renderPointOfInterest((byte) 0, mCoords[1], mapDatabaseCallback.renderPointOfInterest((byte) 0, mTags,
mCoords[0], mTags); mCoords[1], mCoords[0]);
} else { } else {
short[] idx = new short[mIndexPos]; short[] idx = new short[mIndexPos];

View File

@ -17,7 +17,6 @@ package org.oscim.database.test;
import java.util.Map; import java.util.Map;
import org.oscim.core.BoundingBox; import org.oscim.core.BoundingBox;
import org.oscim.core.MercatorProjection;
import org.oscim.core.Tag; import org.oscim.core.Tag;
import org.oscim.core.Tile; import org.oscim.core.Tile;
import org.oscim.database.IMapDatabase; import org.oscim.database.IMapDatabase;
@ -25,7 +24,7 @@ import org.oscim.database.IMapDatabaseCallback;
import org.oscim.database.MapInfo; import org.oscim.database.MapInfo;
import org.oscim.database.OpenResult; import org.oscim.database.OpenResult;
import org.oscim.database.QueryResult; import org.oscim.database.QueryResult;
import org.oscim.view.mapgenerator.JobTile; import org.oscim.view.generator.JobTile;
/** /**
* *
@ -35,7 +34,7 @@ public class MapDatabase implements IMapDatabase {
private final static String PROJECTION = "Mercator"; private final static String PROJECTION = "Mercator";
private float[] mCoords = new float[20]; private float[] mCoords = new float[20];
private short[] mIndex = new short[2]; private short[] mIndex = new short[4];
// private Tag[] mTags = { new Tag("boundary", "administrative"), new Tag("admin_level", "2") }; // private Tag[] mTags = { new Tag("boundary", "administrative"), new Tag("admin_level", "2") };
private Tag[] mTags = { new Tag("natural", "water") }; private Tag[] mTags = { new Tag("natural", "water") };
private Tag[] mNameTags; private Tag[] mNameTags;
@ -46,64 +45,13 @@ public class MapDatabase implements IMapDatabase {
private boolean mOpenFile = false; private boolean mOpenFile = false;
// private static double radius = 6378137;
// private static double D2R = Math.PI / 180;
// private static double HALF_PI = Math.PI / 2;
@Override @Override
public QueryResult executeQuery(JobTile tile, IMapDatabaseCallback mapDatabaseCallback) { public QueryResult executeQuery(JobTile tile, IMapDatabaseCallback mapDatabaseCallback) {
long cx = tile.pixelX + (Tile.TILE_SIZE >> 1); float lat1 = -0.5f;
long cy = tile.pixelY + (Tile.TILE_SIZE >> 1); float lon1 = -0.5f;
// float lon1 = (float) MercatorProjection.pixelXToLongitude(cx - 100, tile.zoomLevel) * 1000000; float lat2 = Tile.TILE_SIZE - 0.5f;
// float lon2 = (float) MercatorProjection.pixelXToLongitude(cx + 100, tile.zoomLevel) * 1000000; float lon2 = Tile.TILE_SIZE - 0.5f;
// float lat1 = (float) MercatorProjection.pixelYToLatitude(cy - 100, tile.zoomLevel) * 1000000;
// float lat2 = (float) MercatorProjection.pixelYToLatitude(cy + 100, tile.zoomLevel) * 1000000;
float lon1 = (float) MercatorProjection.pixelXToLongitude(cx - 100,
tile.zoomLevel);
float lon2 = (float) MercatorProjection.pixelXToLongitude(cx + 100,
tile.zoomLevel);
float lat1 = (float) MercatorProjection
.pixelYToLatitude(cy - 100, tile.zoomLevel);
float lat2 = (float) MercatorProjection
.pixelYToLatitude(cy + 100, tile.zoomLevel);
// double lonRadians = (D2R * lon1);
// double latRadians = (D2R * lat1);
// spherical mercator projection
// lon1 = (float) (radius * lonRadians);
// lat1 = (float) (radius * Math.log(Math.tan(Math.PI * 0.25 + latRadians * 0.5)));
//
// lonRadians = (D2R * lon2);
// latRadians = (D2R * lat2);
//
// lon2 = (float) (radius * lonRadians);
// lat2 = (float) (radius * Math.log(Math.tan(Math.PI * 0.25 + latRadians * 0.5)));
//
// mCoords[0] = lon1;
// mCoords[1] = lat1;
//
// mCoords[2] = lon2;
// mCoords[3] = lat1;
//
// mCoords[4] = lon2;
// mCoords[5] = lat2;
//
// mCoords[6] = lon1;
// mCoords[7] = lat2;
//
// mCoords[8] = lon1;
// mCoords[9] = lat1;
//
// mIndex[0] = 10;
lon1 = (float) MercatorProjection.pixelXToLongitude(cx - 139, tile.zoomLevel) * 1000000;
lon2 = (float) MercatorProjection.pixelXToLongitude(cx + 139, tile.zoomLevel) * 1000000;
lat1 = (float) MercatorProjection.pixelYToLatitude(cy - 139, tile.zoomLevel) * 1000000;
lat2 = (float) MercatorProjection.pixelYToLatitude(cy + 139, tile.zoomLevel) * 1000000;
mCoords[0] = lon1; mCoords[0] = lon1;
mCoords[1] = lat1; mCoords[1] = lat1;
@ -120,12 +68,13 @@ public class MapDatabase implements IMapDatabase {
mCoords[8] = lon1; mCoords[8] = lon1;
mCoords[9] = lat1; mCoords[9] = lat1;
mIndex[0] = 10; mIndex[0] = 8;
mIndex[1] = 2;
lon1 = (float) MercatorProjection.pixelXToLongitude(cx - 119, tile.zoomLevel) * 1000000; lon1 = 40;
lon2 = (float) MercatorProjection.pixelXToLongitude(cx + 119, tile.zoomLevel) * 1000000; lon2 = Tile.TILE_SIZE - 40;
lat1 = (float) MercatorProjection.pixelYToLatitude(cy - 119, tile.zoomLevel) * 1000000; lat1 = 40;
lat2 = (float) MercatorProjection.pixelYToLatitude(cy + 119, tile.zoomLevel) * 1000000; lat2 = Tile.TILE_SIZE - 40;
mCoords[10] = lon1; mCoords[10] = lon1;
mCoords[11] = lat1; mCoords[11] = lat1;
@ -142,24 +91,26 @@ public class MapDatabase implements IMapDatabase {
mCoords[18] = lon1; mCoords[18] = lon1;
mCoords[19] = lat1; mCoords[19] = lat1;
mIndex[1] = 10; mIndex[2] = 8;
mIndex[3] = 2;
mapDatabaseCallback.renderWay((byte) 0, mTags, mCoords, mIndex, true); mapDatabaseCallback.renderWay((byte) 0, mTags, mCoords, mIndex, true);
lon1 = (float) MercatorProjection.pixelXToLongitude(cx, tile.zoomLevel) * 1000000; lon1 = Tile.TILE_SIZE / 2;
lat1 = (float) MercatorProjection.pixelXToLongitude(cx, tile.zoomLevel) * 1000000; lat1 = Tile.TILE_SIZE / 2;
mNameTags = new Tag[2]; mNameTags = new Tag[2];
mNameTags[0] = new Tag("place", "city"); mNameTags[0] = new Tag("place", "city");
mNameTags[1] = new Tag("name", "check one check two, YO!"); mNameTags[1] = new Tag("name", tile.toString());
mapDatabaseCallback.renderPointOfInterest((byte) 0, (int) lat1, (int) lon1, mapDatabaseCallback.renderPointOfInterest((byte) 0, mNameTags, (int) lat1,
mNameTags); (int) lon1);
return QueryResult.SUCCESS; return QueryResult.SUCCESS;
} }
@Override @Override
public String getMapProjection() { public String getMapProjection() {
return PROJECTION; return null; // PROJECTION;
} }
@Override @Override
@ -185,8 +136,6 @@ public class MapDatabase implements IMapDatabase {
@Override @Override
public void cancel() { public void cancel() {
// TODO Auto-generated method stub
} }
} }

View File

@ -1,143 +0,0 @@
/*
* 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.oscim.stuff;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Properties;
import org.oscim.core.MapPosition;
import org.oscim.view.MapView;
import android.os.AsyncTask;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
public class RegionLookup {
/* package */final static String TAG = RegionLookup.class.getName();
private Connection connection = null;
private PreparedStatement prepQuery = null;
private MapView mMapView;
private final Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
Log.d(TAG, "message: " + msg.what);
// switch (msg.what) {
// handle update
// .....
// }
}
};
private static final String QUERY = "" +
"SELECT * from __get_regions_around(?,?)";
public RegionLookup(MapView mapView) {
mMapView = mapView;
}
boolean connect() {
Connection conn = null;
String dburl = "jdbc:postgresql://city.informatik.uni-bremen.de:5432/gis";
Properties dbOpts = new Properties();
dbOpts.setProperty("user", "osm");
dbOpts.setProperty("password", "osm");
dbOpts.setProperty("socketTimeout", "50");
dbOpts.setProperty("tcpKeepAlive", "true");
try {
DriverManager.setLoginTimeout(20);
Log.d(TAG, "Creating JDBC connection...");
Class.forName("org.postgresql.Driver");
conn = DriverManager.getConnection(dburl, dbOpts);
connection = conn;
prepQuery = conn.prepareStatement(QUERY);
} catch (Exception e) {
Log.d(TAG, "Aborted due to error:" + e);
return false;
}
return true;
}
boolean updatePosition() {
if (connection == null) {
if (!connect())
return false;
}
ResultSet r;
MapPosition pos = mMapView.getMapPosition().getMapPosition();
try {
prepQuery.setDouble(1, pos.lat);
prepQuery.setDouble(2, pos.lon);
Log.d(TAG, "" + prepQuery.toString());
prepQuery.execute();
r = prepQuery.getResultSet();
} catch (SQLException e) {
e.printStackTrace();
connection = null;
return false;
}
String level, name, boundary;
double minx, miny, maxx, maxy;
try {
while (r != null && r.next()) {
level = r.getString(1);
boundary = r.getString(2);
name = r.getString(3);
minx = r.getDouble(4);
miny = r.getDouble(5);
maxx = r.getDouble(6);
maxy = r.getDouble(7);
Log.d(TAG, "got:" + level + " b:" + boundary + " n:" + name + " " + minx
+ " " + miny + " " + maxx + " " + maxy);
}
} catch (SQLException e) {
e.printStackTrace();
connection = null;
return false;
}
return true;
}
public void updateRegion() {
new AsyncTask<Object, Integer, Long>() {
@Override
protected Long doInBackground(Object... params) {
RegionLookup.this.updatePosition();
return null;
}
// @Override
// protected void onPostExecute(Long result) {
// Log.d(TAG, "got sth " + result);
// }
}.execute(null, null, null);
}
}

View File

@ -17,9 +17,9 @@ package org.oscim.theme;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import org.oscim.core.LRUCache;
import org.oscim.core.Tag; import org.oscim.core.Tag;
import org.oscim.theme.renderinstruction.RenderInstruction; import org.oscim.theme.renderinstruction.RenderInstruction;
import org.oscim.utils.LRUCache;
import org.xml.sax.Attributes; import org.xml.sax.Attributes;
import android.graphics.Color; import android.graphics.Color;

View File

@ -7,7 +7,7 @@
<style-pathtext name="road" k="name" font-size="16" fill="#101010" stroke="#ffffff" stroke-width="2.0" /> <style-pathtext name="road" k="name" font-size="16" fill="#101010" stroke="#ffffff" stroke-width="2.0" />
<style-pathtext name="major-road" k="name" font-style="bold" font-size="16" fill="#101010" stroke="#ffffff" stroke-width="2.0" /> <style-pathtext name="major-road" k="name" font-style="bold" font-size="16" fill="#101010" stroke="#ffffff" stroke-width="2.0" />
<style-area name="residential" fill="#f0f0ec" fade="10"/> <style-area name="residential" fill="#f0eee8" fade="10"/>
<style-area name="railway|industrial" fill="#f2eeef" fade="10"/> <style-area name="railway|industrial" fill="#f2eeef" fade="10"/>
<!-- "#f0fae7" mint green --> <!-- "#f0fae7" mint green -->
@ -66,7 +66,7 @@
<style-line name="water:outline" stroke="#a4bbcc" width="1.0" fixed="true" cap="butt" /> <style-line name="water:outline" stroke="#a4bbcc" width="1.0" fixed="true" cap="butt" />
<style-line name="water" stroke="#b4cbdc" width="1.0" cap="butt" /> <style-line name="water" stroke="#b4cbdc" width="1.0" cap="butt" />
<style-area name="water" fill="#b4cbdc" /> <style-area name="water" fill="#a3c9f3" />
<!-- no-go area boundary --> <!-- no-go area boundary -->
<style-line name="fence" stroke="#444444" width="1.2" fixed="true" cap="butt"/> <style-line name="fence" stroke="#444444" width="1.2" fixed="true" cap="butt"/>

View File

@ -12,7 +12,7 @@
* You should have received a copy of the GNU Lesser General Public License along with * 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/>. * this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
package org.oscim.view.utils; package org.oscim.utils;
import android.os.Build; import android.os.Build;
import android.os.Looper; import android.os.Looper;

File diff suppressed because it is too large Load Diff

View File

@ -12,7 +12,7 @@
* You should have received a copy of the GNU Lesser General Public License along with * 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/>. * this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
package org.oscim.view.utils; package org.oscim.utils;
/** /**
* *

View File

@ -1,4 +1,4 @@
package org.oscim.view.utils; package org.oscim.utils;
import javax.microedition.khronos.egl.EGL10; import javax.microedition.khronos.egl.EGL10;
import javax.microedition.khronos.egl.EGLConfig; import javax.microedition.khronos.egl.EGLConfig;

View File

@ -12,8 +12,9 @@
* You should have received a copy of the GNU Lesser General Public License along with * 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/>. * this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
package org.oscim.view.utils; package org.oscim.utils;
import static android.opengl.GLES20.glUniform4f;
import android.graphics.Bitmap; import android.graphics.Bitmap;
import android.opengl.GLES20; import android.opengl.GLES20;
import android.opengl.GLUtils; import android.opengl.GLUtils;
@ -142,4 +143,20 @@ public class GlUtils {
} }
return oom; return oom;
} }
public static void setBlendColors(int handle, float[] c1, float[] c2, float alpha) {
glUniform4f(handle,
c1[0] * (1 - alpha) + c2[0] * alpha,
c1[1] * (1 - alpha) + c2[1] * alpha,
c1[2] * (1 - alpha) + c2[2] * alpha, 1);
}
public static void setColor(int handle, float[] c, float alpha) {
if (alpha >= 1)
GLES20.glUniform4fv(handle, 1, c, 0);
else
glUniform4f(handle, c[0] * alpha, c[1] * alpha, c[2] * alpha, alpha);
}
} }

View File

@ -12,7 +12,7 @@
* You should have received a copy of the GNU Lesser General Public License along with * 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/>. * this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
package org.oscim.core; package org.oscim.utils;
import java.util.LinkedHashMap; import java.util.LinkedHashMap;
import java.util.Map; import java.util.Map;

View File

@ -12,7 +12,7 @@
* You should have received a copy of the GNU Lesser General Public License along with * 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/>. * this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
package org.oscim.view.mapgenerator; package org.oscim.utils;
/** /**
* An abstract base class for threads which support pausing and resuming. * An abstract base class for threads which support pausing and resuming.

View File

@ -30,7 +30,7 @@ public class Compass {
if (mMapView != null) { if (mMapView != null) {
mMapView.getMapPosition().setRotation(mAngle); mMapView.getMapPosition().setRotation(mAngle);
mMapView.redrawTiles(); mMapView.redrawMap();
} }
} }
} }
@ -56,7 +56,7 @@ public class Compass {
void enable() { void enable() {
mSensorManager.registerListener(mListener, mSensor, mSensorManager.registerListener(mListener, mSensor,
SensorManager.SENSOR_DELAY_GAME); SensorManager.SENSOR_DELAY_UI);
} }
void disable() { void disable() {

View File

@ -1,54 +0,0 @@
/*
* 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.oscim.view;
import org.oscim.theme.RenderTheme;
import org.oscim.view.mapgenerator.IMapGenerator;
import org.oscim.view.mapgenerator.JobTile;
import android.opengl.GLSurfaceView;
/**
*
*/
public interface IMapRenderer extends GLSurfaceView.Renderer {
/**
* @param tile
* Tile data ready for rendering
* @return true
*/
public boolean passTile(JobTile tile);
/**
* called by MapView on position and map changes
*
* @param clear
* recreate all tiles (i.e. on theme change)
*/
public void updateMap(boolean clear);
/**
* @return new MapGenerator Instance for this Renderer
*/
public IMapGenerator createMapGenerator();
/**
* @param t
* the theme
*/
public void setRenderTheme(RenderTheme t);
}

View File

@ -37,7 +37,7 @@ import android.content.SharedPreferences.Editor;
public abstract class MapActivity extends Activity { public abstract class MapActivity extends Activity {
private static final String KEY_LATITUDE = "latitude"; private static final String KEY_LATITUDE = "latitude";
private static final String KEY_LONGITUDE = "longitude"; private static final String KEY_LONGITUDE = "longitude";
private static final String KEY_MAP_FILE = "mapFile"; // private static final String KEY_MAP_FILE = "mapFile";
private static final String KEY_ZOOM_LEVEL = "zoomLevel"; private static final String KEY_ZOOM_LEVEL = "zoomLevel";
private static final String PREFERENCES_FILE = "MapActivity"; private static final String PREFERENCES_FILE = "MapActivity";
private static final String KEY_THEME = "Theme"; private static final String KEY_THEME = "Theme";

View File

@ -1,76 +0,0 @@
/*
* 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.oscim.view;
import android.util.AttributeSet;
/**
* A factory for the internal MapRenderer implementations.
*/
public final class MapRendererFactory {
private static final String MAP_RENDERER_ATTRIBUTE_NAME = "mapRenderer";
/**
* @param mapView
* ...
* @param attributeSet
* A collection of attributes which includes the desired MapRenderer.
* @return a new MapRenderer instance.
*/
public static IMapRenderer createMapRenderer(MapView mapView,
AttributeSet attributeSet) {
String mapRendererName = attributeSet.getAttributeValue(null,
MAP_RENDERER_ATTRIBUTE_NAME);
if (mapRendererName == null) {
return new org.oscim.view.glrenderer.MapRenderer(mapView);
}
MapRenderers mapRendererInternal = MapRenderers.valueOf(mapRendererName);
return MapRendererFactory.createMapRenderer(mapView, mapRendererInternal);
}
public static MapRenderers getMapRenderer(AttributeSet attributeSet) {
String mapRendererName = attributeSet.getAttributeValue(null,
MAP_RENDERER_ATTRIBUTE_NAME);
if (mapRendererName == null) {
return MapRenderers.GL_RENDERER;
}
return MapRenderers.valueOf(mapRendererName);
}
/**
* @param mapView
* ...
* @param mapRendererInternal
* the internal MapRenderer implementation.
* @return a new MapRenderer instance.
*/
public static IMapRenderer createMapRenderer(MapView mapView,
MapRenderers mapRendererInternal) {
switch (mapRendererInternal) {
case SW_RENDERER:
return new org.oscim.view.swrenderer.MapRenderer(mapView);
case GL_RENDERER:
return new org.oscim.view.glrenderer.MapRenderer(mapView);
}
throw new IllegalArgumentException("unknown enum value: " + mapRendererInternal);
}
private MapRendererFactory() {
throw new IllegalStateException();
}
}

View File

@ -30,30 +30,29 @@ import org.oscim.database.MapDatabaseFactory;
import org.oscim.database.MapDatabases; import org.oscim.database.MapDatabases;
import org.oscim.database.MapInfo; import org.oscim.database.MapInfo;
import org.oscim.database.OpenResult; import org.oscim.database.OpenResult;
import org.oscim.stuff.RegionLookup;
import org.oscim.theme.ExternalRenderTheme; import org.oscim.theme.ExternalRenderTheme;
import org.oscim.theme.InternalRenderTheme; import org.oscim.theme.InternalRenderTheme;
import org.oscim.theme.RenderTheme; import org.oscim.theme.RenderTheme;
import org.oscim.theme.RenderThemeHandler; import org.oscim.theme.RenderThemeHandler;
import org.oscim.theme.Theme; import org.oscim.theme.Theme;
import org.oscim.view.mapgenerator.IMapGenerator; import org.oscim.view.generator.JobQueue;
import org.oscim.view.mapgenerator.JobQueue; import org.oscim.view.generator.JobTile;
import org.oscim.view.mapgenerator.JobTile; import org.oscim.view.generator.MapWorker;
import org.oscim.view.mapgenerator.MapWorker; import org.oscim.view.renderer.MapGenerator;
import org.oscim.view.utils.GlConfigChooser; import org.oscim.view.renderer.MapRenderer;
import org.xml.sax.SAXException; import org.xml.sax.SAXException;
import android.content.Context; import android.content.Context;
import android.opengl.GLSurfaceView;
import android.util.AttributeSet; import android.util.AttributeSet;
import android.util.Log; import android.util.Log;
import android.view.MotionEvent; import android.view.MotionEvent;
import android.widget.FrameLayout;
/** /**
* A MapView shows a map on the display of the device. It handles all user input and touch gestures to move and zoom the * 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. * map.
*/ */
public class MapView extends GLSurfaceView { public class MapView extends FrameLayout {
final static String TAG = "MapView"; final static String TAG = "MapView";
@ -67,19 +66,23 @@ public class MapView extends GLSurfaceView {
public final static boolean debugFrameTime = false; public final static boolean debugFrameTime = false;
public final static boolean testRegionZoom = false;
RegionLookup mRegionLookup;
public boolean enableRotation = false; public boolean enableRotation = false;
public boolean enableCompass = false; public boolean enableCompass = false;
private final MapViewPosition mMapViewPosition; private final MapViewPosition mMapViewPosition;
private final MapZoomControls mMapZoomControls; private final MapZoomControls mMapZoomControls;
private final Projection mProjection;
private final TouchHandler mTouchEventHandler; private final TouchHandler mTouchEventHandler;
private final Compass mCompass; private final Compass mCompass;
private IMapDatabase mMapDatabase; private IMapDatabase mMapDatabase;
private MapDatabases mMapDatabaseType; private MapDatabases mMapDatabaseType;
private IMapRenderer mMapRenderer;
private MapRenderer mMapRenderer;
private JobQueue mJobQueue; private JobQueue mJobQueue;
private MapWorker mMapWorkers[]; private MapWorker mMapWorkers[];
private int mNumMapWorkers = 4; private int mNumMapWorkers = 4;
@ -94,7 +97,7 @@ public class MapView extends GLSurfaceView {
* if the context object is not an instance of {@link MapActivity} . * if the context object is not an instance of {@link MapActivity} .
*/ */
public MapView(Context context) { public MapView(Context context) {
this(context, null, MapRenderers.GL_RENDERER, MapDatabases.MAP_READER); this(context, null, MapDatabases.MAP_READER);
} }
/** /**
@ -106,15 +109,13 @@ public class MapView extends GLSurfaceView {
* if the context object is not an instance of {@link MapActivity} . * if the context object is not an instance of {@link MapActivity} .
*/ */
public MapView(Context context, AttributeSet attributeSet) { public MapView(Context context, AttributeSet attributeSet) {
this(context, attributeSet, this(context, attributeSet, MapDatabaseFactory.getMapDatabase(attributeSet));
MapRendererFactory.getMapRenderer(attributeSet),
MapDatabaseFactory.getMapDatabase(attributeSet));
} }
private boolean mDebugDatabase = false; private boolean mDebugDatabase = false;
private MapView(Context context, AttributeSet attributeSet, private MapView(Context context, AttributeSet attributeSet,
MapRenderers mapGeneratorType, MapDatabases mapDatabaseType) { MapDatabases mapDatabaseType) {
super(context, attributeSet); super(context, attributeSet);
@ -136,17 +137,13 @@ public class MapView extends GLSurfaceView {
mMapViewPosition = new MapViewPosition(this); mMapViewPosition = new MapViewPosition(this);
mMapZoomControls = new MapZoomControls(mapActivity, this);
mProjection = new MapViewProjection(this);
mTouchEventHandler = new TouchHandler(mapActivity, this); mTouchEventHandler = new TouchHandler(mapActivity, this);
mCompass = new Compass(mapActivity, this); mCompass = new Compass(mapActivity, this);
mJobQueue = new JobQueue(); mJobQueue = new JobQueue();
mMapRenderer = MapRendererFactory.createMapRenderer(this, mapGeneratorType); mMapRenderer = new MapRenderer(context, this);
mMapWorkers = new MapWorker[mNumMapWorkers]; mMapWorkers = new MapWorker[mNumMapWorkers];
@ -159,7 +156,7 @@ public class MapView extends GLSurfaceView {
mapDatabase = MapDatabaseFactory.createMapDatabase(mapDatabaseType); mapDatabase = MapDatabaseFactory.createMapDatabase(mapDatabaseType);
} }
IMapGenerator mapGenerator = mMapRenderer.createMapGenerator(); MapGenerator mapGenerator = new MapGenerator(this);
mapGenerator.setMapDatabase(mapDatabase); mapGenerator.setMapDatabase(mapDatabase);
if (i == 0) if (i == 0)
@ -180,22 +177,19 @@ public class MapView extends GLSurfaceView {
setMapCenter(getStartPosition()); setMapCenter(getStartPosition());
} }
setEGLConfigChooser(new GlConfigChooser()); LayoutParams params = new LayoutParams(
setEGLContextClientVersion(2); android.view.ViewGroup.LayoutParams.MATCH_PARENT,
android.view.ViewGroup.LayoutParams.MATCH_PARENT);
// setDebugFlags(DEBUG_CHECK_GL_ERROR | DEBUG_LOG_GL_CALLS); addView(mMapRenderer, params);
setRenderer(mMapRenderer); if (testRegionZoom)
mRegionLookup = new RegionLookup(this);
if (!debugFrameTime)
setRenderMode(GLSurfaceView.RENDERMODE_WHEN_DIRTY);
mRegionLookup = new RegionLookup(this);
mMapZoomControls = new MapZoomControls(mapActivity, this);
mMapZoomControls.setShowMapZoomControls(true);
} }
RegionLookup mRegionLookup;
/** /**
* @return the map database which is used for reading map files. * @return the map database which is used for reading map files.
*/ */
@ -212,6 +206,9 @@ public class MapView extends GLSurfaceView {
@Override @Override
public boolean onTouchEvent(MotionEvent motionEvent) { public boolean onTouchEvent(MotionEvent motionEvent) {
// mMapZoomControls.onMapViewTouchEvent(motionEvent.getAction()
// & MotionEvent.ACTION_MASK);
if (this.isClickable()) if (this.isClickable())
return mTouchEventHandler.handleMotionEvent(motionEvent); return mTouchEventHandler.handleMotionEvent(motionEvent);
@ -221,17 +218,21 @@ public class MapView extends GLSurfaceView {
/** /**
* Calculates all necessary tiles and adds jobs accordingly. * Calculates all necessary tiles and adds jobs accordingly.
*/ */
public void redrawTiles() { public void redrawMap() {
mMapRenderer.updateMap(false); mMapRenderer.updateMap(false);
} }
public void clearAndRedrawMap() {
mMapRenderer.updateMap(true);
}
/** /**
* @param debugSettings * @param debugSettings
* the new DebugSettings for this MapView. * the new DebugSettings for this MapView.
*/ */
public void setDebugSettings(DebugSettings debugSettings) { public void setDebugSettings(DebugSettings debugSettings) {
this.debugSettings = debugSettings; this.debugSettings = debugSettings;
mMapRenderer.updateMap(true); clearAndRedrawMap();
} }
/** /**
@ -262,7 +263,7 @@ public class MapView extends GLSurfaceView {
for (MapWorker mapWorker : mMapWorkers) { for (MapWorker mapWorker : mMapWorkers) {
IMapGenerator mapGenerator = mapWorker.getMapGenerator(); MapGenerator mapGenerator = mapWorker.getMapGenerator();
IMapDatabase mapDatabase = mapGenerator.getMapDatabase(); IMapDatabase mapDatabase = mapGenerator.getMapDatabase();
mapDatabase.close(); mapDatabase.close();
@ -276,7 +277,8 @@ public class MapView extends GLSurfaceView {
if (initialized) { if (initialized) {
mMapOptions = mapOptions; mMapOptions = mapOptions;
mMapRenderer.updateMap(true); clearAndRedrawMap();
Log.i(TAG, "MapDatabase ready"); Log.i(TAG, "MapDatabase ready");
return true; return true;
} }
@ -320,7 +322,7 @@ public class MapView extends GLSurfaceView {
if (mDebugDatabase) if (mDebugDatabase)
return; return;
IMapGenerator mapGenerator; MapGenerator mapGenerator;
Log.i(TAG, "setMapDatabase " + mapDatabaseType.name()); Log.i(TAG, "setMapDatabase " + mapDatabaseType.name());
@ -340,8 +342,6 @@ public class MapView extends GLSurfaceView {
mJobQueue.clear(); mJobQueue.clear();
// String mapFile = mMapFile;
// mMapFile = null;
setMapOptions(null); setMapOptions(null);
mapWorkersProceed(); mapWorkersProceed();
@ -369,7 +369,7 @@ public class MapView extends GLSurfaceView {
if (ret) { if (ret) {
mRenderTheme = internalRenderTheme.name(); mRenderTheme = internalRenderTheme.name();
} }
mMapRenderer.updateMap(true); clearAndRedrawMap();
return ret; return ret;
} }
@ -392,7 +392,7 @@ public class MapView extends GLSurfaceView {
if (ret) { if (ret) {
mRenderTheme = renderThemePath; mRenderTheme = renderThemePath;
} }
mMapRenderer.updateMap(true); clearAndRedrawMap();
} }
private boolean setRenderTheme(Theme theme) { private boolean setRenderTheme(Theme theme) {
@ -432,12 +432,18 @@ public class MapView extends GLSurfaceView {
mJobQueue.clear(); mJobQueue.clear();
mapWorkersPause(true); mapWorkersPause(true);
Log.d(TAG, "onSizeChanged" + width + " " + height);
super.onSizeChanged(width, height, oldWidth, oldHeight); super.onSizeChanged(width, height, oldWidth, oldHeight);
mapWorkersProceed(); mapWorkersProceed();
} }
@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);
}
void destroy() { void destroy() {
for (MapWorker mapWorker : mMapWorkers) { for (MapWorker mapWorker : mMapWorkers) {
mapWorker.pause(); mapWorker.pause();
@ -454,59 +460,26 @@ public class MapView extends GLSurfaceView {
} }
} }
@Override void onPause() {
public void onPause() {
super.onPause();
mapWorkersPause(false); mapWorkersPause(false);
if (this.enableCompass) if (this.enableCompass)
mCompass.disable(); mCompass.disable();
} }
@Override void onResume() {
public void onResume() {
super.onResume();
mapWorkersProceed(); mapWorkersProceed();
if (this.enableCompass) if (this.enableCompass)
mCompass.enable(); mCompass.enable();
} }
/**
* 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;
}
/** /**
* @return the maximum possible zoom level. * @return the maximum possible zoom level.
*/ */
byte getMaximumPossibleZoomLevel() { byte getMaximumPossibleZoomLevel() {
return (byte) 20; return (byte) MapViewPosition.MAX_ZOOMLEVEL;
// FIXME Math.min(mMapZoomControls.getZoomLevelMax(), // Math.min(mMapZoomControls.getZoomLevelMax(),
// mMapGenerator.getZoomLevelMax()); // mMapGenerator.getZoomLevelMax());
} }
@ -529,6 +502,9 @@ public class MapView extends GLSurfaceView {
} }
byte limitZoomLevel(byte zoom) { byte limitZoomLevel(byte zoom) {
if (mMapZoomControls == null)
return zoom;
return (byte) Math.max(Math.min(zoom, getMaximumPossibleZoomLevel()), return (byte) Math.max(Math.min(zoom, getMaximumPossibleZoomLevel()),
mMapZoomControls.getZoomLevelMin()); mMapZoomControls.getZoomLevelMin());
} }
@ -544,7 +520,7 @@ public class MapView extends GLSurfaceView {
+ " lat: " + mapPosition.lat + " lat: " + mapPosition.lat
+ " lon: " + mapPosition.lon); + " lon: " + mapPosition.lon);
mMapViewPosition.setMapCenter(mapPosition); mMapViewPosition.setMapCenter(mapPosition);
redrawTiles(); redrawMap();
} }
/** /**

View File

@ -19,7 +19,6 @@ import org.oscim.core.MapPosition;
import org.oscim.core.MercatorProjection; import org.oscim.core.MercatorProjection;
import android.util.FloatMath; import android.util.FloatMath;
import android.util.Log;
/** /**
* A MapPosition stores the latitude and longitude coordinate of a MapView together with its zoom level. * A MapPosition stores the latitude and longitude coordinate of a MapView together with its zoom level.
@ -27,7 +26,7 @@ import android.util.Log;
public class MapViewPosition { public class MapViewPosition {
private static float MAX_SCALE = 2.0f; private static float MAX_SCALE = 2.0f;
private static float MIN_SCALE = 1.0f; private static float MIN_SCALE = 1.0f;
private static int MAX_ZOOMLEVEL = 16; public static int MAX_ZOOMLEVEL = 16;
private double mLatitude; private double mLatitude;
private double mLongitude; private double mLongitude;
@ -102,6 +101,43 @@ public class MapViewPosition {
return true; return true;
} }
/**
* Get GeoPoint for a pixel on screen
*
* @param x
* ...
* @param y
* ...
* @return the GeoPoint
*/
public GeoPoint getOffsetPoint(float x, float y) {
double pixelX = MercatorProjection.longitudeToPixelX(mLongitude, mZoomLevel);
double pixelY = MercatorProjection.latitudeToPixelY(mLatitude, mZoomLevel);
double dx = ((mMapView.getWidth() >> 1) - x) / mScale;
double dy = ((mMapView.getHeight() >> 1) - y) / mScale;
if (mMapView.enableRotation || mMapView.enableCompass) {
double rad = Math.toRadians(mRotation);
double xx = dx * Math.cos(rad) + dy * -Math.sin(rad);
double yy = dx * Math.sin(rad) + dy * Math.cos(rad);
dx = pixelX - xx;
dy = pixelY - yy;
} else {
dx = pixelX - dx;
dy = pixelY - dy;
}
double latitude = MercatorProjection.pixelYToLatitude(dy, mZoomLevel);
latitude = MercatorProjection.limitLatitude(latitude);
double longitude = MercatorProjection.pixelXToLongitude(dx, mZoomLevel);
longitude = MercatorProjection.limitLongitude(longitude);
return new GeoPoint(latitude, longitude);
}
/** /**
* Moves this MapViewPosition by the given amount of pixels. * Moves this MapViewPosition by the given amount of pixels.
* *
@ -113,22 +149,21 @@ public class MapViewPosition {
public synchronized void moveMap(float mx, float my) { public synchronized void moveMap(float mx, float my) {
double pixelX = MercatorProjection.longitudeToPixelX(mLongitude, mZoomLevel); double pixelX = MercatorProjection.longitudeToPixelX(mLongitude, mZoomLevel);
double pixelY = MercatorProjection.latitudeToPixelY(mLatitude, mZoomLevel); double pixelY = MercatorProjection.latitudeToPixelY(mLatitude, mZoomLevel);
double dx, dy;
double dx = mx / mScale;
double dy = my / mScale;
if (mMapView.enableRotation || mMapView.enableCompass) { if (mMapView.enableRotation || mMapView.enableCompass) {
float rad = (float) Math.toRadians(mRotation); double rad = Math.toRadians(mRotation);
dx = mx / mScale; double x = dx * Math.cos(rad) + dy * -Math.sin(rad);
dy = my / mScale; double y = dx * Math.sin(rad) + dy * Math.cos(rad);
double x = dx * FloatMath.cos(rad) + dy * -FloatMath.sin(rad);
double y = dx * FloatMath.sin(rad) + dy * FloatMath.cos(rad);
dx = pixelX - x; dx = pixelX - x;
dy = pixelY - y; dy = pixelY - y;
} }
else { else {
dx = pixelX - mx / mScale; dx = pixelX - dx;
dy = pixelY - my / mScale; dy = pixelY - dy;
} }
mLatitude = MercatorProjection.pixelYToLatitude(dy, mZoomLevel); mLatitude = MercatorProjection.pixelYToLatitude(dy, mZoomLevel);
mLatitude = MercatorProjection.limitLatitude(mLatitude); mLatitude = MercatorProjection.limitLatitude(mLatitude);
@ -141,7 +176,7 @@ public class MapViewPosition {
public synchronized void rotateMap(float angle, float cx, float cy) { public synchronized void rotateMap(float angle, float cx, float cy) {
moveMap(cx, cy); moveMap(cx, cy);
Log.d("MapViewPosition", "rotate:" + angle + " " + (mRotation - angle)); // Log.d("MapViewPosition", "rotate:" + angle + " " + (mRotation - angle));
mRotation -= angle; mRotation -= angle;
} }
@ -168,6 +203,10 @@ public class MapViewPosition {
mScale = scale; mScale = scale;
} }
// synchronized void zoomBoundingBox(GeoPoint p1, GeoPoint p2) {
//
// }
/** /**
* @param scale * @param scale
* ... * ...

View File

@ -1,125 +0,0 @@
/*
* 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.oscim.view;
import org.oscim.core.GeoPoint;
import org.oscim.core.MapPosition;
import org.oscim.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
double pixelX = MercatorProjection.longitudeToPixelX(mapPosition);
double pixelY = MercatorProjection.latitudeToPixelY(mapPosition);
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
double pixelX = MercatorProjection.longitudeToPixelX(mapPosition);
double pixelY = MercatorProjection.latitudeToPixelY(mapPosition);
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;
}
}

View File

@ -14,7 +14,7 @@
*/ */
package org.oscim.view; package org.oscim.view;
import org.oscim.view.mapgenerator.IMapGenerator; import org.oscim.view.renderer.MapGenerator;
import android.content.Context; import android.content.Context;
import android.os.Handler; import android.os.Handler;
@ -23,6 +23,7 @@ import android.view.Gravity;
import android.view.MotionEvent; import android.view.MotionEvent;
import android.view.View; import android.view.View;
import android.view.ViewConfiguration; import android.view.ViewConfiguration;
import android.view.ViewGroup.LayoutParams;
import android.widget.ZoomControls; import android.widget.ZoomControls;
/** /**
@ -44,28 +45,35 @@ public class MapZoomControls {
} }
private static class ZoomInClickListener implements View.OnClickListener { private static class ZoomInClickListener implements View.OnClickListener {
private final MapView mMapView; private final MapZoomControls mMapZoomControls;
ZoomInClickListener(MapView mapView) { ZoomInClickListener(MapZoomControls mapZoomControls) {
mMapView = mapView; mMapZoomControls = mapZoomControls;
} }
@Override @Override
public void onClick(View view) { public void onClick(View view) {
mMapView.zoom((byte) 1); // if (MapView.testRegionZoom)
// mMapView.mRegionLookup.updateRegion(1, null);
// else
// MapZoomControls.this.zoom((byte) 1);
mMapZoomControls.zoom((byte) 1);
} }
} }
private static class ZoomOutClickListener implements View.OnClickListener { private static class ZoomOutClickListener implements View.OnClickListener {
private final MapView mMapView; private final MapZoomControls mMapZoomControls;
ZoomOutClickListener(MapView mapView) { ZoomOutClickListener(MapZoomControls mapZoomControls) {
mMapView = mapView; mMapZoomControls = mapZoomControls;
} }
@Override @Override
public void onClick(View view) { public void onClick(View view) {
mMapView.zoom((byte) -1); // if (MapView.testRegionZoom)
// mMapView.mRegionLookup.updateRegion(-1, null);
// else
mMapZoomControls.zoom((byte) -1);
} }
} }
@ -78,12 +86,12 @@ public class MapZoomControls {
/** /**
* Default maximum zoom level. * Default maximum zoom level.
*/ */
private static final byte DEFAULT_ZOOM_LEVEL_MAX = 22; private static final byte DEFAULT_ZOOM_LEVEL_MAX = 18;
/** /**
* Default minimum zoom level. * Default minimum zoom level.
*/ */
private static final byte DEFAULT_ZOOM_LEVEL_MIN = 0; private static final byte DEFAULT_ZOOM_LEVEL_MIN = 1;
/** /**
* Message code for the handler to hide the zoom controls. * Message code for the handler to hide the zoom controls.
@ -108,22 +116,53 @@ public class MapZoomControls {
private final Handler mZoomControlsHideHandler; private final Handler mZoomControlsHideHandler;
private byte mZoomLevelMax; private byte mZoomLevelMax;
private byte mZoomLevelMin; private byte mZoomLevelMin;
private MapView mMapView;
MapZoomControls(Context context, final MapView mapView) { MapZoomControls(Context context, final MapView mapView) {
mZoomControls = new ZoomControls(context); mZoomControls = new ZoomControls(context);
mShowMapZoomControls = true; mShowMapZoomControls = true;
mZoomLevelMax = DEFAULT_ZOOM_LEVEL_MAX; mZoomLevelMax = DEFAULT_ZOOM_LEVEL_MAX;
mZoomLevelMin = DEFAULT_ZOOM_LEVEL_MIN; mZoomLevelMin = DEFAULT_ZOOM_LEVEL_MIN;
mZoomControls.setVisibility(View.GONE); if (!MapView.testRegionZoom)
mZoomControls.setVisibility(View.GONE);
mZoomControlsGravity = DEFAULT_ZOOM_CONTROLS_GRAVITY; mZoomControlsGravity = DEFAULT_ZOOM_CONTROLS_GRAVITY;
mZoomControls.setOnZoomInClickListener(new ZoomInClickListener(mapView)); mZoomControls.setOnZoomInClickListener(new ZoomInClickListener(this));
mZoomControls.setOnZoomOutClickListener(new ZoomOutClickListener(mapView)); mZoomControls.setOnZoomOutClickListener(new ZoomOutClickListener(this));
mZoomControlsHideHandler = new ZoomControlsHideHandler(mZoomControls); mZoomControlsHideHandler = new ZoomControlsHideHandler(mZoomControls);
// int wrapContent = android.view.ViewGroup.LayoutParams.WRAP_CONTENT; int wrapContent = android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
// LayoutParams layoutParams = new LayoutParams(wrapContent, wrapContent); LayoutParams layoutParams = new LayoutParams(wrapContent, wrapContent);
// mapView.addView(zoomControls, layoutParams); mapView.addView(mZoomControls, layoutParams);
}
/**
* 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.
*/
boolean zoom(byte zoomLevelDiff) {
MapViewPosition mapViewPosition = mMapView.getMapViewPosition();
int z = mapViewPosition.getZoomLevel() + zoomLevelDiff;
if (zoomLevelDiff > 0) {
// check if zoom in is possible
if (z > mZoomLevelMax) {
return false;
}
} else if (zoomLevelDiff < 0) {
// check if zoom out is possible
if (z < getZoomLevelMin()) {
return false;
}
}
mapViewPosition.setZoomLevel((byte) z);
mMapView.redrawMap();
return true;
} }
/** /**
@ -156,11 +195,11 @@ public class MapZoomControls {
} }
/** /**
* @param showMapZoomControls * @param show
* true if the zoom controls should be visible, false otherwise. * true if the zoom controls should be visible, false otherwise.
*/ */
public void setShowMapZoomControls(boolean showMapZoomControls) { public void setShowMapZoomControls(boolean show) {
mShowMapZoomControls = false; mShowMapZoomControls = show;
} }
/** /**
@ -181,7 +220,7 @@ public class MapZoomControls {
/** /**
* Sets the maximum zoom level of the map. * Sets the maximum zoom level of the map.
* <p> * <p>
* The maximum possible zoom level of the MapView depends also on the current {@link IMapGenerator}. For example, * 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 * 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. * effect in this case.
* *

View File

@ -1,91 +0,0 @@
/*
* 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.oscim.view;
import org.oscim.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);
}

View File

@ -0,0 +1,266 @@
/*
* 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.oscim.view;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Properties;
import org.oscim.core.GeoPoint;
import org.oscim.core.MapPosition;
import org.oscim.core.MercatorProjection;
import android.os.AsyncTask;
import android.util.FloatMath;
import android.util.Log;
import android.widget.Toast;
public class RegionLookup {
final static String TAG = RegionLookup.class.getName();
class BBox {
String level, name, boundary;
GeoPoint min, max;
float area;
}
private Connection connection = null;
private PreparedStatement prepQuery = null;
/* package */MapView mMapView;
/* pacakge */BBox mSelected;
// __get_regions_around(lat double precision, lon double precision)
// returns table (level text, boundary text, name text, xmin double precision, ymin double precision, xmax double
// precision, ymax double precision)
// language sql as
// $$
// select admin_level, boundary, name, xmin(box), ymin(box), xmax(box), ymax(box) from
// .. (select distinct on (box) * from
// .... (select *, st_transform(st_envelope(way),4326) box
// ...... from planet_polygon, st_transform(st_setsrid(st_makepoint($2,$1),4326),900913) point
// ...... where (boundary is not null) and st_contains(way, point)
// .... )p
// .. )p order by st_area(box)
// $$;
private static final String QUERY = "SELECT * from __get_regions_around(?,?)";
public RegionLookup(MapView mapView) {
mMapView = mapView;
}
boolean connect() {
Connection conn = null;
String dburl = "jdbc:postgresql://city.informatik.uni-bremen.de:5432/gis";
Properties dbOpts = new Properties();
dbOpts.setProperty("user", "osm");
dbOpts.setProperty("password", "osm");
dbOpts.setProperty("socketTimeout", "50");
dbOpts.setProperty("tcpKeepAlive", "true");
try {
DriverManager.setLoginTimeout(20);
Log.d(TAG, "Creating JDBC connection...");
Class.forName("org.postgresql.Driver");
conn = DriverManager.getConnection(dburl, dbOpts);
connection = conn;
prepQuery = conn.prepareStatement(QUERY);
} catch (Exception e) {
Log.d(TAG, "Aborted due to error:" + e);
return false;
}
return true;
}
boolean updatePosition() {
if (connection == null) {
if (!connect())
return false;
}
ResultSet r;
MapPosition pos = mMapView.getMapPosition().getMapPosition();
try {
if (mPos == null) {
prepQuery.setDouble(1, pos.lat);
prepQuery.setDouble(2, pos.lon);
} else {
prepQuery.setDouble(1, mPos.getLatitude());
prepQuery.setDouble(2, mPos.getLongitude());
}
Log.d(TAG, prepQuery.toString());
prepQuery.execute();
r = prepQuery.getResultSet();
} catch (SQLException e) {
e.printStackTrace();
connection = null;
return false;
}
ArrayList<BBox> boxes = new ArrayList<BBox>(10);
try {
while (r != null && r.next()) {
BBox bbox = new BBox();
bbox.level = r.getString(1);
bbox.boundary = r.getString(2);
bbox.name = r.getString(3);
bbox.min = new GeoPoint(r.getDouble(5), r.getDouble(4));
bbox.max = new GeoPoint(r.getDouble(7), r.getDouble(6));
bbox.area = (float) Math.abs((bbox.max.getLatitude()
- bbox.min.getLatitude())
* (bbox.max.getLongitude()
- bbox.min.getLongitude()));
Log.d(TAG, "got:" + bbox.area
+ " " + bbox.level + " b:" + bbox.boundary +
" n:" + bbox.name + " " + bbox.min + " " + bbox.max);
boxes.add(bbox);
}
} catch (SQLException e) {
e.printStackTrace();
connection = null;
return false;
}
double w = (mMapView.getWidth() >> 1) / pos.scale;
double h = (mMapView.getHeight() >> 1) / pos.scale;
float minx = (float) MercatorProjection
.pixelXToLongitude(pos.x - w, pos.zoomLevel);
float maxx = (float) MercatorProjection
.pixelXToLongitude(pos.x + w, pos.zoomLevel);
float miny = (float) MercatorProjection
.pixelYToLatitude(pos.y - h, pos.zoomLevel);
float maxy = (float) MercatorProjection
.pixelYToLatitude(pos.y + h, pos.zoomLevel);
float area = Math.abs((maxx - minx) * (miny - maxy));
Log.d(TAG, " BBOX " + area + " " + minx + " "
+ miny + " " + maxx + " " + maxy);
w = mMapView.getWidth();
h = mMapView.getHeight();
mSelected = null;
if (mDirection < 0) {
// get the next larger bbox, union with current and set view region to it.
for (int i = 0, n = boxes.size(); i < n; i++) {
BBox bbox = boxes.get(i);
if (bbox.area > area || i == n - 1) {
mSelected = bbox;
break;
}
}
} else {
for (int i = boxes.size() - 1; i >= 0; i--) {
BBox bbox = boxes.get(i);
// if (bbox.area < area) {
//
// double clat = bbox.min.getLatitude()
// + (bbox.max.getLatitude() - bbox.min.getLatitude()) / 2;
double clon = Math.abs(bbox.max.getLongitude()
- bbox.min.getLongitude());
float zoom = (float) (-Math.log(4) * Math.log(clon / 360) + 0.25);
// float scale = 1 + (zoom - FloatMath.floor(zoom));
// MapPosition mapPos = new MapPosition(clat,
// bbox.min.getLongitude() + clon / 2,
// (byte) zoom, 1 + (zoom - FloatMath.floor(zoom)), 0);
mSelected = bbox;
Log.d(TAG, "jump to: " + bbox.name + " " +
-Math.log(4) * Math.log(clon / 360) + " " + (byte) zoom);
if ((byte) zoom > pos.zoomLevel) {
break;
}
}
}
if (mSelected != null) {
BBox bbox = mSelected;
double clat = bbox.min.getLatitude()
+ (bbox.max.getLatitude() - bbox.min.getLatitude()) / 2;
double clon = Math.abs(bbox.max.getLongitude() - bbox.min.getLongitude());
Log.d(TAG, "jump to: " + bbox.name + " " +
-Math.log(4) * Math.log(clon / 360));
float zoom = (float) (-Math.log(4) * Math.log(clon / 360) + 0.25);
MapPosition mapPos = new MapPosition(clat,
bbox.min.getLongitude() + clon / 2,
(byte) zoom, 1 + (zoom - FloatMath.floor(zoom)), 0);
mMapView.setMapCenter(mapPos);
}
return true;
}
private int mDirection;
private GeoPoint mPos;
public synchronized void updateRegion(int direction, GeoPoint pos) {
mDirection = direction;
mPos = pos;
new AsyncTask<Object, Integer, Long>() {
@Override
protected Long doInBackground(Object... params) {
RegionLookup.this.updatePosition();
return null;
}
@Override
protected void onPostExecute(Long result) {
// Log.d(TAG, "got sth " + result);
if (mSelected != null) {
Toast toast = Toast.makeText(mMapView.getContext(), mSelected.name,
Toast.LENGTH_SHORT);
// toast.setDuration(1000);
toast.show();
}
}
}.execute(null, null, null);
mSelected = null;
}
// private final Handler mHandler = new Handler() {
// @Override
// public void handleMessage(Message msg) {
// Log.d(TAG, "message: " + msg.what);
// // switch (msg.what) {
// // handle update
// // .....
// // }
// }
// };
}

View File

@ -29,19 +29,22 @@ import android.view.animation.DecelerateInterpolator;
import android.widget.Scroller; import android.widget.Scroller;
/** /**
* Implementation for multi-touch capable devices. * Implementation for multi-touch capable devices. TODO write a AnimationTimer instead of using CountDownTimer
*/ */
public class TouchHandler { public class TouchHandler {
private static final int INVALID_POINTER_ID = -1; private static final int INVALID_POINTER_ID = -1;
/* package */final MapView mMapView; /* package */final MapView mMapView;
/* package */final MapViewPosition mMapPosition; /* package */final MapViewPosition mMapPosition;
/* package */final DecelerateInterpolator mInterpolator = new DecelerateInterpolator();
/* package */boolean mBeginScale;
/* package */float mSumScale;
private final float mMapMoveDelta; private final float mMapMoveDelta;
private boolean mMoveStart; private boolean mMoveStart;
private boolean mRotationStart; private boolean mBeginRotate;
private float mPosX; /* package */float mPosX;
private float mPosY; /* package */float mPosY;
private double mAngle; private double mAngle;
private int mActivePointerId; private int mActivePointerId;
@ -78,8 +81,9 @@ public class TouchHandler {
private boolean onActionDown(MotionEvent event) { private boolean onActionDown(MotionEvent event) {
mPosX = event.getX(); mPosX = event.getX();
mPosY = event.getY(); mPosY = event.getY();
mMoveStart = false; mMoveStart = false;
mRotationStart = false; mBeginRotate = false;
// save the ID of the pointer // save the ID of the pointer
mActivePointerId = event.getPointerId(0); mActivePointerId = event.getPointerId(0);
// Log.d("...", "set active pointer" + mActivePointerId); // Log.d("...", "set active pointer" + mActivePointerId);
@ -126,28 +130,27 @@ public class TouchHandler {
double dy = y1 - y2; double dy = y1 - y2;
double rad = Math.atan2(dy, dx); double rad = Math.atan2(dy, dx);
// focus point relative to center
double cx = (mMapView.getWidth() >> 1) - (x1 + x2) / 2;
double cy = (mMapView.getHeight() >> 1) - (y1 + y2) / 2;
double r = rad - mAngle; double r = rad - mAngle;
double rsin = Math.sin(r);
double rcos = Math.cos(r);
float x = (float) (cx * rcos + cy * -rsin - cx);
float y = (float) (cx * rsin + cy * rcos - cy);
// Log.d("...", "move " + x + " " + y + " " + cx + " " + cy); // Log.d("...", "move " + x + " " + y + " " + cx + " " + cy);
if (!mRotationStart) { if (!mBeginRotate && !mBeginScale) {
if (Math.abs(rad - mAngle) > 0.001) if (r > 0.02 || r < -0.02)
mRotationStart = true; mBeginRotate = true;
} } else if (mBeginRotate) {
else { double rsin = Math.sin(r);
double rcos = Math.cos(r);
// focus point relative to center
double cx = (mMapView.getWidth() >> 1) - (x1 + x2) / 2;
double cy = (mMapView.getHeight() >> 1) - (y1 + y2) / 2;
float x = (float) (cx * rcos + cy * -rsin - cx);
float y = (float) (cx * rsin + cy * rcos - cy);
mMapPosition.rotateMap((float) Math.toDegrees(rad - mAngle), x, y); mMapPosition.rotateMap((float) Math.toDegrees(rad - mAngle), x, y);
mAngle = rad; mAngle = rad;
mMapView.redrawTiles(); mMapView.redrawMap();
} }
} }
} }
@ -160,7 +163,7 @@ public class TouchHandler {
} }
mMapPosition.moveMap(moveX, moveY); mMapPosition.moveMap(moveX, moveY);
mMapView.redrawTiles(); mMapView.redrawMap();
return true; return true;
} }
@ -182,7 +185,8 @@ public class TouchHandler {
private boolean onActionPointerUp(MotionEvent motionEvent) { private boolean onActionPointerUp(MotionEvent motionEvent) {
// extract the index of the pointer that left the touch sensor // 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; int masked = (motionEvent.getAction() & MotionEvent.ACTION_POINTER_INDEX_MASK);
int pointerIndex = masked >> MotionEvent.ACTION_POINTER_INDEX_SHIFT;
if (motionEvent.getPointerId(pointerIndex) == mActivePointerId) { if (motionEvent.getPointerId(pointerIndex) == mActivePointerId) {
// the active pointer has gone up, choose a new one // the active pointer has gone up, choose a new one
@ -251,7 +255,7 @@ public class TouchHandler {
class MapGestureDetector extends SimpleOnGestureListener { class MapGestureDetector extends SimpleOnGestureListener {
private Scroller mScroller; private Scroller mScroller;
private float mPrevX, mPrevY, mPrevScale; private float mScrollX, mScrollY, mPrevScale;
private CountDownTimer mTimer = null; private CountDownTimer mTimer = null;
private boolean fling = false; private boolean fling = false;
@ -282,14 +286,14 @@ public class TouchHandler {
} }
mScroller.computeScrollOffset(); mScroller.computeScrollOffset();
float moveX = mScroller.getCurrX() - mPrevX; float moveX = mScroller.getCurrX() - mScrollX;
float moveY = mScroller.getCurrY() - mPrevY; float moveY = mScroller.getCurrY() - mScrollY;
if (moveX >= 1 || moveY >= 1 || moveX <= -1 || moveY <= -1) { if (moveX >= 1 || moveY >= 1 || moveX <= -1 || moveY <= -1) {
mMapPosition.moveMap(moveX, moveY); mMapPosition.moveMap(moveX, moveY);
mMapView.redrawTiles(); mMapView.redrawMap();
mPrevX = mScroller.getCurrX(); mScrollX = mScroller.getCurrX();
mPrevY = mScroller.getCurrY(); mScrollY = mScroller.getCurrY();
} }
return true; return true;
} }
@ -299,8 +303,8 @@ public class TouchHandler {
float velocityY) { float velocityY) {
int w = Tile.TILE_SIZE * 20; int w = Tile.TILE_SIZE * 20;
int h = Tile.TILE_SIZE * 20; int h = Tile.TILE_SIZE * 20;
mPrevX = 0; mScrollX = 0;
mPrevY = 0; mScrollY = 0;
if (mTimer != null) { if (mTimer != null) {
mTimer.cancel(); mTimer.cancel();
@ -326,61 +330,12 @@ public class TouchHandler {
return true; return true;
} }
private DecelerateInterpolator mBounce = new DecelerateInterpolator();
private boolean mZooutOut = true;
@Override @Override
public void onLongPress(MotionEvent e) { public void onLongPress(MotionEvent e) {
Log.d("mapsforge", "long press"); if (MapView.testRegionZoom) {
Log.d("mapsforge", "long press");
mMapView.mRegionLookup.updateRegion(); mMapView.mRegionLookup.updateRegion(-1, null);
// mMapView.zoom((byte) -1);
// mPrevScale = 0;
// mTimer = new CountDownTimer((int) mScaleDuration, 30) {
// @Override
// public void onTick(long tick) {
// scale2(tick);
// }
//
// @Override
// public void onFinish() {
// scale2(0);
//
// }
// }.start();
}
boolean scale2(long tick) {
if (mPrevScale >= 1) {
mTimer = null;
return false;
} }
float adv = (mScaleDuration - tick) / mScaleDuration;
adv = mBounce.getInterpolation(adv);
float scale = adv - mPrevScale;
mPrevScale += scale;
if (mZooutOut) {
mMapPosition.scaleMap(1 - scale, 0, 0);
}
// } else {
// mMapPosition.scaleMap(1 + scale, mFocusX, mFocusY);
// }
mMapView.redrawTiles();
if (tick == 0)
mTimer = null;
return true;
} }
private final float mScaleDuration = 300; private final float mScaleDuration = 300;
@ -391,7 +346,7 @@ public class TouchHandler {
if (mPrevScale >= 1) if (mPrevScale >= 1)
return false; return false;
float adv = (mScaleDuration - tick) / mScaleDuration; float adv = (mScaleDuration - tick) / mScaleDuration;
adv = mBounce.getInterpolation(adv); adv = mInterpolator.getInterpolation(adv);
float scale = adv - mPrevScale; float scale = adv - mPrevScale;
mPrevScale += scale; mPrevScale += scale;
@ -399,8 +354,8 @@ public class TouchHandler {
adv += 1; adv += 1;
if (scale > 1) { if (scale > 1) {
mMapPosition.scaleMap(scale, mPrevX / adv, mPrevY / adv); mMapPosition.scaleMap(scale, mScrollX / adv, mScrollY / adv);
mMapView.redrawTiles(); mMapView.redrawMap();
} }
return true; return true;
@ -408,24 +363,28 @@ public class TouchHandler {
@Override @Override
public boolean onDoubleTap(MotionEvent e) { public boolean onDoubleTap(MotionEvent e) {
// Log.d("mapsforge", "double tap"); if (MapView.testRegionZoom) {
Log.d("mapsforge", "double tap");
mPrevX = (e.getX(0) - (mMapView.getWidth() >> 1)) * 2f; mMapView.mRegionLookup.updateRegion(1,
mPrevY = (e.getY(0) - (mMapView.getHeight() >> 1)) * 2f; mMapPosition.getOffsetPoint(mPosX, mPosY));
mPrevScale = 0; } else {
mScrollX = (e.getX(0) - (mMapView.getWidth() >> 1)) * 2f;
mScrollY = (e.getY(0) - (mMapView.getHeight() >> 1)) * 2f;
mPrevScale = 0;
mTimer = new CountDownTimer((int) mScaleDuration, 30) { mTimer = new CountDownTimer((int) mScaleDuration, 30) {
@Override @Override
public void onTick(long tick) { public void onTick(long tick) {
scale(tick); scale(tick);
} }
@Override
public void onFinish() {
scale(0);
}
}.start();
@Override
public void onFinish() {
scale(0);
}
}.start();
}
return true; return true;
} }
} }
@ -435,39 +394,35 @@ public class TouchHandler {
private float mCenterY; private float mCenterY;
private float mFocusX; private float mFocusX;
private float mFocusY; private float mFocusY;
private float mScale; private long mTimeStart;
private boolean mBeginScale; private long mTimeEnd;
@Override @Override
public boolean onScale(ScaleGestureDetector gd) { public boolean onScale(ScaleGestureDetector gd) {
mScale = gd.getScaleFactor(); float scale = gd.getScaleFactor();
mFocusX = gd.getFocusX() - mCenterX; mFocusX = gd.getFocusX() - mCenterX;
mFocusY = gd.getFocusY() - mCenterY; mFocusY = gd.getFocusY() - mCenterY;
mSumScale *= mScale; mSumScale *= scale;
mTimeEnd = SystemClock.elapsedRealtime(); mTimeEnd = SystemClock.elapsedRealtime();
if (!mBeginScale) { if (!mBeginScale) {
if (mTimeEnd - mTimeStart > 100) { if (mTimeEnd - mTimeStart > 150 || mSumScale > 1.1 || mSumScale < 0.9) {
mBeginScale = true; mBeginScale = true;
mScale = mSumScale; scale = mSumScale;
} }
else else
return true; return true;
} }
mMapPosition.scaleMap(mScale, mFocusX, mFocusY); mMapPosition.scaleMap(scale, mFocusX, mFocusY);
mMapView.redrawTiles(); mMapView.redrawMap();
return true; return true;
} }
private long mTimeStart;
private long mTimeEnd;
private float mSumScale;
@Override @Override
public boolean onScaleBegin(ScaleGestureDetector gd) { public boolean onScaleBegin(ScaleGestureDetector gd) {
mTimeEnd = mTimeStart = SystemClock.elapsedRealtime(); mTimeEnd = mTimeStart = SystemClock.elapsedRealtime();
@ -475,7 +430,6 @@ public class TouchHandler {
mBeginScale = false; mBeginScale = false;
mCenterX = mMapView.getWidth() >> 1; mCenterX = mMapView.getWidth() >> 1;
mCenterY = mMapView.getHeight() >> 1; mCenterY = mMapView.getHeight() >> 1;
mScale = 1;
if (mTimer != null) { if (mTimer != null) {
mTimer.cancel(); mTimer.cancel();
@ -508,9 +462,9 @@ public class TouchHandler {
} }
}.start(); }.start();
} }
mBeginScale = false;
} }
private DecelerateInterpolator mBounce = new DecelerateInterpolator();
private float mPrevScale; private float mPrevScale;
private CountDownTimer mTimer; private CountDownTimer mTimer;
boolean mZooutOut; boolean mZooutOut;
@ -524,7 +478,7 @@ public class TouchHandler {
} }
float adv = (mScaleDuration - tick) / mScaleDuration; float adv = (mScaleDuration - tick) / mScaleDuration;
adv = mBounce.getInterpolation(adv); adv = mInterpolator.getInterpolation(adv);
float scale = adv - mPrevScale; float scale = adv - mPrevScale;
mPrevScale += scale; mPrevScale += scale;
@ -535,7 +489,7 @@ public class TouchHandler {
mMapPosition.scaleMap(1 + scale, mFocusX, mFocusY); mMapPosition.scaleMap(1 + scale, mFocusX, mFocusY);
} }
mMapView.redrawTiles(); mMapView.redrawMap();
if (tick == 0) if (tick == 0)
mTimer = null; mTimer = null;

View File

@ -12,7 +12,7 @@
* You should have received a copy of the GNU Lesser General Public License along with * 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/>. * this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
package org.oscim.view.mapgenerator; package org.oscim.view.generator;
//import static org.oscim.view.mapgenerator.JobTile.LOADING; //import static org.oscim.view.mapgenerator.JobTile.LOADING;

View File

@ -12,7 +12,7 @@
* You should have received a copy of the GNU Lesser General Public License along with * 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/>. * this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
package org.oscim.view.mapgenerator; package org.oscim.view.generator;
import org.oscim.core.Tile; import org.oscim.core.Tile;

View File

@ -12,9 +12,11 @@
* You should have received a copy of the GNU Lesser General Public License along with * 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/>. * this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
package org.oscim.view.mapgenerator; package org.oscim.view.generator;
import org.oscim.view.IMapRenderer; import org.oscim.utils.PausableThread;
import org.oscim.view.renderer.MapGenerator;
import org.oscim.view.renderer.MapRenderer;
/** /**
* A MapWorker uses a {@link IMapGenerator} to generate map tiles. It runs in a separate thread to avoid blocking the UI * A MapWorker uses a {@link IMapGenerator} to generate map tiles. It runs in a separate thread to avoid blocking the UI
@ -23,8 +25,8 @@ import org.oscim.view.IMapRenderer;
public class MapWorker extends PausableThread { public class MapWorker extends PausableThread {
private final String THREAD_NAME; private final String THREAD_NAME;
private final JobQueue mJobQueue; private final JobQueue mJobQueue;
private final IMapGenerator mMapGenerator; private final MapGenerator mMapGenerator;
private final IMapRenderer mMapRenderer; private final MapRenderer mMapRenderer;
// private final int mPrio; // private final int mPrio;
@ -36,8 +38,8 @@ public class MapWorker extends PausableThread {
* @param mapRenderer * @param mapRenderer
* ... * ...
*/ */
public MapWorker(int id, JobQueue jobQueue, IMapGenerator mapGenerator, public MapWorker(int id, JobQueue jobQueue, MapGenerator mapGenerator,
IMapRenderer mapRenderer) { MapRenderer mapRenderer) {
super(); super();
mJobQueue = jobQueue; mJobQueue = jobQueue;
mMapGenerator = mapGenerator; mMapGenerator = mapGenerator;
@ -47,7 +49,7 @@ public class MapWorker extends PausableThread {
// mPrio = Math.max(Thread.MIN_PRIORITY + id, Thread.NORM_PRIORITY - 1); // mPrio = Math.max(Thread.MIN_PRIORITY + id, Thread.NORM_PRIORITY - 1);
} }
public IMapGenerator getMapGenerator() { public MapGenerator getMapGenerator() {
return mMapGenerator; return mMapGenerator;
} }

View File

@ -12,7 +12,7 @@
* You should have received a copy of the GNU Lesser General Public License along with * 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/>. * this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
package org.oscim.view.mapgenerator; package org.oscim.view.generator;
import java.util.Comparator; import java.util.Comparator;

View File

@ -1,73 +0,0 @@
/*
* 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.oscim.view.glrenderer;
import org.oscim.view.mapgenerator.JobTile;
class MapTile extends JobTile {
byte lastDraw = 0;
/**
* VBO layout:
* - 16 bytes fill coordinates
* - n bytes polygon vertices
* - m bytes lines vertices
*/
VertexBufferObject vbo;
/**
* polygonOffset in vbo is always 16 bytes,
*/
int lineOffset;
TextTexture texture;
/**
* Tile data set by MapGenerator:
*/
LineLayer lineLayers;
PolygonLayer polygonLayers;
TextItem labels;
/**
* tile has new data to upload to gl
*/
boolean newData;
/**
* tile is loaded and ready for drawing.
*/
boolean isReady;
/**
* tile is in view region.
*/
boolean isVisible;
/**
* tile is used by render thread. set by updateVisibleList (main thread).
*/
boolean isActive;
/**
* pointer to access relatives in TileTree
*/
QuadTree rel;
MapTile(int tileX, int tileY, byte zoomLevel) {
super(tileX, tileY, zoomLevel);
}
}

View File

@ -1,47 +0,0 @@
/*
* 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.oscim.view.mapgenerator;
import org.oscim.database.IMapDatabase;
import org.oscim.theme.RenderTheme;
/**
* A MapGenerator provides map tiles either by downloading or rendering them.
*/
public interface IMapGenerator {
/**
* Called once at the end of the MapGenerator lifecycle.
*/
void cleanup();
/**
* Called when a job needs to be executed.
*
* @param tile
* the job that should be executed.
* @return true if the job was executed successfully, false otherwise.
*/
boolean executeJob(JobTile tile);
/**
* @param mapDatabase
* the MapDatabase from which the map data will be read.
*/
void setMapDatabase(IMapDatabase mapDatabase);
IMapDatabase getMapDatabase();
void setRenderTheme(RenderTheme theme);
}

View File

@ -12,7 +12,7 @@
* You should have received a copy of the GNU Lesser General License along with * You should have received a copy of the GNU Lesser General License along with
* this program. If not, see <http://www.gnu.org/licenses/>. * this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
package org.oscim.view.glrenderer; package org.oscim.view.renderer;
import static android.opengl.GLES20.GL_ARRAY_BUFFER; import static android.opengl.GLES20.GL_ARRAY_BUFFER;
import static android.opengl.GLES20.GL_BLEND; import static android.opengl.GLES20.GL_BLEND;
@ -41,20 +41,19 @@ import javax.microedition.khronos.opengles.GL10;
import org.oscim.core.MapPosition; import org.oscim.core.MapPosition;
import org.oscim.core.Tile; import org.oscim.core.Tile;
import org.oscim.theme.RenderTheme; import org.oscim.theme.RenderTheme;
import org.oscim.utils.GlUtils;
import org.oscim.view.MapView; import org.oscim.view.MapView;
import org.oscim.view.mapgenerator.IMapGenerator;
import org.oscim.view.mapgenerator.JobTile;
import org.oscim.view.utils.GlUtils;
import android.opengl.GLES20; import android.opengl.GLES20;
import android.opengl.GLSurfaceView;
import android.opengl.Matrix; import android.opengl.Matrix;
import android.os.SystemClock; import android.os.SystemClock;
import android.util.FloatMath; import android.util.FloatMath;
import android.util.Log; import android.util.Log;
public class MapRenderer implements org.oscim.view.IMapRenderer { public class GLRenderer implements GLSurfaceView.Renderer {
private static final String TAG = "MapRenderer"; private static final String TAG = "SurfaceRenderer";
private static final int MB = 1024 * 1024; private static final int MB = 1024 * 1024;
private static final int SHORT_BYTES = 2; private static final int SHORT_BYTES = 2;
@ -117,7 +116,7 @@ public class MapRenderer implements org.oscim.view.IMapRenderer {
* @param mapView * @param mapView
* the MapView * the MapView
*/ */
public MapRenderer(MapView mapView) { public GLRenderer(MapView mapView) {
Log.d(TAG, "init MapRenderer"); Log.d(TAG, "init MapRenderer");
mMapView = mapView; mMapView = mapView;
@ -126,17 +125,6 @@ public class MapRenderer implements org.oscim.view.IMapRenderer {
mUpdateTiles = false; mUpdateTiles = false;
} }
/**
* called by MapView when position or map settings changes
*/
@Override
public void updateMap(boolean clear) {
if (mWidth <= 0 || mHeight <= 0)
return;
TileLoader.updateMap(clear);
}
/** /**
* called by TileLoader when only position changed * called by TileLoader when only position changed
* *
@ -157,21 +145,51 @@ public class MapRenderer implements org.oscim.view.IMapRenderer {
* @return curTiles (the previously active tiles) * @return curTiles (the previously active tiles)
*/ */
static TilesData updateTiles(MapPosition mapPosition, TilesData tiles) { static TilesData updateTiles(MapPosition mapPosition, TilesData tiles) {
synchronized (MapRenderer.lock) { synchronized (GLRenderer.lock) {
mCurPosition = mapPosition; mCurPosition = mapPosition;
for (int i = 0; i < curTiles.cnt; i++) // unlock previously active tiles
curTiles.tiles[i].isActive = false; for (int i = 0; i < curTiles.cnt; i++) {
MapTile t = curTiles.tiles[i];
boolean found = false;
for (int j = 0; j < tiles.cnt; j++) {
if (tiles.tiles[j] == t) {
found = true;
break;
}
}
if (found)
continue;
for (int j = 0; j < drawTiles.cnt; j++) {
if (drawTiles.tiles[j] == t) {
found = true;
break;
}
}
if (found)
continue;
t.unlock();
}
TilesData tmp = curTiles; TilesData tmp = curTiles;
curTiles = tiles; curTiles = tiles;
for (int i = 0; i < curTiles.cnt; i++) // lock tiles (and their proxies) to not be removed from cache
curTiles.tiles[i].isActive = true; for (int i = 0; i < curTiles.cnt; i++) {
MapTile t = curTiles.tiles[i];
if (!t.isActive)
t.lock();
}
for (int j = 0; j < drawTiles.cnt; j++) for (int j = 0; j < drawTiles.cnt; j++) {
drawTiles.tiles[j].isActive = true; MapTile t = drawTiles.tiles[j];
if (!t.isActive)
t.lock();
}
mUpdateTiles = true; mUpdateTiles = true;
@ -191,44 +209,25 @@ public class MapRenderer implements org.oscim.view.IMapRenderer {
} }
} }
/** void setVBO(MapTile tile) {
* called from MapWorker Thread when tile is loaded by MapGenerator
*/
@Override
public synchronized boolean passTile(JobTile jobTile) {
MapTile tile = (MapTile) jobTile;
if (!tile.isLoading) {
// no one should be able to use this tile now, mapgenerator passed it,
// glthread does nothing until newdata is set.
Log.d(TAG, "passTile: canceled " + tile);
TileLoader.addTileLoaded(tile);
return true;
}
synchronized (mVBOs) { synchronized (mVBOs) {
int numVBOs = mVBOs.size(); int numVBOs = mVBOs.size();
if (numVBOs > 0 && tile.vbo == null) { if (numVBOs > 0 && tile.vbo == null) {
tile.vbo = mVBOs.remove(numVBOs - 1); tile.vbo = mVBOs.remove(numVBOs - 1);
} }
if (tile.vbo == null) {
Log.d(TAG, "no VBOs left for " + tile);
tile.isLoading = false;
return false;
}
} }
}
tile.newData = true; void setRenderTheme(RenderTheme t) {
tile.isLoading = false; int bg = t.getMapBackground();
float[] c = new float[4];
if (!MapView.debugFrameTime) c[3] = (bg >> 24 & 0xff) / 255.0f;
mMapView.requestRender(); c[0] = (bg >> 16 & 0xff) / 255.0f;
c[1] = (bg >> 8 & 0xff) / 255.0f;
TileLoader.addTileLoaded(tile); c[2] = (bg >> 0 & 0xff) / 255.0f;
mClearColor = c;
return true; mUpdateColor = true;
} }
// depthRange: -1 to 1, bits: 2^24 => 2/2^24 one step // depthRange: -1 to 1, bits: 2^24 => 2/2^24 one step
@ -254,7 +253,7 @@ public class MapRenderer implements org.oscim.view.IMapRenderer {
Matrix.translateM(mMVPMatrix, 0, Matrix.translateM(mMVPMatrix, 0,
x * COORD_MULTIPLIER, x * COORD_MULTIPLIER,
-(y + Tile.TILE_SIZE) * COORD_MULTIPLIER, -(y + Tile.TILE_SIZE) * COORD_MULTIPLIER,
-1 + offset * 0.01f); -0.99f + offset * 0.01f);
Matrix.multiplyMM(mMVPMatrix, 0, mRotateMatrix, 0, mMVPMatrix, 0); Matrix.multiplyMM(mMVPMatrix, 0, mRotateMatrix, 0, mMVPMatrix, 0);
@ -268,7 +267,7 @@ public class MapRenderer implements org.oscim.view.IMapRenderer {
mMVPMatrix[12] = x * scale * mAspect; mMVPMatrix[12] = x * scale * mAspect;
mMVPMatrix[13] = -(y + Tile.TILE_SIZE) * scale; mMVPMatrix[13] = -(y + Tile.TILE_SIZE) * scale;
// increase the 'distance' with each tile drawn. // increase the 'distance' with each tile drawn.
mMVPMatrix[14] = -1 + offset * 0.01f; // depthStep; // 0.01f; mMVPMatrix[14] = -0.99f + offset * 0.01f; // depthStep; // 0.01f;
mMVPMatrix[0] = scale * mAspect / COORD_MULTIPLIER; mMVPMatrix[0] = scale * mAspect / COORD_MULTIPLIER;
mMVPMatrix[5] = scale / COORD_MULTIPLIER; mMVPMatrix[5] = scale / COORD_MULTIPLIER;
} }
@ -332,13 +331,13 @@ public class MapRenderer implements org.oscim.view.IMapRenderer {
if (!tile.newData) if (!tile.newData)
return false; return false;
int lineSize = LineLayers.sizeOf(tile.lineLayers); int lineSize = LineRenderer.sizeOf(tile.lineLayers);
int polySize = PolygonLayers.sizeOf(tile.polygonLayers); int polySize = PolygonRenderer.sizeOf(tile.polygonLayers);
int newSize = lineSize + polySize; int newSize = lineSize + polySize;
if (newSize == 0) { if (newSize == 0) {
LineLayers.clear(tile.lineLayers); LineRenderer.clear(tile.lineLayers);
PolygonLayers.clear(tile.polygonLayers); PolygonRenderer.clear(tile.polygonLayers);
tile.lineLayers = null; tile.lineLayers = null;
tile.polygonLayers = null; tile.polygonLayers = null;
tile.newData = false; tile.newData = false;
@ -365,7 +364,7 @@ public class MapRenderer implements org.oscim.view.IMapRenderer {
sbuf.clear(); sbuf.clear();
sbuf.position(8); sbuf.position(8);
PolygonLayers.compileLayerData(tile.polygonLayers, sbuf); PolygonRenderer.compileLayerData(tile.polygonLayers, sbuf);
tile.lineOffset = (8 + polySize); tile.lineOffset = (8 + polySize);
if (tile.lineOffset != sbuf.position()) if (tile.lineOffset != sbuf.position())
@ -374,25 +373,29 @@ public class MapRenderer implements org.oscim.view.IMapRenderer {
+ sbuf.position() + " " + sbuf.position() + " "
+ sbuf.limit() + " " + sbuf.limit() + " "
+ sbuf.remaining() + " " + sbuf.remaining() + " "
+ PolygonLayers.sizeOf(tile.polygonLayers) + " " + PolygonRenderer.sizeOf(tile.polygonLayers) + " "
+ tile.rel); + tile.rel);
tile.lineOffset *= SHORT_BYTES; tile.lineOffset *= SHORT_BYTES;
LineLayers.compileLayerData(tile.lineLayers, sbuf); LineRenderer.compileLayerData(tile.lineLayers, sbuf);
sbuf.flip(); sbuf.flip();
if (newSize != sbuf.remaining()) if (newSize != sbuf.remaining()) {
Log.d(TAG, "tiles wrong: " + tile + " " Log.d(TAG, "tiles wrong: " + tile + " "
+ newSize + " " + newSize + " "
+ sbuf.position() + " " + sbuf.position() + " "
+ sbuf.limit() + " " + sbuf.limit() + " "
+ sbuf.remaining() + " " + sbuf.remaining() + " "
+ LineLayers.sizeOf(tile.lineLayers) + LineRenderer.sizeOf(tile.lineLayers)
+ tile.isLoading + " " + tile.isLoading + " "
+ tile.rel); + tile.rel);
tile.newData = false;
return false;
}
newSize *= SHORT_BYTES; newSize *= SHORT_BYTES;
if (tile.vbo.size > newSize && tile.vbo.size < newSize * 4 if (tile.vbo.size > newSize && tile.vbo.size < newSize * 4
@ -459,6 +462,7 @@ public class MapRenderer implements org.oscim.view.IMapRenderer {
@Override @Override
public void onDrawFrame(GL10 glUnused) { public void onDrawFrame(GL10 glUnused) {
long start = 0; long start = 0;
MapPosition mapPosition; MapPosition mapPosition;
if (MapView.debugFrameTime) if (MapView.debugFrameTime)
@ -484,7 +488,7 @@ public class MapRenderer implements org.oscim.view.IMapRenderer {
| GLES20.GL_STENCIL_BUFFER_BIT); | GLES20.GL_STENCIL_BUFFER_BIT);
// get position and current tiles to draw // get position and current tiles to draw
synchronized (MapRenderer.lock) { synchronized (GLRenderer.lock) {
mapPosition = mCurPosition; mapPosition = mCurPosition;
if (mUpdateTiles) { if (mUpdateTiles) {
@ -495,6 +499,9 @@ public class MapRenderer implements org.oscim.view.IMapRenderer {
} }
} }
if (drawTiles == null)
return;
int tileCnt = drawTiles.cnt; int tileCnt = drawTiles.cnt;
MapTile[] tiles = drawTiles.tiles; MapTile[] tiles = drawTiles.tiles;
@ -635,24 +642,25 @@ public class MapRenderer implements org.oscim.view.IMapRenderer {
if (pl != null && pnext < lnext) { if (pl != null && pnext < lnext) {
glDisable(GL_BLEND); glDisable(GL_BLEND);
pl = PolygonLayers.drawPolygons(pl, lnext, mMVPMatrix, z, s, !clipped); pl = PolygonRenderer.drawPolygons(pl, lnext, mMVPMatrix, z, s, !clipped);
clipped = true; clipped = true;
} else { } else {
// XXX nasty // XXX nasty
if (!clipped) { if (!clipped) {
PolygonLayers.drawPolygons(null, 0, mMVPMatrix, z, s, true); PolygonRenderer.drawPolygons(null, 0, mMVPMatrix, z, s, true);
clipped = true; clipped = true;
} }
glEnable(GL_BLEND); glEnable(GL_BLEND);
ll = LineLayers.drawLines(tile, ll, pnext, mMVPMatrix, div, z, s); ll = LineRenderer.drawLines(tile, ll, pnext, mMVPMatrix, div, z, s);
} }
} }
} }
// TODO could use tile.proxies here
private static boolean drawProxyChild(MapPosition mapPosition, MapTile tile) { private static boolean drawProxyChild(MapPosition mapPosition, MapTile tile) {
int drawn = 0; int drawn = 0;
for (int i = 0; i < 4; i++) { for (int i = 0; i < 4; i++) {
@ -676,6 +684,7 @@ public class MapRenderer implements org.oscim.view.IMapRenderer {
return drawn == 4; return drawn == 4;
} }
// TODO could use tile.proxies here
private static void drawProxyTile(MapPosition mapPosition, MapTile tile) { private static void drawProxyTile(MapPosition mapPosition, MapTile tile) {
if (mapPosition.scale > 1.5f) { if (mapPosition.scale > 1.5f) {
@ -716,14 +725,16 @@ public class MapRenderer implements org.oscim.view.IMapRenderer {
public void onSurfaceChanged(GL10 glUnused, int width, int height) { public void onSurfaceChanged(GL10 glUnused, int width, int height) {
Log.d(TAG, "SurfaceChanged:" + width + " " + height); Log.d(TAG, "SurfaceChanged:" + width + " " + height);
drawTiles = curTiles = null; mWidth = width;
mBufferMemoryUsage = 0; mHeight = height;
if (width <= 0 || height <= 0) if (width <= 0 || height <= 0)
return; return;
mWidth = width; boolean changed = true;
mHeight = height; if (mWidth == width || mHeight == height)
changed = false;
mAspect = (float) height / width; mAspect = (float) height / width;
Matrix.orthoM(mProjMatrix, 0, -0.5f / mAspect, 0.5f / mAspect, -0.5f, 0.5f, -1, 1); Matrix.orthoM(mProjMatrix, 0, -0.5f / mAspect, 0.5f / mAspect, -0.5f, 0.5f, -1, 1);
@ -733,14 +744,16 @@ public class MapRenderer implements org.oscim.view.IMapRenderer {
glViewport(0, 0, width, height); glViewport(0, 0, width, height);
if (!changed && !mNewSurface) {
mMapView.redrawMap();
return;
}
mBufferMemoryUsage = 0;
int numTiles = (mWidth / (Tile.TILE_SIZE / 2) + 2) int numTiles = (mWidth / (Tile.TILE_SIZE / 2) + 2)
* (mHeight / (Tile.TILE_SIZE / 2) + 2); * (mHeight / (Tile.TILE_SIZE / 2) + 2);
TileLoader.init(mMapView, width, height, numTiles);
drawTiles = new TilesData(numTiles);
curTiles = new TilesData(numTiles);
// Set up vertex buffer objects // Set up vertex buffer objects
int numVBO = (CACHE_TILES + (numTiles * 2)); int numVBO = (CACHE_TILES + (numTiles * 2));
int[] mVboIds = new int[numVBO]; int[] mVboIds = new int[numVBO];
@ -774,14 +787,24 @@ public class MapRenderer implements org.oscim.view.IMapRenderer {
GlUtils.checkGlError("onSurfaceChanged"); GlUtils.checkGlError("onSurfaceChanged");
mMapView.redrawTiles(); mMapView.redrawMap();
}
void clearTiles() {
int numTiles = (mWidth / (Tile.TILE_SIZE / 2) + 2)
* (mHeight / (Tile.TILE_SIZE / 2) + 2);
Log.d(TAG, "clearTiles " + numTiles);
drawTiles = new TilesData(numTiles);
curTiles = new TilesData(numTiles);
} }
@Override @Override
public void onSurfaceCreated(GL10 gl, EGLConfig config) { public void onSurfaceCreated(GL10 gl, EGLConfig config) {
// String ext = GLES20.glGetString(GLES20.GL_EXTENSIONS); String ext = GLES20.glGetString(GLES20.GL_EXTENSIONS);
// Log.d(TAG, "Extensions: " + ext); Log.d(TAG, "Extensions: " + ext);
shortBuffer = new ShortBuffer[rotateBuffers]; shortBuffer = new ShortBuffer[rotateBuffers];
@ -799,25 +822,11 @@ public class MapRenderer implements org.oscim.view.IMapRenderer {
mFillCoords[6] = max; mFillCoords[6] = max;
mFillCoords[7] = min; mFillCoords[7] = min;
LineLayers.init(); LineRenderer.init();
PolygonLayers.init(); PolygonRenderer.init();
mNewSurface = true;
} }
@Override private boolean mNewSurface;
public IMapGenerator createMapGenerator() {
return new MapGenerator(mMapView);
}
@Override
public void setRenderTheme(RenderTheme t) {
int bg = t.getMapBackground();
float[] c = new float[4];
c[0] = (bg >> 16 & 0xff) / 255.0f;
c[1] = (bg >> 8 & 0xff) / 255.0f;
c[2] = (bg >> 0 & 0xff) / 255.0f;
c[3] = (bg >> 24 & 0xff) / 255.0f;
mClearColor = c;
mUpdateColor = true;
}
} }

View File

@ -12,7 +12,7 @@
* You should have received a copy of the GNU Lesser General License along with * You should have received a copy of the GNU Lesser General License along with
* this program. If not, see <http://www.gnu.org/licenses/>. * this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
package org.oscim.view.glrenderer; package org.oscim.view.renderer;
import org.oscim.core.Tile; import org.oscim.core.Tile;
import org.oscim.theme.renderinstruction.Line; import org.oscim.theme.renderinstruction.Line;
@ -22,7 +22,7 @@ import android.util.FloatMath;
class LineLayer { class LineLayer {
private static final float COORD_SCALE = MapRenderer.COORD_MULTIPLIER; private static final float COORD_SCALE = GLRenderer.COORD_MULTIPLIER;
// scale factor mapping extrusion vector to short values // scale factor mapping extrusion vector to short values
private static final float DIR_SCALE = 2048; private static final float DIR_SCALE = 2048;
// mask for packing last two bits of extrusion vector with texture coordinates // mask for packing last two bits of extrusion vector with texture coordinates
@ -67,7 +67,7 @@ class LineLayer {
* line extrusion is based on code from GLMap (https://github.com/olofsj/GLMap/) by olofsj * line extrusion is based on code from GLMap (https://github.com/olofsj/GLMap/) by olofsj
*/ */
void addLine(float[] points, short[] index) { void addLine(float[] points, short[] index, boolean closed) {
float x, y, nextX, nextY, prevX, prevY; float x, y, nextX, nextY, prevX, prevY;
float a, ux, uy, vx, vy, wx, wy; float a, ux, uy, vx, vy, wx, wy;
@ -91,6 +91,7 @@ class LineLayer {
int opos = si.used; int opos = si.used;
for (int i = 0, pos = 0, n = index.length; i < n; i++) { for (int i = 0, pos = 0, n = index.length; i < n; i++) {
int length = index[i]; int length = index[i];
if (length < 0) if (length < 0)
break; break;
@ -99,15 +100,22 @@ class LineLayer {
if (rounded && i > 200) if (rounded && i > 200)
rounded = false; rounded = false;
int ipos = pos;
// need at least two points // need at least two points
if (length < 4) { if (length < 4) {
pos += length; pos += length;
continue; continue;
} }
//
closed = false;
// amount of vertices used // amount of vertices used
verticesCnt += length + (rounded ? 6 : 2); // + 2 for drawing triangle-strip
// + 4 for round caps
// + 2 for closing polygons
verticesCnt += length + (rounded ? 6 : 2) + (closed ? 2 : 0);
int ipos = pos;
x = points[ipos++]; x = points[ipos++];
y = points[ipos++]; y = points[ipos++];
@ -270,9 +278,17 @@ class LineLayer {
x = nextX; x = nextX;
y = nextY; y = nextY;
for (; ipos < pos + length;) { for (;;) {
nextX = points[ipos++]; if (ipos < pos + length) {
nextY = points[ipos++]; nextX = points[ipos++];
nextY = points[ipos++];
} else if (closed && ipos < pos + length + 2) {
// add startpoint == endpoint
nextX = points[pos];
nextY = points[pos + 1];
ipos += 2;
} else
break;
// Unit vector pointing back to previous node // Unit vector pointing back to previous node
vx = prevX - x; vx = prevX - x;
@ -310,18 +326,18 @@ class LineLayer {
} }
} }
if (opos == ShortItem.SIZE) {
si = si.next = ShortPool.get();
v = si.vertices;
opos = 0;
}
ox = (short) (x * COORD_SCALE); ox = (short) (x * COORD_SCALE);
oy = (short) (y * COORD_SCALE); oy = (short) (y * COORD_SCALE);
ddx = (int) (ux * DIR_SCALE); ddx = (int) (ux * DIR_SCALE);
ddy = (int) (uy * DIR_SCALE); ddy = (int) (uy * DIR_SCALE);
if (opos == ShortItem.SIZE) {
si = si.next = ShortPool.get();
v = si.vertices;
opos = 0;
}
v[opos++] = ox; v[opos++] = ox;
v[opos++] = oy; v[opos++] = oy;
v[opos++] = (short) (0 | ddx & DIR_MASK); v[opos++] = (short) (0 | ddx & DIR_MASK);

View File

@ -12,7 +12,7 @@
* You should have received a copy of the GNU Lesser General License along with * You should have received a copy of the GNU Lesser General License along with
* this program. If not, see <http://www.gnu.org/licenses/>. * this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
package org.oscim.view.glrenderer; package org.oscim.view.renderer;
import static android.opengl.GLES20.GL_TRIANGLE_STRIP; import static android.opengl.GLES20.GL_TRIANGLE_STRIP;
import static android.opengl.GLES20.glDisableVertexAttribArray; import static android.opengl.GLES20.glDisableVertexAttribArray;
@ -20,8 +20,6 @@ import static android.opengl.GLES20.glDrawArrays;
import static android.opengl.GLES20.glEnableVertexAttribArray; import static android.opengl.GLES20.glEnableVertexAttribArray;
import static android.opengl.GLES20.glGetAttribLocation; import static android.opengl.GLES20.glGetAttribLocation;
import static android.opengl.GLES20.glGetUniformLocation; import static android.opengl.GLES20.glGetUniformLocation;
import static android.opengl.GLES20.glUniform4f;
import static android.opengl.GLES20.glUniform4fv;
import static android.opengl.GLES20.glUniformMatrix4fv; import static android.opengl.GLES20.glUniformMatrix4fv;
import static android.opengl.GLES20.glUseProgram; import static android.opengl.GLES20.glUseProgram;
import static android.opengl.GLES20.glVertexAttribPointer; import static android.opengl.GLES20.glVertexAttribPointer;
@ -29,12 +27,12 @@ import static android.opengl.GLES20.glVertexAttribPointer;
import java.nio.ShortBuffer; import java.nio.ShortBuffer;
import org.oscim.theme.renderinstruction.Line; import org.oscim.theme.renderinstruction.Line;
import org.oscim.view.utils.GlUtils; import org.oscim.utils.GlUtils;
import android.opengl.GLES20; import android.opengl.GLES20;
import android.util.FloatMath; import android.util.FloatMath;
class LineLayers { class LineRenderer {
private static int NUM_VERTEX_SHORTS = 4; private static int NUM_VERTEX_SHORTS = 4;
private static final int LINE_VERTICES_DATA_POS_OFFSET = 0; private static final int LINE_VERTICES_DATA_POS_OFFSET = 0;
@ -108,20 +106,12 @@ class LineLayers {
if (line.fade != -1 && line.fade > zoom) if (line.fade != -1 && line.fade > zoom)
continue; continue;
if (line.fade >= zoom) { float alpha = 1.0f;
float alpha = 1.0f;
if (line.fade >= zoom)
alpha = (scale > 1.2f ? scale : 1.2f) - alpha; alpha = (scale > 1.2f ? scale : 1.2f) - alpha;
if (alpha > 1.0f)
alpha = 1.0f; GlUtils.setColor(hLineColor, line.color, alpha);
glUniform4f(hLineColor,
line.color[0] * alpha,
line.color[1] * alpha,
line.color[2] * alpha,
alpha);
} else {
glUniform4fv(hLineColor, 1, line.color, 0);
}
if (blur) { if (blur) {
if (mFast) if (mFast)

View File

@ -12,7 +12,7 @@
* You should have received a copy of the GNU Lesser General Public License along with * 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/>. * this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
package org.oscim.view.glrenderer; package org.oscim.view.renderer;
import org.oscim.core.MercatorProjection; import org.oscim.core.MercatorProjection;
import org.oscim.core.Tag; import org.oscim.core.Tag;
@ -30,8 +30,7 @@ import org.oscim.theme.renderinstruction.PathText;
import org.oscim.theme.renderinstruction.RenderInstruction; import org.oscim.theme.renderinstruction.RenderInstruction;
import org.oscim.view.DebugSettings; import org.oscim.view.DebugSettings;
import org.oscim.view.MapView; import org.oscim.view.MapView;
import org.oscim.view.mapgenerator.IMapGenerator; import org.oscim.view.generator.JobTile;
import org.oscim.view.mapgenerator.JobTile;
import android.graphics.Bitmap; import android.graphics.Bitmap;
import android.graphics.Paint; import android.graphics.Paint;
@ -40,7 +39,7 @@ import android.util.Log;
/** /**
* *
*/ */
public class MapGenerator implements IMapGenerator, IRenderCallback, IMapDatabaseCallback { public class MapGenerator implements IRenderCallback, IMapDatabaseCallback {
private static String TAG = MapGenerator.class.getName(); private static String TAG = MapGenerator.class.getName();
@ -59,8 +58,8 @@ public class MapGenerator implements IMapGenerator, IRenderCallback, IMapDatabas
private MapTile mCurrentTile; private MapTile mCurrentTile;
private float[] mWayNodes; private float[] mCoords;
private short[] mWays; private short[] mIndices;
private LineLayer mLineLayers; private LineLayer mLineLayers;
private PolygonLayer mPolyLayers; private PolygonLayer mPolyLayers;
@ -89,8 +88,8 @@ public class MapGenerator implements IMapGenerator, IRenderCallback, IMapDatabas
private final Tag[] debugTagWay = { new Tag("debug", "way") }; private final Tag[] debugTagWay = { new Tag("debug", "way") };
private final Tag[] debugTagArea = { new Tag("debug", "area") }; private final Tag[] debugTagArea = { new Tag("debug", "area") };
private final float[] debugBoxCoords = { 0, 0, 0, Tile.TILE_SIZE, private final float[] debugBoxCoords = { 0, 0, 0, Tile.TILE_SIZE,
Tile.TILE_SIZE, Tile.TILE_SIZE, Tile.TILE_SIZE, 0, 0, 0 }; Tile.TILE_SIZE, Tile.TILE_SIZE, Tile.TILE_SIZE, 0 };
private final short[] debugBoxIndex = { 10 }; private final short[] debugBoxIndex = { 8 };
private float mProjectionScaleFactor; private float mProjectionScaleFactor;
@ -112,7 +111,7 @@ public class MapGenerator implements IMapGenerator, IRenderCallback, IMapDatabas
private void filterTags(Tag[] tags) { private void filterTags(Tag[] tags) {
for (int i = 0; i < tags.length; i++) { for (int i = 0; i < tags.length; i++) {
// Log.d(TAG, "check tag: " + tags[i]); // Log.d(TAG, "check tag: " + tags[i]);
if (tags[i].key == Tag.TAG_KEY_NAME && tags[i].value != null) { if (tags[i].key == Tag.TAG_KEY_NAME) {
mTagName = tags[i]; mTagName = tags[i];
tags[i] = mTagEmptyName; tags[i] = mTagEmptyName;
} }
@ -122,8 +121,8 @@ public class MapGenerator implements IMapGenerator, IRenderCallback, IMapDatabas
// private RenderInstruction[] mNodeRenderInstructions; // private RenderInstruction[] mNodeRenderInstructions;
@Override @Override
public void renderPointOfInterest(byte layer, float latitude, float longitude, public void renderPointOfInterest(byte layer, Tag[] tags, float latitude,
Tag[] tags) { float longitude) {
mTagName = null; mTagName = null;
@ -171,13 +170,16 @@ public class MapGenerator implements IMapGenerator, IRenderCallback, IMapDatabas
} }
private boolean mClosed;
@Override @Override
public void renderWay(byte layer, Tag[] tags, float[] wayNodes, short[] wayLength, public void renderWay(byte layer, Tag[] tags, float[] coords, short[] indices,
boolean closed) { boolean closed) {
mTagName = null; mTagName = null;
mProjected = false; mProjected = false;
mCurLineLayer = null; mCurLineLayer = null;
mClosed = closed;
mDrawingLayer = getValidLayer(layer) * mLevels; mDrawingLayer = getValidLayer(layer) * mLevels;
mSimplify = 0.5f; mSimplify = 0.5f;
@ -192,8 +194,8 @@ public class MapGenerator implements IMapGenerator, IRenderCallback, IMapDatabas
mSimplify = 0; mSimplify = 0;
} }
mWayNodes = wayNodes; mCoords = coords;
mWays = wayLength; mIndices = indices;
// remove tags that should not be cached in Rendertheme // remove tags that should not be cached in Rendertheme
filterTags(tags); filterTags(tags);
@ -236,7 +238,7 @@ public class MapGenerator implements IMapGenerator, IRenderCallback, IMapDatabas
if (caption.textKey == mTagEmptyName.key) { if (caption.textKey == mTagEmptyName.key) {
TextItem t = new TextItem(mWayNodes[0], mWayNodes[1], mTagName.value, caption); TextItem t = new TextItem(mCoords[0], mCoords[1], mTagName.value, caption);
t.next = mLabels; t.next = mLabels;
mLabels = t; mLabels = t;
} }
@ -266,8 +268,8 @@ public class MapGenerator implements IMapGenerator, IRenderCallback, IMapDatabas
if (pathText.textKey == mTagEmptyName.key) { if (pathText.textKey == mTagEmptyName.key) {
mLabels = WayDecorator.renderText(mWayNodes, mTagName.value, pathText, 0, mLabels = WayDecorator.renderText(mCoords, mTagName.value, pathText, 0,
mWays[0], mLabels); mIndices[0], mLabels);
} }
} }
@ -335,6 +337,7 @@ public class MapGenerator implements IMapGenerator, IRenderCallback, IMapDatabas
// lineLayer = LineLayers.get(numLayer, line, w, false); // lineLayer = LineLayers.get(numLayer, line, w, false);
lineLayer.next = l.next; lineLayer.next = l.next;
l.next = lineLayer; l.next = lineLayer;
break;
} }
l = l.next; l = l.next;
} }
@ -351,7 +354,7 @@ public class MapGenerator implements IMapGenerator, IRenderCallback, IMapDatabas
mCurLineLayer = lineLayer; mCurLineLayer = lineLayer;
lineLayer.addLine(mWayNodes, mWays); lineLayer.addLine(mCoords, mIndices, mClosed);
} }
@Override @Override
@ -387,6 +390,7 @@ public class MapGenerator implements IMapGenerator, IRenderCallback, IMapDatabas
layer = new PolygonLayer(numLayer, area); layer = new PolygonLayer(numLayer, area);
layer.next = l.next; layer.next = l.next;
l.next = layer; l.next = layer;
break;
} }
l = l.next; l = l.next;
} }
@ -396,7 +400,7 @@ public class MapGenerator implements IMapGenerator, IRenderCallback, IMapDatabas
mCurPolyLayer = layer; mCurPolyLayer = layer;
layer.addPolygon(mWayNodes, mWays); layer.addPolygon(mCoords, mIndices);
} }
@Override @Override
@ -405,7 +409,6 @@ public class MapGenerator implements IMapGenerator, IRenderCallback, IMapDatabas
} }
@Override
public void cleanup() { public void cleanup() {
// TODO Auto-generated method stub // TODO Auto-generated method stub
@ -414,7 +417,6 @@ public class MapGenerator implements IMapGenerator, IRenderCallback, IMapDatabas
private boolean mDebugDrawPolygons; private boolean mDebugDrawPolygons;
boolean mDebugDrawUnmatched; boolean mDebugDrawUnmatched;
@Override
public boolean executeJob(JobTile jobTile) { public boolean executeJob(JobTile jobTile) {
MapTile tile; MapTile tile;
@ -455,8 +457,8 @@ public class MapGenerator implements IMapGenerator, IRenderCallback, IMapDatabas
if (mMapDatabase.executeQuery(tile, this) != QueryResult.SUCCESS) { if (mMapDatabase.executeQuery(tile, this) != QueryResult.SUCCESS) {
Log.d(TAG, "Failed loading: " + tile); Log.d(TAG, "Failed loading: " + tile);
LineLayers.clear(mLineLayers); LineRenderer.clear(mLineLayers);
PolygonLayers.clear(mPolyLayers); PolygonRenderer.clear(mPolyLayers);
mLineLayers = null; mLineLayers = null;
mPolyLayers = null; mPolyLayers = null;
mLabels = null; mLabels = null;
@ -471,8 +473,8 @@ public class MapGenerator implements IMapGenerator, IRenderCallback, IMapDatabas
mPoiY = 10; mPoiY = 10;
MapGenerator.renderTheme.matchNode(this, debugTagWay, (byte) 0); MapGenerator.renderTheme.matchNode(this, debugTagWay, (byte) 0);
mWays = debugBoxIndex; mIndices = debugBoxIndex;
mWayNodes = debugBoxCoords; mCoords = debugBoxCoords;
mDrawingLayer = 10 * mLevels; mDrawingLayer = 10 * mLevels;
MapGenerator.renderTheme.matchWay(this, debugTagBox, (byte) 0, false, true); MapGenerator.renderTheme.matchWay(this, debugTagBox, (byte) 0, false, true);
} }
@ -518,18 +520,15 @@ public class MapGenerator implements IMapGenerator, IRenderCallback, IMapDatabas
private String mMapProjection; private String mMapProjection;
@Override
public void setMapDatabase(IMapDatabase mapDatabase) { public void setMapDatabase(IMapDatabase mapDatabase) {
mMapDatabase = mapDatabase; mMapDatabase = mapDatabase;
mMapProjection = mMapDatabase.getMapProjection(); mMapProjection = mMapDatabase.getMapProjection();
} }
@Override
public IMapDatabase getMapDatabase() { public IMapDatabase getMapDatabase() {
return mMapDatabase; return mMapDatabase;
} }
@Override
public void setRenderTheme(RenderTheme theme) { public void setRenderTheme(RenderTheme theme) {
MapGenerator.renderTheme = theme; MapGenerator.renderTheme = theme;
} }
@ -552,7 +551,7 @@ public class MapGenerator implements IMapGenerator, IRenderCallback, IMapDatabas
if (mMapProjection == WebMercator.NAME) if (mMapProjection == WebMercator.NAME)
useWebMercator = true; useWebMercator = true;
float[] coords = mWayNodes; float[] coords = mCoords;
long x = mCurrentTile.pixelX; long x = mCurrentTile.pixelX;
long y = mCurrentTile.pixelY + Tile.TILE_SIZE; long y = mCurrentTile.pixelY + Tile.TILE_SIZE;
@ -571,8 +570,8 @@ public class MapGenerator implements IMapGenerator, IRenderCallback, IMapDatabas
divy = z / PIx4; divy = z / PIx4;
} }
for (int pos = 0, outPos = 0, i = 0, m = mWays.length; i < m; i++) { for (int pos = 0, outPos = 0, i = 0, m = mIndices.length; i < m; i++) {
int len = mWays[i]; int len = mIndices[i];
if (len == 0) if (len == 0)
continue; continue;
if (len < 0) if (len < 0)
@ -608,7 +607,7 @@ public class MapGenerator implements IMapGenerator, IRenderCallback, IMapDatabas
cnt += 2; cnt += 2;
} }
mWays[i] = (short) cnt; mIndices[i] = (short) cnt;
} }
mProjected = true; mProjected = true;
// mProjectedResult = true; // mProjectedResult = true;

View File

@ -12,7 +12,7 @@
* You should have received a copy of the GNU Lesser General Public License along with * 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/>. * this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
package org.oscim.view.glrenderer; package org.oscim.view.renderer;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
@ -20,22 +20,45 @@ import java.util.Collections;
import org.oscim.core.MapPosition; import org.oscim.core.MapPosition;
import org.oscim.core.MercatorProjection; import org.oscim.core.MercatorProjection;
import org.oscim.core.Tile; import org.oscim.core.Tile;
import org.oscim.theme.RenderTheme;
import org.oscim.utils.GlConfigChooser;
import org.oscim.view.MapView; import org.oscim.view.MapView;
import org.oscim.view.glrenderer.MapRenderer.TilesData; import org.oscim.view.generator.JobTile;
import org.oscim.view.mapgenerator.JobTile; import org.oscim.view.renderer.GLRenderer.TilesData;
import android.content.Context;
import android.opengl.GLSurfaceView;
import android.util.FloatMath; import android.util.FloatMath;
import android.util.Log; import android.util.Log;
// for lack of a better name... maybe TileManager? public class MapRenderer extends GLSurfaceView {
private final static String TAG = "MapRenderer";
/** public MapRenderer(Context context, MapView mapView) {
* Update list of visible tiles and passes them to MapRenderer, when not available tiles are created and added to super(context);
* JobQueue (mapView.addJobs) for loading by MapGenerator class
*/
class TileLoader { mMapView = mapView;
private static final String TAG = "TileLoader";
Log.d(TAG, "init GLSurfaceLayer");
setEGLConfigChooser(new GlConfigChooser());
setEGLContextClientVersion(2);
// setDebugFlags(DEBUG_CHECK_GL_ERROR | DEBUG_LOG_GL_CALLS);
mRenderer = new GLRenderer(mMapView);
setRenderer(mRenderer);
//
// if (!debugFrameTime)
setRenderMode(GLSurfaceView.RENDERMODE_WHEN_DIRTY);
mJobList = new ArrayList<JobTile>();
mTiles = new ArrayList<MapTile>();
mTilesLoaded = new ArrayList<MapTile>(30);
ShortPool.init();
QuadTree.init();
mInitial = true;
}
private static final int MAX_TILES_IN_QUEUE = 40; private static final int MAX_TILES_IN_QUEUE = 40;
@ -58,28 +81,25 @@ class TileLoader {
private static boolean mInitial; private static boolean mInitial;
// private static MapPosition mCurPosition, mDrawPosition; // private static MapPosition mCurPosition, mDrawPosition;
private static int mWidth, mHeight; private static int mWidth = 0, mHeight = 0;
private static TilesData newTiles; private static TilesData newTiles;
static void init(MapView mapView, int w, int h, int numTiles) { /**
mMapView = mapView; * called by MapView when position or map settings changes
*/
/**
* Update list of visible tiles and passes them to MapRenderer, when not available tiles are created and added to
* JobQueue (mapView.addJobs) for loading by MapGenerator class
*
* @param clear
* ...
*/
ShortPool.init(); public synchronized void updateMap(boolean clear) {
QuadTree.init();
mJobList = new ArrayList<JobTile>(); if (mWidth == 0 || mHeight == 0)
mTiles = new ArrayList<MapTile>(); return;
mTilesLoaded = new ArrayList<MapTile>(30);
mInitial = true;
mWidth = w;
mHeight = h;
newTiles = new TilesData(numTiles);
}
static synchronized void updateMap(boolean clear) {
boolean changedPos = false; boolean changedPos = false;
boolean changedZoom = false; boolean changedZoom = false;
@ -95,8 +115,10 @@ class TileLoader {
} }
if (clear) { if (clear) {
Log.d(TAG, "CLEAR");
mInitial = true; mInitial = true;
synchronized (MapRenderer.lock) { synchronized (GLRenderer.lock) {
for (MapTile t : mTiles) for (MapTile t : mTiles)
clearTile(t); clearTile(t);
@ -107,6 +129,15 @@ class TileLoader {
} }
} }
if (mInitial) {
mRenderer.clearTiles();
int numTiles = (mWidth / (Tile.TILE_SIZE / 2) + 2)
* (mHeight / (Tile.TILE_SIZE / 2) + 2);
Log.d(TAG, "newTiles: " + numTiles);
newTiles = new TilesData(numTiles);
}
byte zoomLevel = mapPosition.zoomLevel; byte zoomLevel = mapPosition.zoomLevel;
float scale = mapPosition.scale; float scale = mapPosition.scale;
@ -148,17 +179,17 @@ class TileLoader {
updateVisibleList(mapPosition, 0); updateVisibleList(mapPosition, 0);
} else { } else {
// pass new position to glThread // pass new position to glThread
MapRenderer.updatePosition(mapPosition); GLRenderer.updatePosition(mapPosition);
} }
if (!MapView.debugFrameTime) if (!MapView.debugFrameTime)
mMapView.requestRender(); requestRender();
if (changedPos) if (changedPos)
updateVisibleList(mapPosition, zdir); updateVisibleList(mapPosition, zdir);
if (changedPos || changedZoom) { if (changedPos || changedZoom) {
int remove = mTiles.size() - MapRenderer.CACHE_TILES; int remove = mTiles.size() - GLRenderer.CACHE_TILES;
if (remove > 50) if (remove > 50)
limitCache(mapPosition, remove); limitCache(mapPosition, remove);
} }
@ -240,8 +271,9 @@ class TileLoader {
// pass new tile list to glThread // pass new tile list to glThread
newTiles.cnt = tiles; newTiles.cnt = tiles;
newTiles = MapRenderer.updateTiles(mapPosition, newTiles); newTiles = GLRenderer.updateTiles(mapPosition, newTiles);
// note: this sets isLoading == true for all job tiles
if (mJobList.size() > 0) { if (mJobList.size() > 0) {
updateTileDistances(mJobList, mapPosition); updateTileDistances(mJobList, mapPosition);
Collections.sort(mJobList); Collections.sort(mJobList);
@ -252,88 +284,31 @@ class TileLoader {
} }
private static void clearTile(MapTile t) { private static void clearTile(MapTile t) {
t.newData = false; t.newData = false;
t.isLoading = false; t.isLoading = false;
t.isReady = false; t.isReady = false;
LineLayers.clear(t.lineLayers); LineRenderer.clear(t.lineLayers);
PolygonLayers.clear(t.polygonLayers); PolygonRenderer.clear(t.polygonLayers);
t.labels = null; t.labels = null;
t.lineLayers = null; t.lineLayers = null;
t.polygonLayers = null; t.polygonLayers = null;
if (t.vbo != null) { if (t.vbo != null) {
MapRenderer.addVBO(t.vbo); GLRenderer.addVBO(t.vbo);
t.vbo = null; t.vbo = null;
} }
if (t.texture != null)
t.texture.tile = null;
QuadTree.remove(t); QuadTree.remove(t);
} }
private static boolean childIsActive(MapTile t) { // private static boolean tileInUse(MapTile t) {
MapTile c = null; // return (t.isActive || t.refs != 0);
// }
for (int i = 0; i < 4; i++) {
if (t.rel.child[i] == null)
continue;
c = t.rel.child[i].tile;
if (c != null && c.isActive && !(c.isReady || c.newData))
return true;
}
return false;
}
// FIXME still the chance that one jumped two zoomlevels between
// cur and draw. should use reference counter instead
private static boolean tileInUse(MapTile t) {
byte z = mPrevZoom;
if (t.isActive) {
return true;
} else if (t.zoomLevel == z + 1) {
MapTile p = t.rel.parent.tile;
if (p != null && p.isActive && !(p.isReady || p.newData))
return true;
} else if (t.zoomLevel == z + 2) {
MapTile p = t.rel.parent.parent.tile;
if (p != null && p.isActive && !(p.isReady || p.newData))
return true;
} else if (t.zoomLevel == z - 1) {
if (childIsActive(t))
return true;
} else if (t.zoomLevel == z - 2) {
for (QuadTree c : t.rel.child) {
if (c == null)
continue;
if (c.tile != null && childIsActive(c.tile))
return true;
}
} else if (t.zoomLevel == z - 3) {
for (QuadTree c : t.rel.child) {
if (c == null)
continue;
for (QuadTree c2 : c.child) {
if (c2 == null)
continue;
if (c2.tile != null && childIsActive(c2.tile))
return true;
}
}
}
return false;
}
private static void updateTileDistances(ArrayList<?> tiles, private static void updateTileDistances(ArrayList<?> tiles,
MapPosition mapPosition) { MapPosition mapPosition) {
@ -386,14 +361,12 @@ class TileLoader {
int removes = remove; int removes = remove;
int size = mTiles.size(); int size = mTiles.size();
// int tmp = size;
// remove orphaned tiles // remove orphaned tiles
for (int i = 0; i < size;) { for (int i = 0; i < size;) {
MapTile cur = mTiles.get(i); MapTile cur = mTiles.get(i);
// make sure tile cannot be used by GL or MapWorker Thread // make sure tile cannot be used by GL or MapWorker Thread
if ((!cur.isActive) && (!cur.isLoading) && (!cur.newData) if (!cur.isLocked() && !cur.isLoading && !cur.newData && !cur.isReady) {
&& (!cur.isReady) && (!tileInUse(cur))) {
clearTile(cur); clearTile(cur);
mTiles.remove(i); mTiles.remove(i);
@ -405,7 +378,7 @@ class TileLoader {
i++; i++;
} }
// Log.d(TAG, "remove tiles: " + removes + " " + size + " " + tmp); // Log.d(TAG, "remove tiles: " + removes + " " + size);
if (removes <= 0) if (removes <= 0)
return; return;
@ -413,35 +386,25 @@ class TileLoader {
updateTileDistances(mTiles, mapPosition); updateTileDistances(mTiles, mapPosition);
Collections.sort(mTiles); Collections.sort(mTiles);
// boolean printAll = false;
for (int i = 1; i <= removes; i++) { for (int i = 1; i <= removes; i++) {
MapTile t = mTiles.remove(size - i); MapTile t = mTiles.remove(size - i);
synchronized (t) { synchronized (t) {
if (t.isActive) { if (t.isLocked()) {
// dont remove tile used by renderthread // dont remove tile used by renderthread
Log.d(TAG, "X not removing active " + t + " " + t.distance); Log.d(TAG, "X not removing " + t + " " + t.isActive + " "
+ t.distance);
// if (printAll) {
// printAll = false;
// for (GLMapTile tt : mTiles)
// Log.d(TAG, ">>>" + tt + " " + tt.distance);
// }
mTiles.add(t);
} else if ((t.isReady || t.newData) && tileInUse(t)) {
// check if this tile could be used as proxy
Log.d(TAG, "X not removing proxy: " + t + " " + t.distance);
mTiles.add(t); mTiles.add(t);
} else if (t.isLoading) { } else if (t.isLoading) {
// FIXME !!! if we add tile back on next limit cache // FIXME if we add tile back on next limit cache
// this will be removed. clearTile could interfere with // this will be removed. clearTile could interfere with
// MapGenerator... clear in passTile(). // MapGenerator... clear in passTile().
Log.d(TAG, "X cancel loading " + t + " " + t.distance); Log.d(TAG, "X cancel loading " + t + " " + t.distance);
t.isLoading = false; t.isLoading = false;
// mTiles.add(t); // mTiles.add(t);
} else { } else {
clearTile(t); clearTile(t);
} }
@ -469,12 +432,13 @@ class TileLoader {
i++; i++;
} }
// clear loaded but not used tiles
if (size < MAX_TILES_IN_QUEUE) if (size < MAX_TILES_IN_QUEUE)
return; return;
// Log.d(TAG, "queue: " + mTilesLoaded.size() + " " + size + " " // Log.d(TAG, "queue: " + mTilesLoaded.size() + " " + size + " "
// + (size - MAX_TILES_IN_QUEUE / 2)); // + (size - MAX_TILES_IN_QUEUE / 2));
// clear loaded but not used tiles
for (int i = 0, n = size - MAX_TILES_IN_QUEUE / 2; i < n; n--) { for (int i = 0, n = size - MAX_TILES_IN_QUEUE / 2; i < n; n--) {
MapTile t = mTilesLoaded.get(i); MapTile t = mTilesLoaded.get(i);
@ -485,7 +449,7 @@ class TileLoader {
continue; continue;
} }
if (tileInUse(t)) { if (t.isLocked()) {
// Log.d(TAG, "keep unused tile data: " + t + " " + t.isActive); // Log.d(TAG, "keep unused tile data: " + t + " " + t.isActive);
i++; i++;
continue; continue;
@ -501,14 +465,70 @@ class TileLoader {
} }
/** /**
* Manage tiles that have data to be uploaded to gl * called from MapWorker Thread when tile is loaded by MapGenerator
* *
* @param tile * @param jobTile
* tile processed by MapGenerator * ...
* @return ...
*/ */
static void addTileLoaded(MapTile tile) { public synchronized boolean passTile(JobTile jobTile) {
MapTile tile = (MapTile) jobTile;
if (!tile.isLoading) {
// no one should be able to use this tile now, mapgenerator passed it,
// glthread does nothing until newdata is set.
Log.d(TAG, "passTile: canceled " + tile);
synchronized (mTilesLoaded) {
mTilesLoaded.add(tile);
}
return true;
}
mRenderer.setVBO(tile);
if (tile.vbo == null) {
Log.d(TAG, "no VBOs left for " + tile);
tile.isLoading = false;
return false;
}
tile.newData = true;
tile.isLoading = false;
if (!MapView.debugFrameTime)
requestRender();
synchronized (mTilesLoaded) { synchronized (mTilesLoaded) {
mTilesLoaded.add(tile); mTilesLoaded.add(tile);
} }
return true;
} }
public void setRenderTheme(RenderTheme t) {
if (mRenderer != null)
mRenderer.setRenderTheme(t);
}
private GLRenderer mRenderer;
@Override
public void onPause() {
super.onPause();
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
Log.d(TAG, "onSizeChanged" + w + " " + h);
mWidth = w;
mHeight = h;
if (mWidth > 0 && mHeight > 0)
mInitial = true;
super.onSizeChanged(w, h, oldw, oldh);
}
} }

View File

@ -0,0 +1,148 @@
/*
* 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.oscim.view.renderer;
import org.oscim.view.generator.JobTile;
class MapTile extends JobTile {
/**
* VBO layout: - 16 bytes fill coordinates, n bytes polygon vertices, m bytes lines vertices
*/
VertexBufferObject vbo;
/**
* polygonOffset in vbo is always 16 bytes,
*/
int lineOffset;
TextTexture texture;
/**
* Tile data set by MapGenerator:
*/
LineLayer lineLayers;
PolygonLayer polygonLayers;
TextItem labels;
/**
* tile is used by render thread. set by updateVisibleList (main thread).
*/
boolean isActive;
/**
* tile has new data to upload to gl
*/
boolean newData;
/**
* tile is loaded and ready for drawing.
*/
boolean isReady;
/**
* tile is in view region.
*/
boolean isVisible;
/**
* pointer to access relatives in TileTree
*/
QuadTree rel;
byte lastDraw = 0;
// keep track which tiles are locked as proxy for this tile
// 16: parent
// 32: grandparent
// 1-8: children
byte proxies;
// counting the tiles that use this tile as proxy
byte refs;
boolean isLocked() {
return isActive || refs > 0;
}
// void unref() {
// if (refs == 0) {
// Log.d("MapTile", "XXX already unrefd " + this);
// return;
// }
// refs--;
// }
//
// void ref() {
// refs++;
// }
void lock() {
isActive = true;
if (isReady || newData)
return;
MapTile p = rel.parent.tile;
if (p != null && (p.isReady || p.newData || p.isLoading)) {
proxies |= (1 << 4);
p.refs++;
} else {
p = rel.parent.parent.tile;
if (p != null && (p.isReady || p.newData || p.isLoading)) {
proxies |= (1 << 5);
p.refs++;
}
}
for (int j = 0; j < 4; j++) {
if (rel.child[j] != null) {
p = rel.child[j].tile;
if (p != null && (p.isReady || p.newData || p.isLoading)) {
proxies |= (1 << j);
p.refs++;
}
}
}
}
void unlock() {
isActive = false;
if (proxies == 0)
return;
if ((proxies & (1 << 4)) != 0) {
MapTile p = rel.parent.tile;
p.refs--;
} else if ((proxies & (1 << 5)) != 0) {
MapTile p = rel.parent.parent.tile;
p.refs--;
}
for (int i = 0; i < 4; i++) {
if ((proxies & (1 << i)) != 0) {
rel.child[i].tile.refs--;
}
}
proxies = 0;
}
MapTile(int tileX, int tileY, byte zoomLevel) {
super(tileX, tileY, zoomLevel);
}
}

View File

@ -12,13 +12,13 @@
* You should have received a copy of the GNU Lesser General License along with * You should have received a copy of the GNU Lesser General License along with
* this program. If not, see <http://www.gnu.org/licenses/>. * this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
package org.oscim.view.glrenderer; package org.oscim.view.renderer;
import org.oscim.core.Tile; import org.oscim.core.Tile;
import org.oscim.theme.renderinstruction.Area; import org.oscim.theme.renderinstruction.Area;
class PolygonLayer { class PolygonLayer {
private static final float S = MapRenderer.COORD_MULTIPLIER; private static final float S = GLRenderer.COORD_MULTIPLIER;
PolygonLayer next; PolygonLayer next;
Area area; Area area;

View File

@ -12,7 +12,7 @@
* You should have received a copy of the GNU Lesser General License along with * You should have received a copy of the GNU Lesser General License along with
* this program. If not, see <http://www.gnu.org/licenses/>. * this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
package org.oscim.view.glrenderer; package org.oscim.view.renderer;
import static android.opengl.GLES20.GL_BLEND; import static android.opengl.GLES20.GL_BLEND;
import static android.opengl.GLES20.GL_EQUAL; import static android.opengl.GLES20.GL_EQUAL;
@ -30,7 +30,6 @@ import static android.opengl.GLES20.glGetUniformLocation;
import static android.opengl.GLES20.glStencilFunc; import static android.opengl.GLES20.glStencilFunc;
import static android.opengl.GLES20.glStencilMask; import static android.opengl.GLES20.glStencilMask;
import static android.opengl.GLES20.glStencilOp; import static android.opengl.GLES20.glStencilOp;
import static android.opengl.GLES20.glUniform4f;
import static android.opengl.GLES20.glUniform4fv; import static android.opengl.GLES20.glUniform4fv;
import static android.opengl.GLES20.glUniformMatrix4fv; import static android.opengl.GLES20.glUniformMatrix4fv;
import static android.opengl.GLES20.glUseProgram; import static android.opengl.GLES20.glUseProgram;
@ -38,11 +37,11 @@ import static android.opengl.GLES20.glVertexAttribPointer;
import java.nio.ShortBuffer; import java.nio.ShortBuffer;
import org.oscim.view.utils.GlUtils; import org.oscim.utils.GlUtils;
import android.opengl.GLES20; import android.opengl.GLES20;
class PolygonLayers { class PolygonRenderer {
private static final int NUM_VERTEX_SHORTS = 2; private static final int NUM_VERTEX_SHORTS = 2;
private static final int POLYGON_VERTICES_DATA_POS_OFFSET = 0; private static final int POLYGON_VERTICES_DATA_POS_OFFSET = 0;
private static int STENCIL_BITS = 8; private static int STENCIL_BITS = 8;
@ -102,11 +101,8 @@ class PolygonLayers {
glEnable(GL_BLEND); glEnable(GL_BLEND);
blend = true; blend = true;
} }
glUniform4f(hPolygonColor,
l.area.color[0] * alpha, GlUtils.setColor(hPolygonColor, l.area.color, alpha);
l.area.color[1] * alpha,
l.area.color[2] * alpha,
alpha);
} else if (l.area.blend == zoom) { } else if (l.area.blend == zoom) {
// fade in/out // fade in/out
@ -116,10 +112,9 @@ class PolygonLayers {
else if (alpha < 0) else if (alpha < 0)
alpha = 0; alpha = 0;
glUniform4f(hPolygonColor, GlUtils.setBlendColors(hPolygonColor,
l.area.color[0] * (1 - alpha) + l.area.blendColor[0] * alpha, l.area.color, l.area.blendColor, alpha);
l.area.color[1] * (1 - alpha) + l.area.blendColor[1] * alpha,
l.area.color[2] * (1 - alpha) + l.area.blendColor[2] * alpha, 1);
} else { } else {
// draw solid // draw solid
if (blend) { if (blend) {
@ -132,6 +127,16 @@ class PolygonLayers {
glUniform4fv(hPolygonColor, 1, l.area.color, 0); glUniform4fv(hPolygonColor, 1, l.area.color, 0);
} }
// if (alpha < 1) {
// if (!blend) {
// glEnable(GL_BLEND);
// blend = true;
// }
// } else if (blend) {
// glDisable(GL_BLEND);
// blend = false;
// }
// set stencil buffer mask used to draw this layer // set stencil buffer mask used to draw this layer
glStencilFunc(GL_EQUAL, 0xff, 1 << c); glStencilFunc(GL_EQUAL, 0xff, 1 << c);
@ -200,6 +205,7 @@ class PolygonLayers {
// stencil op for stencil method polygon drawing // stencil op for stencil method polygon drawing
glStencilOp(GL_INVERT, GL_INVERT, GL_INVERT); glStencilOp(GL_INVERT, GL_INVERT, GL_INVERT);
glDisable(GLES20.GL_DEPTH_TEST); glDisable(GLES20.GL_DEPTH_TEST);
} }
mFillPolys[cnt] = l; mFillPolys[cnt] = l;

View File

@ -12,7 +12,7 @@
* You should have received a copy of the GNU Lesser General Public License along with * 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/>. * this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
package org.oscim.view.glrenderer; package org.oscim.view.renderer;
import android.util.Log; import android.util.Log;
@ -42,12 +42,12 @@ class QuadTree {
root = new QuadTree(); root = new QuadTree();
root.parent = root; root.parent = root;
QuadTree t; // QuadTree t;
for (int i = 0; i < 200; i++) { // for (int i = 0; i < 200; i++) {
t = new QuadTree(); // t = new QuadTree();
t.parent = pool; // t.parent = pool;
pool = t; // pool = t;
} // }
} }
static boolean remove(MapTile t) { static boolean remove(MapTile t) {

View File

@ -13,7 +13,7 @@
* this program. If not, see <http://www.gnu.org/licenses/>. * this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
package org.oscim.view.glrenderer; package org.oscim.view.renderer;
class Shaders { class Shaders {

View File

@ -12,7 +12,7 @@
* You should have received a copy of the GNU Lesser General Public License along with * 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/>. * this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
package org.oscim.view.glrenderer; package org.oscim.view.renderer;
public class ShortItem { public class ShortItem {
final short[] vertices; final short[] vertices;

View File

@ -12,7 +12,7 @@
* You should have received a copy of the GNU Lesser General Public License along with * 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/>. * this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
package org.oscim.view.glrenderer; package org.oscim.view.renderer;
import android.util.Log; import android.util.Log;

View File

@ -12,7 +12,7 @@
* You should have received a copy of the GNU Lesser General Public License along with * 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/>. * this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
package org.oscim.view.glrenderer; package org.oscim.view.renderer;
public class SymbolLayer { public class SymbolLayer {

View File

@ -12,7 +12,7 @@
* You should have received a copy of the GNU Lesser General Public License along with * 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/>. * this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
package org.oscim.view.glrenderer; package org.oscim.view.renderer;
import org.oscim.theme.renderinstruction.Caption; import org.oscim.theme.renderinstruction.Caption;
import org.oscim.theme.renderinstruction.PathText; import org.oscim.theme.renderinstruction.PathText;

View File

@ -12,13 +12,13 @@
* You should have received a copy of the GNU Lesser General Public License along with * 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/>. * this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
package org.oscim.view.glrenderer; package org.oscim.view.renderer;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import java.nio.ByteOrder; import java.nio.ByteOrder;
import java.nio.ShortBuffer; import java.nio.ShortBuffer;
import org.oscim.view.utils.GlUtils; import org.oscim.utils.GlUtils;
import android.graphics.Bitmap; import android.graphics.Bitmap;
import android.graphics.Canvas; import android.graphics.Canvas;
@ -188,6 +188,7 @@ public class TextRenderer {
tex = mTextures[i]; tex = mTextures[i];
if (tex.tile == null) if (tex.tile == null)
break; break;
if (!tex.tile.isActive) if (!tex.tile.isActive)
break; break;
@ -390,7 +391,8 @@ public class TextRenderer {
GLUtils.texSubImage2D(GLES20.GL_TEXTURE_2D, 0, 0, 0, mBitmap, GLUtils.texSubImage2D(GLES20.GL_TEXTURE_2D, 0, 0, 0, mBitmap,
mBitmapFormat, mBitmapType); mBitmapFormat, mBitmapType);
// GLES20.glFlush(); // FIXME shouldnt be needed here, still looking for sometimes corrupted labels..
GLES20.glFlush();
return true; return true;
} }

View File

@ -12,7 +12,7 @@
* You should have received a copy of the GNU Lesser General Public License along with * 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/>. * this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
package org.oscim.view.glrenderer; package org.oscim.view.renderer;
public class TextTexture { public class TextTexture {

View File

@ -12,8 +12,8 @@
* You should have received a copy of the GNU Lesser General Public License along with * 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/>. * this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
package org.oscim.view.swrenderer; package org.oscim.view.renderer;
public class TextureLayer {
enum ShapeType {
CIRCLE, WAY;
} }

View File

@ -13,7 +13,7 @@
* this program. If not, see <http://www.gnu.org/licenses/>. * this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
package org.oscim.view.glrenderer; package org.oscim.view.renderer;
class VertexBufferObject { class VertexBufferObject {
int id; int id;

View File

@ -12,10 +12,10 @@
* You should have received a copy of the GNU Lesser General Public License along with * 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/>. * this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
package org.oscim.view.glrenderer; package org.oscim.view.renderer;
import org.oscim.theme.renderinstruction.PathText; import org.oscim.theme.renderinstruction.PathText;
import org.oscim.view.utils.GeometryUtils; import org.oscim.utils.GeometryUtils;
import android.util.FloatMath; import android.util.FloatMath;

View File

@ -1,254 +0,0 @@
/*
* 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.oscim.view.swrenderer;
import java.util.List;
import org.oscim.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;
}
}

View File

@ -1,33 +0,0 @@
/*
* 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.oscim.view.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;
}
}

View File

@ -1,985 +0,0 @@
/*
* 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.oscim.view.swrenderer;
import java.util.ArrayList;
import java.util.Hashtable;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import org.oscim.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;
}
}
}
}

View File

@ -1,116 +0,0 @@
/*
* 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.oscim.view.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;
}
}

View File

@ -1,766 +0,0 @@
/*
* 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.oscim.view.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.oscim.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;
}
}

View File

@ -1,63 +0,0 @@
/*
* 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.oscim.view.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();
}
}
}
}

View File

@ -1,45 +0,0 @@
/*
* 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.oscim.view.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;
}
}

View File

@ -1,541 +0,0 @@
/*
* 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.oscim.view.swrenderer;
import java.util.ArrayList;
import java.util.List;
import org.oscim.core.Tag;
import org.oscim.core.Tile;
import org.oscim.database.IMapDatabase;
import org.oscim.database.IMapDatabaseCallback;
import org.oscim.database.mapfile.MapDatabase;
import org.oscim.theme.IRenderCallback;
import org.oscim.theme.RenderTheme;
import org.oscim.theme.renderinstruction.Area;
import org.oscim.theme.renderinstruction.Caption;
import org.oscim.theme.renderinstruction.Line;
import org.oscim.theme.renderinstruction.PathText;
import org.oscim.view.DebugSettings;
import org.oscim.view.MapView;
import org.oscim.view.mapgenerator.IMapGenerator;
import org.oscim.view.mapgenerator.JobTile;
import android.graphics.Bitmap;
import android.graphics.Color;
import android.graphics.Paint;
import android.util.FloatMath;
/**
* A DatabaseRenderer renders map tiles by reading from a {@link MapDatabase}.
*/
public class MapGenerator implements IMapGenerator, IRenderCallback,
IMapDatabaseCallback {
// private static String TAG = MapGenerator.class.getName();
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 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 Theme 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 JobTile mCurrentTile;
private static long mCurrentTileY;
private static long mCurrentTileX;
private static long mCurrentTileZoom;
private float[] mCoords = null;
// private long _renderTime;
private int _nodes, _nodesDropped;
private MapView mMapView;
/**
* Constructs a new DatabaseRenderer.
*
* @param mapView
* the MapView
*/
public MapGenerator(MapView mapView) {
mMapView = mapView;
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 (MapGenerator.renderTheme != null) {
MapGenerator.renderTheme.destroy();
}
}
@Override
public boolean executeJob(JobTile jobTile) {
long time_load = System.currentTimeMillis();
_nodes = 0;
_nodesDropped = 0;
// _renderTime = 0;
mCurrentTile = jobTile;
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();
// Theme theme = mapGeneratorJob.jobParameters.theme;
// if (!theme.equals(mPreviousJobTheme)) {
// // if (MapGenerator.renderTheme == null)
// // MapGenerator.renderTheme = getRenderTheme(theme);
// // if (MapGenerator.renderTheme == null) {
// // mPreviousJobTheme = null;
// // return false;
// // }
// createWayLists();
// mPreviousJobTheme = theme;
// mPreviousZoomLevel = Byte.MIN_VALUE;
// }
//
// byte zoomLevel = mCurrentTile.zoomLevel;
// if (zoomLevel != mPreviousZoomLevel) {
// setScaleStrokeWidth(zoomLevel);
// mPreviousZoomLevel = zoomLevel;
// }
//
// float textScale = mapGeneratorJob.jobParameters.textScale;
// if (textScale != mPreviousTextScale) {
// MapGenerator.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(MapGenerator.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;
DebugSettings debugSettings = mMapView.getDebugSettings();
if (debugSettings.mDrawTileFrames) {
mCanvasRasterer.drawTileFrame();
}
if (debugSettings.mDrawTileCoordinates) {
mCanvasRasterer.drawTileCoordinates(mCurrentTile, time_load, time_draw,
_nodes, _nodesDropped);
}
clearLists();
// mapGeneratorJob.setBitmap(mTileBitmap);
return true;
}
@Override
public void renderAreaCaption(Caption caption) {
// 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, float latitude, float longitude,
Tag[] tags) {
mDrawingLayer = mWays[getValidLayer(layer)];
mPoiX = scaleLongitude(longitude);
mPoiY = scaleLatitude(latitude);
MapGenerator.renderTheme.matchNode(this, tags, mCurrentTile.zoomLevel);
}
@Override
public void renderPointOfInterestCaption(Caption caption) {
// 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, short[] 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, int level) {
// List<ShapeContainer> c = mDrawingLayer.add(level, mWayDataContainer,
// line.paint);
//
// if (mCurLevelContainer1 == null)
// mCurLevelContainer1 = c;
// else if (mCurLevelContainer2 == null)
// mCurLevelContainer2 = c;
}
@Override
public void renderArea(Area area, int level) {
// if (area.paintFill != null)
// mCurLevelContainer1 = mDrawingLayer.add(level, mWayDataContainer,
// area.paintFill);
// if (area.paintOutline != null)
// mCurLevelContainer1 = mDrawingLayer.add(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(PathText pathText) {
// if (mWayDataContainer.textPos[0] >= 0)
// WayDecorator.renderText(this, paint, outline, mCoords, mWayDataContainer, mWayNames);
}
@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 = MapGenerator.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);
// MapGenerator.renderTheme.scaleStrokeWidth((float) Math.pow(STROKE_INCREASE,
// zoomLevelDiff));
// }
@Override
public IMapDatabase getMapDatabase() {
return mMapDatabase;
}
@Override
public void setRenderTheme(RenderTheme theme) {
// TODO Auto-generated method stub
}
@Override
public boolean checkWay(Tag[] tags, boolean closed) {
// TODO Auto-generated method stub
return false;
}
}

View File

@ -1,583 +0,0 @@
/*
* 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.oscim.view.swrenderer;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;
import java.util.ArrayList;
import java.util.Collections;
import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;
import org.oscim.core.MapPosition;
import org.oscim.core.MercatorProjection;
import org.oscim.core.Tile;
import org.oscim.theme.RenderTheme;
import org.oscim.view.MapView;
import org.oscim.view.mapgenerator.IMapGenerator;
import org.oscim.view.mapgenerator.JobTile;
import org.oscim.view.mapgenerator.TileDistanceSort;
import org.oscim.view.utils.GlUtils;
import android.opengl.GLES20;
import android.opengl.Matrix;
/**
*
*/
public class MapRenderer implements org.oscim.view.IMapRenderer {
// 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<JobTile> mJobList;
ArrayList<Integer> mTextures;
MapView mMapView;
MapTile[] currentTiles;
MapTile[] newTiles;
int currentTileCnt = 0;
// private TileCacheKey mTileCacheKey;
// private LinkedHashMap<TileCacheKey, GLMapTile> mTiles;
private ArrayList<MapTile> 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;
// 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<JobTile>();
// mTiles = new LinkedHashMap<TileCacheKey, GLMapTile>(100);
mTileList = new ArrayList<MapTile>();
// mTileCacheKey = new TileCacheKey();
mInitial = true;
}
private void limitCache(byte zoom, int remove) {
long x = mTileX;
long y = mTileY;
int diff;
for (MapTile 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++) {
MapTile 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(Integer.valueOf(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;
int tileLeft = MercatorProjection.pixelXToTileX(pixelLeft, zoomLevel);
int tileTop = MercatorProjection.pixelYToTileY(pixelTop, zoomLevel);
int tileRight = MercatorProjection.pixelXToTileX(pixelRight, zoomLevel);
int tileBottom = MercatorProjection.pixelYToTileY(pixelBottom, zoomLevel);
mJobList.clear();
// IMapGenerator mapGenerator = mMapView.getMapGenerator();
int tiles = 0;
for (int tileY = tileTop - 1; tileY <= tileBottom + 1; tileY++) {
for (int 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.isReady || (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, mJobParameter,
// mDebugSettings);
// job.setScale(scale);
// mJobList.add(job);
// }
}
}
synchronized (this) {
limitCache(zoomLevel, (mTileList.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.addJobs(mJobList);
// }
return true;
}
/**
*
*/
@Override
public synchronized void updateMap(boolean clear) {
boolean update = false;
mMapPosition = mMapView.getMapPosition().getMapPosition();
long x = (long) MercatorProjection.longitudeToPixelX(mMapPosition);
long y = (long) MercatorProjection.latitudeToPixelY(mMapPosition);
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(JobTile jobTile) {
// mMapGeneratorJob = mapGeneratorJob;
processedTile = false;
mMapView.requestRender();
return true;
}
private boolean drawTile(MapTile 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);
MapTile 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.isReady = 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);
// }
// }
// }
// }
}
@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 MapTile[tiles];
newTiles = new MapTile[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;
// }
@Override
public IMapGenerator createMapGenerator() {
return new MapGenerator(mMapView);
}
@Override
public void setRenderTheme(RenderTheme t) {
// TODO Auto-generated method stub
}
}

View File

@ -1,84 +0,0 @@
/*
* 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.oscim.view.swrenderer;
import org.oscim.view.mapgenerator.JobTile;
/**
*
*/
public class MapTile extends JobTile {
private float mScale;
final MapTile[] child = { null, null, null, null };
MapTile parent;
// private long mLoadTime;
private int mTextureID;
boolean isVisible;
/**
* @param tileX
* ...
* @param tileY
* ...
* @param zoomLevel
* ..
*/
public MapTile(int tileX, int tileY, byte zoomLevel) {
super(tileX, tileY, zoomLevel);
mScale = 1;
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;
}
}

View File

@ -1,115 +0,0 @@
/*
* 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.oscim.view.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);
}
}
}

View File

@ -1,19 +0,0 @@
/*
* 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.oscim.view.swrenderer;
interface ShapeContainer {
ShapeType getShapeType();
}

View File

@ -1,29 +0,0 @@
/*
* 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.oscim.view.swrenderer;
import android.graphics.Paint;
class ShapePaintContainer {
public Paint paint;
public ShapeContainer shapeContainer;
public ShapePaintContainer next;
ShapePaintContainer(ShapeContainer shapeContainer, Paint paint) {
this.shapeContainer = shapeContainer;
this.paint = paint;
}
}

View File

@ -1,61 +0,0 @@
/*
* 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.oscim.view.swrenderer;
import android.graphics.Bitmap;
class SymbolContainer {
final boolean alignCenter;
final float rotation;
final Bitmap symbol;
final float x;
final float y;
/**
* Creates a new symbol container. The symbol will not be centered.
*
* @param symbol
* the symbol to render at the point
* @param x
* the x coordinate of the point.
* @param y
* the y coordinate of the point.
*/
SymbolContainer(Bitmap symbol, float x, float y) {
this(symbol, x, y, false, 0);
}
/**
* Creates a new symbol container.
*
* @param symbol
* the symbol to render at the point
* @param x
* the x coordinate of the point.
* @param y
* the y coordinate of the point.
* @param alignCenter
* true if the symbol should be centered, false otherwise.
* @param rotation
* the rotation of the symbol.
*/
SymbolContainer(Bitmap symbol, float x, float y, boolean alignCenter, float rotation) {
this.symbol = symbol;
this.x = x;
this.y = y;
this.alignCenter = alignCenter;
this.rotation = rotation;
}
}

View File

@ -1,34 +0,0 @@
/*
* 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.oscim.view.swrenderer;
class WayDataContainer implements ShapeContainer {
// position and length of float coordinates
int[] position;
int[] length;
int[] textPos;
WayDataContainer(int size) {
length = new int[size];
position = new int[size];
}
@Override
public ShapeType getShapeType() {
return ShapeType.WAY;
}
}

View File

@ -1,300 +0,0 @@
/*
* 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.oscim.view.swrenderer;
import java.util.List;
import org.oscim.view.utils.GeometryUtils;
import android.graphics.Bitmap;
import android.graphics.Paint;
import android.util.Log;
final class WayDecorator {
/**
* Minimum distance in pixels before the symbol is repeated.
*/
private static final int DISTANCE_BETWEEN_SYMBOLS = 200;
/**
* Minimum distance in pixels before the way name is repeated.
*/
private static final int DISTANCE_BETWEEN_WAY_NAMES = 500;
/**
* Distance in pixels to skip from both ends of a segment.
*/
private static final int SEGMENT_SAFETY_DISTANCE = 30;
static void renderSymbol(Bitmap symbolBitmap, boolean alignCenter,
boolean repeatSymbol, float[][] coordinates,
List<SymbolContainer> waySymbols) {
int skipPixels = SEGMENT_SAFETY_DISTANCE;
// get the first way point coordinates
float previousX = coordinates[0][0];
float previousY = coordinates[0][1];
// draw the symbol on each way segment
float segmentLengthRemaining;
float segmentSkipPercentage;
float symbolAngle;
for (int i = 2; i < coordinates[0].length; i += 2) {
// get the current way point coordinates
float currentX = coordinates[0][i];
float currentY = coordinates[0][i + 1];
// calculate the length of the current segment (Euclidian distance)
float diffX = currentX - previousX;
float diffY = currentY - previousY;
double segmentLengthInPixel = Math.sqrt(diffX * diffX + diffY * diffY);
segmentLengthRemaining = (float) segmentLengthInPixel;
while (segmentLengthRemaining - skipPixels > SEGMENT_SAFETY_DISTANCE) {
// calculate the percentage of the current segment to skip
segmentSkipPercentage = skipPixels / segmentLengthRemaining;
// move the previous point forward towards the current point
previousX += diffX * segmentSkipPercentage;
previousY += diffY * segmentSkipPercentage;
symbolAngle = (float) Math.toDegrees(Math.atan2(currentY - previousY,
currentX - previousX));
waySymbols.add(new SymbolContainer(symbolBitmap, previousX, previousY,
alignCenter, symbolAngle));
// check if the symbol should only be rendered once
if (!repeatSymbol) {
return;
}
// recalculate the distances
diffX = currentX - previousX;
diffY = currentY - previousY;
// recalculate the remaining length of the current segment
segmentLengthRemaining -= skipPixels;
// set the amount of pixels to skip before repeating the symbol
skipPixels = DISTANCE_BETWEEN_SYMBOLS;
}
skipPixels -= segmentLengthRemaining;
if (skipPixels < SEGMENT_SAFETY_DISTANCE) {
skipPixels = SEGMENT_SAFETY_DISTANCE;
}
// set the previous way point coordinates for the next loop
previousX = currentX;
previousY = currentY;
}
}
static void renderText(MapGenerator mapGenerator, Paint paint, Paint outline,
float[] coordinates, WayDataContainer wayDataContainer,
List<WayTextContainer> wayNames) {
int pos = wayDataContainer.position[0];
int len = wayDataContainer.length[0];
// int coordinatesLength
String text = null;
// calculate the way name length plus some margin of safety
float wayNameWidth = -1; // paint.measureText(textKey) + 5;
float minWidth = 100;
int skipPixels = 0;
// get the first way point coordinates
int previousX = (int) coordinates[pos + 0];
int previousY = (int) coordinates[pos + 1];
int containerSize = -1;
// find way segments long enough to draw the way name on them
for (int i = pos + 2; i < pos + len; i += 2) {
// get the current way point coordinates
int currentX = (int) coordinates[i];
int currentY = (int) coordinates[i + 1];
int first = i - 2;
int last = i;
// calculate the length of the current segment (Euclidian distance)
int diffX = currentX - previousX;
int diffY = currentY - previousY;
for (int j = i + 2; j < pos + len; j += 2) {
int nextX = (int) coordinates[j];
int nextY = (int) coordinates[j + 1];
if (diffY == 0) {
if ((currentY - nextY) != 0)
break;
currentX = nextX;
currentY = nextY;
last = j;
continue;
} else if ((currentY - nextY) == 0)
break;
float diff = ((float) (diffX) / (diffY) - (float) (currentX - nextX)
/ (currentY - nextY));
// skip segments with corners
if (diff >= 0.2 || diff <= -0.2)
break;
currentX = nextX;
currentY = nextY;
last = j;
}
diffX = currentX - previousX;
diffY = currentY - previousY;
if (diffX < 0)
diffX = -diffX;
if (diffY < 0)
diffY = -diffY;
if (diffX + diffY < minWidth) {
previousX = currentX;
previousY = currentY;
continue;
}
if (wayNameWidth > 0 && diffX + diffY < wayNameWidth) {
previousX = currentX;
previousY = currentY;
continue;
}
double segmentLengthInPixel = Math.sqrt(diffX * diffX + diffY * diffY);
if (skipPixels > 0) {
skipPixels -= segmentLengthInPixel;
} else if (segmentLengthInPixel > minWidth) {
if (wayNameWidth < 0) {
if (text == null) {
// text = mapGenerator.getWayName();
// if (text == null)
text = "blub";
}
wayNameWidth = (paint.measureText(text) + 10);
}
if (segmentLengthInPixel > wayNameWidth) {
double s = (wayNameWidth + 10) / segmentLengthInPixel;
int width, height;
int x1, y1, x2, y2;
if (previousX < currentX) {
x1 = previousX;
y1 = previousY;
x2 = currentX;
y2 = currentY;
} else {
x1 = currentX;
y1 = currentY;
x2 = previousX;
y2 = previousY;
}
// estimate position of text on path
width = (x2 - x1) / 2;
x2 = x2 - (int) (width - s * width);
x1 = x1 + (int) (width - s * width);
height = (y2 - y1) / 2;
y2 = y2 - (int) (height - s * height);
y1 = y1 + (int) (height - s * height);
short top = (short) (y1 < y2 ? y1 : y2);
short bot = (short) (y1 < y2 ? y2 : y1);
boolean intersects = false;
if (containerSize == -1)
containerSize = wayNames.size();
for (int k = 0; k < containerSize; k++) {
WayTextContainer wtc2 = wayNames.get(k);
if (!wtc2.match)
// outline (not 'match') are appended to the end;
break;
// check crossings
if (GeometryUtils.lineIntersect(x1, y1, x2, y2, wtc2.x1, wtc2.y1,
wtc2.x2, wtc2.y2)) {
intersects = true;
break;
}
// check overlapping labels of road with more than one
// way
short top2 = (wtc2.y1 < wtc2.y2 ? wtc2.y1 : wtc2.y2);
short bot2 = (wtc2.y1 < wtc2.y2 ? wtc2.y2 : wtc2.y1);
if (x1 - 10 < wtc2.x2 && wtc2.x1 - 10 < x2 && top - 10 < bot2
&& top2 - 10 < bot) {
if (wtc2.text.equals(text)) {
intersects = true;
break;
}
}
}
if (intersects) {
previousX = (int) coordinates[pos + i];
previousY = (int) coordinates[pos + i + 1];
continue;
}
Log.d("mapsforge", "add " + text + " " + first + " " + last);
WayTextContainer wtc = new WayTextContainer(first, last,
wayDataContainer, text,
paint);
wtc.x1 = (short) x1;
wtc.y1 = (short) y1;
wtc.x2 = (short) x2;
wtc.y2 = (short) y2;
wtc.match = true;
wayNames.add(0, wtc);
containerSize++;
if (outline != null) {
wayNames.add(new WayTextContainer(first, last, wayDataContainer,
text, outline));
containerSize++;
}
// 500 ??? how big is a tile?!
skipPixels = DISTANCE_BETWEEN_WAY_NAMES;
}
}
// store the previous way point coordinates
previousX = currentX;
previousY = currentY;
}
}
private WayDecorator() {
throw new IllegalStateException();
}
}

View File

@ -1,37 +0,0 @@
/*
* 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.oscim.view.swrenderer;
import android.graphics.Paint;
class WayTextContainer {
final WayDataContainer wayDataContainer;
final int first;
final int last;
final Paint paint;
final String text;
short x1, y1, x2, y2;
boolean match;
WayTextContainer(int first, int last, WayDataContainer wayDataContainer, String text, Paint paint) {
this.wayDataContainer = wayDataContainer;
this.first = first;
this.last = last;
this.text = text;
this.paint = paint;
this.match = false;
}
}