diff --git a/settings.gradle b/settings.gradle
index 4d7adb71e..704fd5738 100644
--- a/settings.gradle
+++ b/settings.gradle
@@ -9,9 +9,9 @@ include ':vtm-themes'
include ':vtm-gdx'
include ':vtm-desktop'
include ':vtm-android-gdx'
-include ':vtm-web'
-include ':vtm-web-app'
-include ':vtm-web-js'
+//include ':vtm-web'
+//include ':vtm-web-app'
+//include ':vtm-web-js'
include ':vtm-jeo'
include ':vtm-jeo-desktop'
include ':vtm-playground'
diff --git a/vtm-android-example/AndroidManifest.xml b/vtm-android-example/AndroidManifest.xml
index 5f2a9918a..2684729e4 100644
--- a/vtm-android-example/AndroidManifest.xml
+++ b/vtm-android-example/AndroidManifest.xml
@@ -15,8 +15,8 @@
-
+ android:label="@string/app_name"
+ android:theme="@style/AppTheme" >
@@ -72,6 +72,12 @@
android:name="org.oscim.android.test.OsmJsonMapActivity"
android:label="@string/title_activity_map" >
-
+
+
+
+
+
\ No newline at end of file
diff --git a/vtm-android-example/build.gradle b/vtm-android-example/build.gradle
index 5aa737fb6..87993bcb1 100644
--- a/vtm-android-example/build.gradle
+++ b/vtm-android-example/build.gradle
@@ -11,7 +11,8 @@ dependencies {
compile project(':vtm-extras')
compile project(':vtm-themes')
- compile 'com.android.support:support-v4:21.+'
+ compile 'com.android.support:support-v4:22.+'
+ compile 'com.android.support:appcompat-v7:22.+'
eclipseCompile project(':appcompat')
compile 'com.noveogroup.android:android-logger:1.3.4'
diff --git a/vtm-android-example/res/layout/activity_map_styler.xml b/vtm-android-example/res/layout/activity_map_styler.xml
index 1f622be23..875d1b801 100644
--- a/vtm-android-example/res/layout/activity_map_styler.xml
+++ b/vtm-android-example/res/layout/activity_map_styler.xml
@@ -26,7 +26,7 @@
android:id="@+id/controls"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
- android:background="#cc000000"
+ android:background="#ccdddddd"
android:orientation="vertical"
android:paddingLeft="10dp"
android:paddingRight="10dp"
diff --git a/vtm-android-example/res/values/styles.xml b/vtm-android-example/res/values/styles.xml
index 8e0a2292e..76c49238d 100644
--- a/vtm-android-example/res/values/styles.xml
+++ b/vtm-android-example/res/values/styles.xml
@@ -1,5 +1,5 @@
-
+
\ No newline at end of file
diff --git a/vtm-android-example/src/org/oscim/android/test/BaseMapActivity.java b/vtm-android-example/src/org/oscim/android/test/BaseMapActivity.java
index c807de293..9cfac3679 100644
--- a/vtm-android-example/src/org/oscim/android/test/BaseMapActivity.java
+++ b/vtm-android-example/src/org/oscim/android/test/BaseMapActivity.java
@@ -16,8 +16,6 @@
*/
package org.oscim.android.test;
-import org.oscim.android.MapActivity;
-import org.oscim.android.MapView;
import org.oscim.android.cache.TileCache;
import org.oscim.core.MapPosition;
import org.oscim.layers.TileGridLayer;
@@ -37,30 +35,22 @@ public class BaseMapActivity extends MapActivity {
final static boolean USE_CACHE = true;
- MapView mMapView;
VectorTileLayer mBaseLayer;
TileSource mTileSource;
TileGridLayer mGridLayer;
private TileCache mCache;
- protected final int mContentView;
-
public BaseMapActivity(int contentView) {
- mContentView = contentView;
+ super(contentView);
}
public BaseMapActivity() {
- this(R.layout.activity_map);
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
- setContentView(mContentView);
-
- mMapView = (MapView) findViewById(R.id.mapView);
- registerMapView(mMapView);
mTileSource = new OSciMap4TileSource();
@@ -76,7 +66,6 @@ public void onCreate(Bundle savedInstanceState) {
mMap.getMapPosition(pos);
if (pos.x == 0.5 && pos.y == 0.5)
mMap.setMapPosition(53.08, 8.83, Math.pow(2, 16));
-
}
@Override
@@ -88,7 +77,7 @@ protected void onDestroy() {
}
@Override
- public boolean onMenuItemSelected(int featureId, MenuItem item) {
+ public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.theme_default:
diff --git a/vtm-android-example/src/org/oscim/android/test/BitmapTileMapActivity.java b/vtm-android-example/src/org/oscim/android/test/BitmapTileMapActivity.java
index 602a580df..c92ee595a 100644
--- a/vtm-android-example/src/org/oscim/android/test/BitmapTileMapActivity.java
+++ b/vtm-android-example/src/org/oscim/android/test/BitmapTileMapActivity.java
@@ -14,8 +14,6 @@
*/
package org.oscim.android.test;
-import org.oscim.android.MapActivity;
-import org.oscim.android.MapView;
import org.oscim.android.cache.TileCache;
import org.oscim.backend.canvas.Color;
import org.oscim.core.MapPosition;
@@ -23,44 +21,51 @@
import org.oscim.layers.TileGridLayer;
import org.oscim.layers.tile.bitmap.BitmapTileLayer;
import org.oscim.renderer.MapRenderer;
-import org.oscim.tiling.TileSource;
+import org.oscim.tiling.source.bitmap.BitmapTileSource;
import org.oscim.tiling.source.bitmap.DefaultSources;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
import android.os.Bundle;
public class BitmapTileMapActivity extends MapActivity {
+ static final Logger log = LoggerFactory.getLogger(BitmapTileMapActivity.class);
+
private final static boolean USE_CACHE = true;
- private final TileSource mTileSource;
+ private final BitmapTileSource mTileSource;
protected BitmapTileLayer mBitmapLayer;
public BitmapTileMapActivity() {
- //mTileSource = DefaultSources.STAMEN_TONER.build();
- mTileSource = DefaultSources.OPENSTREETMAP.build();
+ this(DefaultSources.OPENSTREETMAP.build());
}
- public BitmapTileMapActivity(TileSource tileSource) {
+ public BitmapTileMapActivity(BitmapTileSource tileSource) {
+ super(R.layout.activity_map);
mTileSource = tileSource;
}
- MapView mMapView;
-
private TileCache mCache;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_map);
-
- mMapView = (MapView) findViewById(R.id.mapView);
- registerMapView(mMapView);
MapRenderer.setBackgroundColor(0xff777777);
mMap.layers().add(new TileGridLayer(mMap, Color.GRAY, 1.8f, 8));
+ if (mTileSource == null)
+ return;
+
if (USE_CACHE) {
- mCache = new TileCache(this, null, mTileSource.getClass().getSimpleName());
+ String cacheFile = mTileSource.getUrl()
+ .toString()
+ .replaceFirst("https?://", "")
+ .replaceAll("/", "-");
+
+ log.debug("use bitmap cache {}", cacheFile);
+ mCache = new TileCache(this, null, cacheFile);
mCache.setCacheSize(512 * (1 << 10));
mTileSource.setCache(mCache);
}
@@ -74,7 +79,7 @@ public void onCreate(Bundle savedInstanceState) {
@Override
protected void onDestroy() {
super.onDestroy();
- if (USE_CACHE)
+ if (mCache != null)
mCache.dispose();
}
diff --git a/vtm-android-example/src/org/oscim/android/test/MapActivity.java b/vtm-android-example/src/org/oscim/android/test/MapActivity.java
new file mode 100644
index 000000000..841cb9ad0
--- /dev/null
+++ b/vtm-android-example/src/org/oscim/android/test/MapActivity.java
@@ -0,0 +1,53 @@
+package org.oscim.android.test;
+
+import org.oscim.android.MapPreferences;
+import org.oscim.android.MapView;
+import org.oscim.map.Map;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import android.os.Bundle;
+import android.support.v7.app.ActionBarActivity;
+
+public abstract class MapActivity extends ActionBarActivity {
+ public static final Logger log = LoggerFactory.getLogger(MapActivity.class);
+ MapView mMapView;
+ Map mMap;
+ MapPreferences mPrefs;
+
+ protected final int mContentView;
+
+ public MapActivity(int contentView) {
+ mContentView = contentView;
+ }
+
+ public MapActivity() {
+ this(R.layout.activity_map);
+ }
+
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(mContentView);
+
+ mMapView = (MapView) findViewById(R.id.mapView);
+ mMap = mMapView.map();
+ mPrefs = new MapPreferences(MapActivity.class.getName(), this);
+ }
+
+ @Override
+ protected void onResume() {
+ super.onResume();
+
+ mPrefs.load(mMapView.map());
+ mMapView.onResume();
+ }
+
+ @Override
+ protected void onPause() {
+ super.onPause();
+
+ mMapView.onPause();
+ mPrefs.save(mMapView.map());
+ }
+
+}
diff --git a/vtm-android-example/src/org/oscim/android/test/MapsforgeMapActivity.java b/vtm-android-example/src/org/oscim/android/test/MapsforgeMapActivity.java
index 436151b7c..c93914165 100644
--- a/vtm-android-example/src/org/oscim/android/test/MapsforgeMapActivity.java
+++ b/vtm-android-example/src/org/oscim/android/test/MapsforgeMapActivity.java
@@ -14,7 +14,6 @@
*/
package org.oscim.android.test;
-import org.oscim.android.MapActivity;
import org.oscim.android.MapView;
import org.oscim.android.filepicker.FilePicker;
import org.oscim.android.filepicker.FilterByFileExtension;
@@ -42,10 +41,6 @@ public class MapsforgeMapActivity extends MapActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_map);
-
- mMapView = (MapView) findViewById(R.id.mapView);
- registerMapView(mMapView);
startActivityForResult(new Intent(this, MapFilePicker.class),
SELECT_MAP_FILE);
@@ -65,7 +60,7 @@ public boolean onCreateOptionsMenu(Menu menu) {
}
@Override
- public boolean onMenuItemSelected(int featureId, MenuItem item) {
+ public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.theme_default:
diff --git a/vtm-android-example/src/org/oscim/android/test/MarkerOverlayActivity.java b/vtm-android-example/src/org/oscim/android/test/MarkerOverlayActivity.java
index a0c098780..043870dab 100644
--- a/vtm-android-example/src/org/oscim/android/test/MarkerOverlayActivity.java
+++ b/vtm-android-example/src/org/oscim/android/test/MarkerOverlayActivity.java
@@ -84,7 +84,14 @@ public void onCreate(Bundle savedInstanceState) {
markerLayer.addItems(pts);
mMap.layers().add(new TileGridLayer(mMap));
- mMap.setMapPosition(0, 0, 1);
+ }
+
+ @Override
+ protected void onResume() {
+ super.onResume();
+ /* ignore saved position */
+ mMap.setMapPosition(0, 0, 1 << 2);
+ mMapView.onResume();
}
@Override
diff --git a/vtm-android-example/src/org/oscim/android/test/OsmJsonMapActivity.java b/vtm-android-example/src/org/oscim/android/test/OsmJsonMapActivity.java
index ccf6d7f62..d8cad18fa 100644
--- a/vtm-android-example/src/org/oscim/android/test/OsmJsonMapActivity.java
+++ b/vtm-android-example/src/org/oscim/android/test/OsmJsonMapActivity.java
@@ -16,7 +16,6 @@
import static org.oscim.tiling.source.bitmap.DefaultSources.STAMEN_TONER;
-import org.oscim.android.MapActivity;
import org.oscim.android.MapView;
import org.oscim.layers.TileGridLayer;
import org.oscim.layers.tile.bitmap.BitmapTileLayer;
@@ -43,10 +42,6 @@ public class OsmJsonMapActivity extends MapActivity {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_map);
-
- mMapView = (MapView) findViewById(R.id.mapView);
- registerMapView(mMapView);
mTileSource = new OsmWaterJsonTileSource();
diff --git a/vtm-android-example/src/org/oscim/android/test/PathOverlayActivity.java b/vtm-android-example/src/org/oscim/android/test/PathOverlayActivity.java
index f4b85d5ec..985664ae3 100644
--- a/vtm-android-example/src/org/oscim/android/test/PathOverlayActivity.java
+++ b/vtm-android-example/src/org/oscim/android/test/PathOverlayActivity.java
@@ -16,70 +16,74 @@
*/
package org.oscim.android.test;
-import static org.oscim.tiling.source.bitmap.DefaultSources.STAMEN_TONER;
-
import java.util.ArrayList;
-import java.util.List;
import org.oscim.backend.canvas.Color;
-import org.oscim.core.GeoPoint;
+import org.oscim.core.MapPosition;
+import org.oscim.event.Event;
import org.oscim.layers.PathLayer;
+import org.oscim.map.Map.UpdateListener;
import android.os.Bundle;
-import android.os.SystemClock;
+/**
+ * This is a very INEFFICIENT and somewhat less usefull example for how to use
+ * PathLayers!
+ */
public class PathOverlayActivity extends BitmapTileMapActivity {
public PathOverlayActivity() {
- super(STAMEN_TONER.build());
+ //super(STAMEN_TONER.build());
+ super(null);
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
- mBitmapLayer.tileRenderer().setBitmapAlpha(0.5f);
-
- createLayers(1, true);
+ //mBitmapLayer.tileRenderer().setBitmapAlpha(0.5f);
mMap.setMapPosition(0, 0, 1 << 2);
+ for (double lat = -90; lat <= 90; lat += 5) {
+ int c = Color.fade(Color.rainbow((float) (lat + 90) / 180), 0.5f);
+ PathLayer pathLayer = new PathLayer(mMap, c, 6);
+ mMap.layers().add(pathLayer);
+ mPathLayers.add(pathLayer);
+ }
- looooop();
- }
-
- void looooop() {
- mMap.postDelayed(new Runnable() {
+ mMap.events.bind(new UpdateListener() {
@Override
- public void run() {
- long t = SystemClock.uptimeMillis();
+ public void onMapEvent(Event e, MapPosition mapPosition) {
+ //if (e == Map.UPDATE_EVENT) {
+ long t = System.currentTimeMillis();
float pos = t % 20000 / 10000f - 1f;
- createLayers(pos, false);
- //Samples.log.debug("update took" + (SystemClock.uptimeMillis() - t) + " " + pos);
- looooop();
- redraw();
+ createLayers(pos);
+
+ mMap.updateMap(true);
+ //}
}
- }, 50);
+ });
}
- void redraw() {
- mMap.render();
+ @Override
+ protected void onResume() {
+ super.onResume();
+ /* ignore saved position */
+ mMap.setMapPosition(0, 0, 1 << 2);
+ mMapView.onResume();
}
ArrayList mPathLayers = new ArrayList();
- void createLayers(float pos, boolean init) {
+ void createLayers(float pos) {
int i = 0;
-
for (double lat = -90; lat <= 90; lat += 5) {
- List pts = new ArrayList();
-
+ double[] packedCoordinates = new double[360 + 2];
+ //List pts = new ArrayList();
+ int c = 0;
for (double lon = -180; lon <= 180; lon += 2) {
//pts.add(new GeoPoint(lat, lon));
- double longitude = lon + (pos * 180);
- if (longitude < -180)
- longitude += 360;
- if (longitude > 180)
- longitude -= 360;
+ double longitude = lon;
double latitude = lat + (pos * 90);
if (latitude < -90)
@@ -89,20 +93,15 @@ void createLayers(float pos, boolean init) {
latitude += Math.sin((Math.abs(pos) * (lon / Math.PI)));
- pts.add(new GeoPoint(latitude, longitude));
- }
- PathLayer pathLayer;
- if (init) {
- int c = Color.fade(Color.rainbow((float) (lat + 90) / 180), 0.5f);
- pathLayer = new PathLayer(mMap, c, 6);
- mMap.layers().add(pathLayer);
- mPathLayers.add(pathLayer);
- } else {
- pathLayer = mPathLayers.get(i++);
+ packedCoordinates[c++] = longitude;
+ packedCoordinates[c++] = latitude;
}
- pathLayer.setPoints(pts);
- }
+ //LineString line = new LineString(factory.create(packedCoordinates, 2), geomFactory);
+ //mPathLayers.get(i++).setLineString(line);
+ mPathLayers.get(i++).setLineString(packedCoordinates);
+
+ }
}
}
diff --git a/vtm-android-example/src/org/oscim/android/test/Samples.java b/vtm-android-example/src/org/oscim/android/test/Samples.java
index 8312f753e..dbda24243 100644
--- a/vtm-android-example/src/org/oscim/android/test/Samples.java
+++ b/vtm-android-example/src/org/oscim/android/test/Samples.java
@@ -49,6 +49,7 @@ protected void onCreate(Bundle savedInstanceState) {
linearLayout.addView(createButton(S3DBMapActivity.class));
linearLayout.addView(createButton(JeoIndoorMapActivity.class));
linearLayout.addView(createButton(OsmJsonMapActivity.class));
+ linearLayout.addView(createButton(VectorLayerMapActivity.class));
}
private Button createButton(final Class> clazz) {
diff --git a/vtm-android-example/src/org/oscim/android/test/SimpleMapActivity.java b/vtm-android-example/src/org/oscim/android/test/SimpleMapActivity.java
index 37f3cbf32..dfbde7d88 100644
--- a/vtm-android-example/src/org/oscim/android/test/SimpleMapActivity.java
+++ b/vtm-android-example/src/org/oscim/android/test/SimpleMapActivity.java
@@ -21,7 +21,6 @@
import org.oscim.layers.tile.buildings.BuildingLayer;
import org.oscim.layers.tile.vector.labeling.LabelLayer;
import org.oscim.map.Layers;
-import org.oscim.map.Map;
import org.oscim.theme.IRenderTheme;
import org.oscim.theme.ThemeLoader;
import org.oscim.theme.VtmThemes;
@@ -33,14 +32,13 @@ public class SimpleMapActivity extends BaseMapActivity {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
- Map m = this.map();
Layers layers = mMap.layers();
layers.add(new BuildingLayer(mMap, mBaseLayer));
layers.add(new LabelLayer(mMap, mBaseLayer));
layers.add(new MapScaleBar(mMapView));
- m.setTheme(VtmThemes.DEFAULT);
+ mMap.setTheme(VtmThemes.DEFAULT);
}
void runTheMonkey() {
diff --git a/vtm-android-example/src/org/oscim/android/test/VectorLayerMapActivity.java b/vtm-android-example/src/org/oscim/android/test/VectorLayerMapActivity.java
new file mode 100644
index 000000000..4f7c486b4
--- /dev/null
+++ b/vtm-android-example/src/org/oscim/android/test/VectorLayerMapActivity.java
@@ -0,0 +1,95 @@
+/*
+ * Copyright 2013 Hannes Janetzek
+ *
+ * This file is part of the OpenScienceMap project (http://www.opensciencemap.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 .
+ */package org.oscim.android.test;
+
+import org.oscim.backend.canvas.Color;
+import org.oscim.layers.TileGridLayer;
+import org.oscim.layers.vector.VectorLayer;
+import org.oscim.layers.vector.geometries.PointDrawable;
+import org.oscim.layers.vector.geometries.Style;
+import org.oscim.theme.VtmThemes;
+import org.oscim.utils.ColorUtil;
+
+import android.os.Bundle;
+
+public class VectorLayerMapActivity extends BaseMapActivity {
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ mMap.setTheme(VtmThemes.NEWTRON);
+
+ VectorLayer vectorLayer = new VectorLayer(mMap);
+
+ // Geometry g = new GeomBuilder()
+ // .point(8.8, 53.1)
+ // .point()
+ // .buffer(1)
+ // .get();
+ //
+ // vectorLayer.add(new PolygonDrawable(g, defaultStyle()));
+ //
+ // vectorLayer.add(new PointDrawable(53.1, 8.8, Style.builder()
+ // .setBuffer(0.5)
+ // .setFillColor(Color.RED)
+ // .setFillAlpha(0.2)
+ // .build()));
+ //
+ // Style.Builder sb = Style.builder()
+ // .setBuffer(0.5)
+ // .setFillColor(Color.RED)
+ // .setFillAlpha(0.2);
+ //
+ // Style style = sb.setFillAlpha(0.2).build();
+ //
+ // int tileSize = 5;
+ // for (int x = -180; x < 180; x += tileSize) {
+ // for (int y = -90; y < 90; y += tileSize) {
+ // // Style style = sb.setFillAlpha(FastMath.clamp(FastMath.length(x, y) / 180, 0.2, 1))
+ // // .build();
+ //
+ // vectorLayer.add(new RectangleDrawable(FastMath.clamp(y, -85, 85), x,
+ // FastMath.clamp(y + tileSize - 0.1, -85, 85),
+ // x + tileSize - 0.1, style));
+ //
+ // }
+ // }
+
+ Style.Builder sb = Style.builder()
+ .buffer(0.5)
+ .fillColor(Color.RED)
+ .fillAlpha(0.2);
+
+ for (int i = 0; i < 2000; i++) {
+ Style style = sb.buffer(Math.random() + 0.2)
+ .fillColor(ColorUtil.setHue(Color.RED,
+ (int) (Math.random() * 50) / 50.0))
+ .fillAlpha(0.5)
+ .build();
+
+ vectorLayer.add(new PointDrawable(Math.random() * 180 - 90,
+ Math.random() * 360 - 180,
+ style));
+
+ }
+
+ mMap.layers().add(vectorLayer);
+ mMap.layers().add(new TileGridLayer(mMap, 0xff222222, 1.2f, 1));
+
+ mMap.setMapPosition(0, 0, 1 << 2);
+ }
+}
diff --git a/vtm-android-gdx/build.gradle b/vtm-android-gdx/build.gradle
index b0ab0e56a..369079239 100644
--- a/vtm-android-gdx/build.gradle
+++ b/vtm-android-gdx/build.gradle
@@ -25,7 +25,8 @@ dependencies {
android {
compileSdkVersion androidTargetSdk()
buildToolsVersion "$androidBuildVersionTools"
-
+ lintOptions { abortOnError false }
+
sourceSets {
main {
manifest.srcFile 'AndroidManifest.xml'
diff --git a/vtm-android-start/build.gradle b/vtm-android-start/build.gradle
index 3c317f2eb..adcbd921a 100644
--- a/vtm-android-start/build.gradle
+++ b/vtm-android-start/build.gradle
@@ -9,7 +9,8 @@ dependencies {
compile project(':vtm-android')
compile project(':vtm-themes')
- compile 'com.android.support:support-v4:21.+'
+ compile 'com.android.support:support-v4:22.+'
+ compile 'com.android.support:appcompat-v7:22.+'
eclipseCompile project(':appcompat')
compile 'com.noveogroup.android:android-logger:1.3.4'
diff --git a/vtm-android-start/src/org/oscim/android/start/TestActivity.java b/vtm-android-start/src/org/oscim/android/start/TestActivity.java
index 72f36951b..7620e7855 100644
--- a/vtm-android-start/src/org/oscim/android/start/TestActivity.java
+++ b/vtm-android-start/src/org/oscim/android/start/TestActivity.java
@@ -1,6 +1,7 @@
package org.oscim.android.start;
-import org.oscim.android.MapActivity;
+import org.oscim.android.MapPreferences;
+import org.oscim.android.MapView;
import org.oscim.layers.tile.buildings.BuildingLayer;
import org.oscim.layers.tile.vector.VectorTileLayer;
import org.oscim.layers.tile.vector.labeling.LabelLayer;
@@ -11,24 +12,41 @@
import org.slf4j.LoggerFactory;
import android.os.Bundle;
+import android.support.v7.app.ActionBarActivity;
-public class TestActivity extends MapActivity {
+public class TestActivity extends ActionBarActivity {
public static final Logger log = LoggerFactory.getLogger(TestActivity.class);
+ MapView mMapView;
+ MapPreferences mPrefs;
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_map);
- Map map = this.map();
+ mMapView = (MapView) findViewById(R.id.mapView);
+ Map map = mMapView.map();
+ mPrefs = new MapPreferences(TestActivity.class.getName(), this);
VectorTileLayer baseLayer = map.setBaseMap(new OSciMap4TileSource());
map.layers().add(new BuildingLayer(map, baseLayer));
map.layers().add(new LabelLayer(map, baseLayer));
map.setTheme(VtmThemes.DEFAULT);
+ }
- //mMap.setMapPosition(49.417, 8.673, 1 << 17);
- map.setMapPosition(53.5620092, 9.9866457, 1 << 16);
+ @Override
+ protected void onResume() {
+ super.onResume();
- // mMap.layers().add(new TileGridLayer(mMap));
+ mPrefs.load(mMapView.map());
+ mMapView.onResume();
}
+
+ @Override
+ protected void onPause() {
+ super.onPause();
+
+ mMapView.onPause();
+ mPrefs.save(mMapView.map());
+ }
+
}
diff --git a/vtm-android/src/org/oscim/android/AndroidMap.java b/vtm-android/src/org/oscim/android/AndroidMap.java
deleted file mode 100644
index 4801da947..000000000
--- a/vtm-android/src/org/oscim/android/AndroidMap.java
+++ /dev/null
@@ -1,105 +0,0 @@
-/*
- * Copyright 2013 Hannes Janetzek
- *
- * This file is part of the OpenScienceMap project (http://www.opensciencemap.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 .
- */
-package org.oscim.android;
-
-import org.oscim.android.gl.GLView;
-import org.oscim.map.Map;
-
-import android.widget.RelativeLayout.LayoutParams;
-
-public class AndroidMap extends Map {
-
- private final MapView mMapView;
- final GLView mGLView;
-
- private volatile boolean mWaitRedraw;
- private volatile boolean mPausing;
-
- public AndroidMap(MapView mapView) {
- super();
-
- mMapView = mapView;
- mGLView = new GLView(mapView.getContext(), this);
-
- LayoutParams params =
- new LayoutParams(android.view.ViewGroup.LayoutParams.MATCH_PARENT,
- android.view.ViewGroup.LayoutParams.MATCH_PARENT);
-
- mapView.addView(mGLView, params);
- }
-
- @Override
- public int getWidth() {
- return mMapView.getWidth();
- }
-
- @Override
- public int getHeight() {
- return mMapView.getHeight();
- }
-
- @Override
- public void updateMap(boolean redraw) {
- //if (redraw && !mClearMap && !mPausing)
- // mGLView.requestRender();
-
- if (!mWaitRedraw) {
- mWaitRedraw = true;
- mMapView.post(mRedrawRequest);
- }
- }
-
- @Override
- public void render() {
- if (mPausing)
- return;
-
- if (mClearMap)
- updateMap(false);
- else
- mGLView.requestRender();
- }
-
- private final Runnable mRedrawRequest = new Runnable() {
- @Override
- public void run() {
- redrawMapInternal();
- }
- };
-
- void redrawMapInternal() {
- mWaitRedraw = false;
-
- updateLayers();
-
- mGLView.requestRender();
- }
-
- @Override
- public boolean post(Runnable runnable) {
- return mMapView.post(runnable);
- }
-
- @Override
- public boolean postDelayed(Runnable action, long delay) {
- return mMapView.postDelayed(action, delay);
- }
-
- public void pause(boolean pause) {
- mPausing = pause;
- }
-}
diff --git a/vtm-android/src/org/oscim/android/MapActivity.java b/vtm-android/src/org/oscim/android/MapActivity.java
deleted file mode 100644
index b04a4ec4b..000000000
--- a/vtm-android/src/org/oscim/android/MapActivity.java
+++ /dev/null
@@ -1,125 +0,0 @@
-/*
- * Copyright 2010, 2011, 2012 mapsforge.org
- * Copyright 2013 Hannes Janetzek
- *
- * This file is part of the OpenScienceMap project (http://www.opensciencemap.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 .
- */
-package org.oscim.android;
-
-import org.oscim.core.GeoPoint;
-import org.oscim.core.MapPosition;
-import org.oscim.map.Map;
-
-import android.content.SharedPreferences;
-import android.content.SharedPreferences.Editor;
-import android.support.v4.app.FragmentActivity;
-
-/**
- * MapActivity is the abstract base class which can be extended in order to use
- * a {@link MapView}. There are no abstract methods in this implementation which
- * subclasses need to override and no API key or registration is required.
- *
- * A subclass may create a MapView either via one of the MapView constructors or
- * by inflating an XML layout file.
- *
- * When the MapActivity is shut down, the current center position, zoom level
- * and map file of the MapView are saved in a preferences file and restored in
- * the next startup process.
- */
-public abstract class MapActivity extends FragmentActivity {
- private static final String KEY_LATITUDE = "latitude";
- private static final String KEY_LONGITUDE = "longitude";
- private static final String KEY_MAP_SCALE = "map_scale";
-
- private static final String PREFERENCES_FILE = "MapActivity";
-
- private static boolean containsViewport(SharedPreferences sharedPreferences) {
- return sharedPreferences.contains(KEY_LATITUDE)
- && sharedPreferences.contains(KEY_LONGITUDE)
- && sharedPreferences.contains(KEY_MAP_SCALE);
- }
-
- protected Map mMap;
- protected MapView mMapView;
-
- public Map map() {
- return mMap;
- }
-
- @Override
- protected void onDestroy() {
- super.onDestroy();
- mMap.destroy();
- }
-
- @Override
- protected void onPause() {
- super.onPause();
-
- Editor editor = getSharedPreferences(PREFERENCES_FILE, MODE_PRIVATE).edit();
- editor.clear();
-
- // save the map position
- MapPosition mapPosition = new MapPosition();
-
- mMap.viewport().getMapPosition(mapPosition);
-
- GeoPoint geoPoint = mapPosition.getGeoPoint();
-
- editor.putInt(KEY_LATITUDE, geoPoint.latitudeE6);
- editor.putInt(KEY_LONGITUDE, geoPoint.longitudeE6);
- editor.putFloat(KEY_MAP_SCALE, (float) mapPosition.scale);
-
- editor.commit();
- }
-
- @Override
- protected void onResume() {
- super.onResume();
- mMapView.onResume();
- }
-
- @Override
- protected void onStop() {
- super.onStop();
- mMapView.onPause();
- }
-
- /**
- * This method is called once by each MapView during its setup process.
- *
- * @param mapView
- * the calling MapView.
- */
- public final void registerMapView(MapView mapView) {
- mMapView = mapView;
- mMap = mapView.map();
-
- SharedPreferences sharedPreferences = getSharedPreferences(PREFERENCES_FILE,
- MODE_PRIVATE);
-
- if (containsViewport(sharedPreferences)) {
- // get and set the map position and zoom level
- int latitudeE6 = sharedPreferences.getInt(KEY_LATITUDE, 0);
- int longitudeE6 = sharedPreferences.getInt(KEY_LONGITUDE, 0);
- float scale = sharedPreferences.getFloat(KEY_MAP_SCALE, 1);
-
- MapPosition mapPosition = new MapPosition();
- mapPosition.setPosition(latitudeE6 / 1E6, longitudeE6 / 1E6);
- mapPosition.setScale(scale);
-
- mMap.setMapPosition(mapPosition);
- }
- }
-}
diff --git a/vtm-android/src/org/oscim/android/MapPreferences.java b/vtm-android/src/org/oscim/android/MapPreferences.java
new file mode 100644
index 000000000..cc11ba68a
--- /dev/null
+++ b/vtm-android/src/org/oscim/android/MapPreferences.java
@@ -0,0 +1,74 @@
+package org.oscim.android;
+
+import org.oscim.core.MapPosition;
+import org.oscim.map.Map;
+
+import android.app.Activity;
+import android.content.Context;
+import android.content.SharedPreferences;
+import android.content.SharedPreferences.Editor;
+
+public class MapPreferences {
+ private static final String KEY_LATITUDE = "latitude";
+ private static final String KEY_LONGITUDE = "longitude";
+ private static final String KEY_SCALE = "scale";
+
+ private final String PREFERENCES_FILE;
+ Context ctx;
+
+ public MapPreferences(String name, Context ctx) {
+ this.ctx = ctx;
+ this.PREFERENCES_FILE = name;
+ }
+
+ private void putDouble(Editor editor, String key, double value) {
+ editor.putLong(key, Double.doubleToLongBits(value));
+ }
+
+ private double getDouble(SharedPreferences prefs, String key) {
+ return Double.longBitsToDouble(prefs.getLong(key, 0));
+ }
+
+ public void save(Map map) {
+ save(map.getMapPosition());
+ }
+
+ public void save(MapPosition pos) {
+ Editor editor = ctx.getSharedPreferences(PREFERENCES_FILE,
+ Activity.MODE_PRIVATE).edit();
+ editor.clear();
+ putDouble(editor, KEY_LATITUDE, pos.y);
+ putDouble(editor, KEY_LONGITUDE, pos.x);
+ putDouble(editor, KEY_SCALE, pos.scale);
+ putDouble(editor, KEY_LATITUDE, pos.y);
+ editor.commit();
+ }
+
+ private static boolean containsViewport(SharedPreferences prefs) {
+ return prefs.contains(KEY_LATITUDE)
+ && prefs.contains(KEY_LONGITUDE)
+ && prefs.contains(KEY_SCALE);
+ }
+
+ public boolean load(Map map) {
+ MapPosition pos = map.getMapPosition();
+ if (load(pos)) {
+ map.setMapPosition(pos);
+ return true;
+ }
+ return false;
+ }
+
+ public boolean load(MapPosition pos) {
+ SharedPreferences prefs = ctx.getSharedPreferences(PREFERENCES_FILE,
+ Activity.MODE_PRIVATE);
+
+ if (containsViewport(prefs)) {
+ pos.x = getDouble(prefs, KEY_LONGITUDE);
+ pos.y = getDouble(prefs, KEY_LATITUDE);
+ pos.scale = getDouble(prefs, KEY_SCALE);
+ return true;
+ }
+ return false;
+ }
+}
diff --git a/vtm-android/src/org/oscim/android/MapView.java b/vtm-android/src/org/oscim/android/MapView.java
index 2847a2ccc..d8c7c712f 100644
--- a/vtm-android/src/org/oscim/android/MapView.java
+++ b/vtm-android/src/org/oscim/android/MapView.java
@@ -16,8 +16,12 @@
*/
package org.oscim.android;
+import javax.microedition.khronos.egl.EGLConfig;
+import javax.microedition.khronos.opengles.GL10;
+
import org.oscim.android.canvas.AndroidGraphics;
import org.oscim.android.gl.AndroidGL;
+import org.oscim.android.gl.GlConfigChooser;
import org.oscim.android.input.AndroidMotionEvent;
import org.oscim.android.input.GestureHandler;
import org.oscim.backend.CanvasAdapter;
@@ -28,19 +32,26 @@
import android.annotation.SuppressLint;
import android.content.Context;
+import android.opengl.GLSurfaceView;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.view.GestureDetector;
-import android.widget.RelativeLayout;
-public class MapView extends RelativeLayout {
+/**
+ * The MapView,
+ *
+ * add it your App, have a map!
+ *
+ * Dont forget to call onPause / onResume!
+ */
+public class MapView extends GLSurfaceView {
+
+ static final Logger log = LoggerFactory.getLogger(MapView.class);
static {
System.loadLibrary("vtm-jni");
}
- static final Logger log = LoggerFactory.getLogger(MapView.class);
-
protected final AndroidMap mMap;
protected final GestureDetector mGestureDetector;
protected final AndroidMotionEvent mMotionEvent;
@@ -51,10 +62,14 @@ public MapView(Context context) {
public MapView(Context context, AttributeSet attributeSet) {
super(context, attributeSet);
+
+ /* Not sure if this makes sense */
this.setWillNotDraw(true);
this.setClickable(true);
this.setFocusable(true);
+ this.setFocusableInTouchMode(true);
+ /* Setup android backedn */
AndroidGraphics.init();
AndroidAssets.init(context);
GLAdapter.init(new AndroidGL());
@@ -62,10 +77,19 @@ public MapView(Context context, AttributeSet attributeSet) {
DisplayMetrics metrics = getResources().getDisplayMetrics();
CanvasAdapter.dpi = (int) Math.max(metrics.xdpi, metrics.ydpi);
+ /* Initialize the Map */
mMap = new AndroidMap(this);
- if (context instanceof MapActivity)
- ((MapActivity) context).registerMapView(this);
+ /* Initialize Renderer */
+ setEGLConfigChooser(new GlConfigChooser());
+ setEGLContextClientVersion(2);
+
+ if (GLAdapter.debug)
+ setDebugFlags(GLSurfaceView.DEBUG_CHECK_GL_ERROR
+ | GLSurfaceView.DEBUG_LOG_GL_CALLS);
+
+ setRenderer(new GLRenderer(mMap));
+ setRenderMode(GLSurfaceView.RENDERMODE_WHEN_DIRTY);
mMap.clearMap();
mMap.updateMap(false);
@@ -81,11 +105,11 @@ public void onStop() {
}
- void onPause() {
+ public void onPause() {
mMap.pause(true);
}
- void onResume() {
+ public void onResume() {
mMap.pause(false);
}
@@ -116,4 +140,114 @@ protected void onSizeChanged(int width, int height,
public Map map() {
return mMap;
}
+
+ static class AndroidMap extends Map {
+
+ private final MapView mMapView;
+
+ private boolean mRenderRequest;
+ private boolean mRenderWait;
+ private boolean mPausing;
+
+ public AndroidMap(MapView mapView) {
+ super();
+ mMapView = mapView;
+ }
+
+ @Override
+ public int getWidth() {
+ return mMapView.getWidth();
+ }
+
+ @Override
+ public int getHeight() {
+ return mMapView.getHeight();
+ }
+
+ private final Runnable mRedrawCb = new Runnable() {
+ @Override
+ public void run() {
+ prepareFrame();
+ mMapView.requestRender();
+ }
+ };
+
+ @Override
+ public void updateMap(boolean redraw) {
+ synchronized (mRedrawCb) {
+ if (mPausing)
+ return;
+
+ if (!mRenderRequest) {
+ mRenderRequest = true;
+ mMapView.post(mRedrawCb);
+ } else {
+ mRenderWait = true;
+ }
+ }
+ }
+
+ @Override
+ public void render() {
+ if (mPausing)
+ return;
+
+ /** TODO should not need to call prepareFrame in mRedrawCb */
+ updateMap(false);
+ }
+
+ @Override
+ public void beginFrame() {
+ }
+
+ @Override
+ public void doneFrame(boolean animate) {
+ synchronized (mRedrawCb) {
+ mRenderRequest = false;
+ if (animate || mRenderWait) {
+ mRenderWait = false;
+ render();
+ }
+ }
+ }
+
+ @Override
+ public boolean post(Runnable runnable) {
+ return mMapView.post(runnable);
+ }
+
+ @Override
+ public boolean postDelayed(Runnable action, long delay) {
+ return mMapView.postDelayed(action, delay);
+ }
+
+ public void pause(boolean pause) {
+ log.debug("pause... {}", pause);
+ mPausing = pause;
+ }
+ }
+
+ static class GLRenderer extends org.oscim.renderer.MapRenderer
+ implements GLSurfaceView.Renderer {
+
+ public GLRenderer(Map map) {
+ super(map);
+ }
+
+ @Override
+ public void onSurfaceCreated(GL10 gl, EGLConfig config) {
+ super.onSurfaceCreated();
+ }
+
+ @Override
+ public void onSurfaceChanged(GL10 gl, int width, int height) {
+ super.onSurfaceChanged(width, height);
+
+ }
+
+ @Override
+ public void onDrawFrame(GL10 gl) {
+ super.onDrawFrame();
+ }
+ }
}
diff --git a/vtm-android/src/org/oscim/android/gl/GLView.java b/vtm-android/src/org/oscim/android/gl/GLView.java
deleted file mode 100644
index fcecb62d9..000000000
--- a/vtm-android/src/org/oscim/android/gl/GLView.java
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- * Copyright 2012 Hannes Janetzek
- *
- * This file is part of the OpenScienceMap project (http://www.opensciencemap.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 .
- */
-package org.oscim.android.gl;
-
-import javax.microedition.khronos.egl.EGLConfig;
-import javax.microedition.khronos.opengles.GL10;
-
-import org.oscim.backend.GLAdapter;
-import org.oscim.map.Map;
-
-import android.content.Context;
-import android.opengl.GLSurfaceView;
-
-public class GLView extends GLSurfaceView {
-
- class GLRenderer extends org.oscim.renderer.MapRenderer implements GLSurfaceView.Renderer {
-
- public GLRenderer(Map map) {
- super(map);
- }
-
- @Override
- public void onSurfaceCreated(GL10 gl, EGLConfig config) {
- super.onSurfaceCreated();
- }
-
- @Override
- public void onSurfaceChanged(GL10 gl, int width, int height) {
- super.onSurfaceChanged(width, height);
-
- }
-
- @Override
- public void onDrawFrame(GL10 gl) {
- super.onDrawFrame();
- }
- }
-
- public GLView(Context context, Map map) {
- super(context);
- setEGLConfigChooser(new GlConfigChooser());
- setEGLContextClientVersion(2);
-
- if (GLAdapter.debug)
- setDebugFlags(GLSurfaceView.DEBUG_CHECK_GL_ERROR | GLSurfaceView.DEBUG_LOG_GL_CALLS);
-
- setRenderer(new GLRenderer(map));
-
- setRenderMode(GLSurfaceView.RENDERMODE_WHEN_DIRTY);
- }
-}
diff --git a/vtm-desktop/src/org/oscim/gdx/GdxMapApp.java b/vtm-desktop/src/org/oscim/gdx/GdxMapApp.java
index 334ee8b01..9b75a0f09 100644
--- a/vtm-desktop/src/org/oscim/gdx/GdxMapApp.java
+++ b/vtm-desktop/src/org/oscim/gdx/GdxMapApp.java
@@ -66,7 +66,8 @@ static protected JglfwApplicationConfiguration getConfig() {
cfg.height = 800;
cfg.stencil = 8;
//cfg.samples = 2;
- cfg.foregroundFPS = 60;
+ cfg.foregroundFPS = 30;
+ cfg.backgroundFPS = 10;
return cfg;
}
diff --git a/vtm-extras/src/org/oscim/layers/OsmVectorLayer.java b/vtm-extras/src/org/oscim/layers/OsmVectorLayer.java
index 91d7a8d1e..63835ed28 100644
--- a/vtm-extras/src/org/oscim/layers/OsmVectorLayer.java
+++ b/vtm-extras/src/org/oscim/layers/OsmVectorLayer.java
@@ -1,6 +1,6 @@
package org.oscim.layers;
-import org.oscim.core.BoundingBox;
+import org.oscim.core.Box;
import org.oscim.core.osm.OsmElement;
import org.oscim.layers.vector.AbstractVectorLayer;
import org.oscim.map.Map;
@@ -12,7 +12,7 @@ public OsmVectorLayer(Map map) {
}
@Override
- protected void processFeatures(Task t, BoundingBox b) {
+ protected void processFeatures(Task t, Box b) {
}
diff --git a/vtm-gdx/src/org/oscim/gdx/GdxMap.java b/vtm-gdx/src/org/oscim/gdx/GdxMap.java
index dda616199..288d84089 100644
--- a/vtm-gdx/src/org/oscim/gdx/GdxMap.java
+++ b/vtm-gdx/src/org/oscim/gdx/GdxMap.java
@@ -38,15 +38,12 @@
public abstract class GdxMap implements ApplicationListener {
final static Logger log = LoggerFactory.getLogger(GdxMap.class);
- protected final Map mMap;
- private final MapAdapter mMapAdapter;
+ protected Map mMap;
VectorTileLayer mMapLayer;
- private final MapRenderer mMapRenderer;
+ private MapRenderer mMapRenderer;
public GdxMap() {
- mMap = mMapAdapter = new MapAdapter();
- mMapRenderer = new MapRenderer(mMap);
}
protected void initDefaultLayers(TileSource tileSource, boolean tileGrid, boolean labels,
@@ -70,6 +67,8 @@ protected void initDefaultLayers(TileSource tileSource, boolean tileGrid, boolea
@Override
public void create() {
+ mMap = new MapAdapter();
+ mMapRenderer = new MapRenderer(mMap);
Gdx.graphics.setContinuousRendering(false);
Gdx.app.setLogLevel(Application.LOG_DEBUG);
@@ -101,9 +100,13 @@ public void dispose() {
}
+ /* private */boolean mRenderWait;
+ /* private */boolean mRenderRequest;
+ /* private */boolean mUpdateRequest;
+
@Override
public void render() {
- if (!mMapAdapter.needsRedraw())
+ if (!mRenderRequest)
return;
mMapRenderer.onDrawFrame();
@@ -132,8 +135,7 @@ public Map getMap() {
return mMap;
}
- static class MapAdapter extends Map {
- boolean mRenderRequest;
+ class MapAdapter extends Map {
@Override
public int getWidth() {
@@ -145,21 +147,36 @@ public int getHeight() {
return Gdx.graphics.getHeight();
}
+ private final Runnable mRedrawCb = new Runnable() {
+ @Override
+ public void run() {
+ prepareFrame();
+ Gdx.graphics.requestRendering();
+ }
+ };
+
@Override
public void updateMap(boolean forceRender) {
- if (!mWaitRedraw) {
- mWaitRedraw = true;
- Gdx.app.postRunnable(mRedrawRequest);
+ synchronized (mRedrawCb) {
+ if (!mRenderRequest) {
+ mRenderRequest = true;
+ Gdx.app.postRunnable(mRedrawCb);
+ } else {
+ mRenderWait = true;
+ }
}
}
@Override
public void render() {
- mRenderRequest = true;
- if (mClearMap)
- updateMap(false);
- else
- Gdx.graphics.requestRendering();
+ synchronized (mRedrawCb) {
+ mRenderRequest = true;
+ if (mClearMap)
+ updateMap(false);
+ else {
+ Gdx.graphics.requestRendering();
+ }
+ }
}
@Override
@@ -179,35 +196,19 @@ public void run() {
return true;
}
- /**
- * Update all Layers on Main thread.
- *
- * @param forceRedraw
- * also render frame FIXME (does nothing atm)
- */
- private void redrawMapInternal(boolean forceRedraw) {
- updateLayers();
-
- mRenderRequest = true;
- Gdx.graphics.requestRendering();
+ @Override
+ public void beginFrame() {
}
- /* private */boolean mWaitRedraw;
- private final Runnable mRedrawRequest = new Runnable() {
- @Override
- public void run() {
- mWaitRedraw = false;
- redrawMapInternal(false);
+ @Override
+ public void doneFrame(boolean animate) {
+ synchronized (mRedrawCb) {
+ mRenderRequest = false;
+ if (animate || mRenderWait) {
+ mRenderWait = false;
+ updateMap(true);
+ }
}
- };
-
- public boolean needsRedraw() {
- if (!mRenderRequest)
- return false;
-
- mRenderRequest = false;
- return true;
}
-
}
}
diff --git a/vtm-jeo/src/org/oscim/layers/JeoTileSource.java b/vtm-jeo/src/org/oscim/layers/JeoTileSource.java
index 46330f2ef..35781bb37 100644
--- a/vtm-jeo/src/org/oscim/layers/JeoTileSource.java
+++ b/vtm-jeo/src/org/oscim/layers/JeoTileSource.java
@@ -1,8 +1,8 @@
package org.oscim.layers;
-import static org.oscim.tiling.ITileDataSink.QueryResult.FAILED;
-import static org.oscim.tiling.ITileDataSink.QueryResult.SUCCESS;
-import static org.oscim.tiling.ITileDataSink.QueryResult.TILE_NOT_FOUND;
+import static org.oscim.tiling.QueryResult.FAILED;
+import static org.oscim.tiling.QueryResult.SUCCESS;
+import static org.oscim.tiling.QueryResult.TILE_NOT_FOUND;
import java.io.ByteArrayInputStream;
import java.io.IOException;
diff --git a/vtm-jeo/src/org/oscim/layers/JeoVectorLayer.java b/vtm-jeo/src/org/oscim/layers/JeoVectorLayer.java
index d78447dfa..e3581935c 100644
--- a/vtm-jeo/src/org/oscim/layers/JeoVectorLayer.java
+++ b/vtm-jeo/src/org/oscim/layers/JeoVectorLayer.java
@@ -33,6 +33,8 @@ public class JeoVectorLayer extends JtsLayer {
private final RuleList mRules;
protected double mDropPointDistance = 0.01;
+ private double mMinX;
+ private double mMinY;
public JeoVectorLayer(Map map, VectorDataset data, Style style) {
super(map);
diff --git a/vtm-jeo/src/org/oscim/layers/JtsLayer.java b/vtm-jeo/src/org/oscim/layers/JtsLayer.java
index 6430e6e1c..08e5d8b61 100644
--- a/vtm-jeo/src/org/oscim/layers/JtsLayer.java
+++ b/vtm-jeo/src/org/oscim/layers/JtsLayer.java
@@ -1,7 +1,7 @@
package org.oscim.layers;
import org.jeo.geom.CoordinatePath;
-import org.oscim.core.BoundingBox;
+import org.oscim.core.Box;
import org.oscim.core.GeometryBuffer;
import org.oscim.core.MapPosition;
import org.oscim.core.MercatorProjection;
@@ -19,14 +19,16 @@
public abstract class JtsLayer extends AbstractVectorLayer {
+ private double mMinX;
+ private double mMinY;
+
public JtsLayer(Map map) {
super(map);
}
@Override
- protected void processFeatures(Task t, BoundingBox bbox) {
- processFeatures(t, new Envelope(bbox.getMinLongitude(), bbox.getMaxLongitude(),
- bbox.getMinLatitude(), bbox.getMaxLatitude()));
+ protected void processFeatures(Task t, Box bbox) {
+ processFeatures(t, new Envelope(bbox.xmin, bbox.ymin, bbox.xmax, bbox.ymax));
}
diff --git a/vtm-playground/src/org/oscim/test/PathLayerTest.java b/vtm-playground/src/org/oscim/test/PathLayerTest.java
new file mode 100644
index 000000000..b6f3073a6
--- /dev/null
+++ b/vtm-playground/src/org/oscim/test/PathLayerTest.java
@@ -0,0 +1,83 @@
+package org.oscim.test;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.oscim.backend.canvas.Color;
+import org.oscim.core.GeoPoint;
+import org.oscim.core.MapPosition;
+import org.oscim.event.Event;
+import org.oscim.gdx.GdxMapApp;
+import org.oscim.layers.PathLayer;
+import org.oscim.map.Map;
+import org.oscim.map.Map.UpdateListener;
+
+public class PathLayerTest extends GdxMapApp {
+
+ @Override
+ public void createLayers() {
+ createLayers(1, true);
+
+ mMap.setMapPosition(0, 0, 1 << 2);
+
+ mMap.events.bind(new UpdateListener() {
+ @Override
+ public void onMapEvent(Event e, MapPosition mapPosition) {
+ if (e == Map.UPDATE_EVENT) {
+ long t = System.currentTimeMillis();
+ float pos = t % 20000 / 10000f - 1f;
+ createLayers(pos, false);
+ mMap.updateMap(true);
+ }
+ }
+ });
+ }
+
+ ArrayList mPathLayers = new ArrayList();
+
+ void createLayers(float pos, boolean init) {
+
+ int i = 0;
+
+ for (double lat = -90; lat <= 90; lat += 5) {
+ List pts = new ArrayList();
+
+ for (double lon = -180; lon <= 180; lon += 2) {
+ //pts.add(new GeoPoint(lat, lon));
+ // double longitude = lon + (pos * 180);
+ // if (longitude < -180)
+ // longitude += 360;
+ // if (longitude > 180)
+ // longitude -= 360;
+ double longitude = lon;
+
+ double latitude = lat + (pos * 90);
+ if (latitude < -90)
+ latitude += 180;
+ if (latitude > 90)
+ latitude -= 180;
+
+ latitude += Math.sin((Math.abs(pos) * (lon / Math.PI)));
+
+ pts.add(new GeoPoint(latitude, longitude));
+ }
+ PathLayer pathLayer;
+ if (init) {
+ int c = Color.fade(Color.rainbow((float) (lat + 90) / 180), 0.5f);
+ pathLayer = new PathLayer(mMap, c, 6);
+ mMap.layers().add(pathLayer);
+ mPathLayers.add(pathLayer);
+ } else {
+ pathLayer = mPathLayers.get(i++);
+ }
+
+ pathLayer.setPoints(pts);
+ }
+
+ }
+
+ public static void main(String[] args) {
+ GdxMapApp.init();
+ GdxMapApp.run(new PathLayerTest(), null, 400);
+ }
+}
diff --git a/vtm-playground/src/org/oscim/test/TileRenderTest.java b/vtm-playground/src/org/oscim/test/TileRenderTest.java
index dbfb1ee07..a43eb28f4 100644
--- a/vtm-playground/src/org/oscim/test/TileRenderTest.java
+++ b/vtm-playground/src/org/oscim/test/TileRenderTest.java
@@ -20,6 +20,7 @@
import org.oscim.map.Map;
import org.oscim.renderer.MapRenderer;
import org.oscim.theme.VtmThemes;
+import org.oscim.tiling.QueryResult;
import org.oscim.tiling.TileSource;
import org.oscim.tiling.source.oscimap4.OSciMap4TileSource;
@@ -100,7 +101,7 @@ public void createLayers() {
log.debug("load {}", tile);
tileLoader[0].loadTile(tile);
- tileManager.jobCompleted(tile, true);
+ tileManager.jobCompleted(tile, QueryResult.SUCCESS);
} else {
tileManager.update(mapPosition);
MapTile t = tileManager.getTileJob();
@@ -108,7 +109,7 @@ public void createLayers() {
log.debug("load {}", t);
tileLoader[0].loadTile(t);
- tileManager.jobCompleted(t, true);
+ tileManager.jobCompleted(t, QueryResult.SUCCESS);
t = tileManager.getTileJob();
}
diff --git a/vtm-playground/src/org/oscim/test/VectorLayerTest.java b/vtm-playground/src/org/oscim/test/VectorLayerTest.java
new file mode 100644
index 000000000..dea935755
--- /dev/null
+++ b/vtm-playground/src/org/oscim/test/VectorLayerTest.java
@@ -0,0 +1,81 @@
+package org.oscim.test;
+
+import org.oscim.backend.canvas.Color;
+import org.oscim.gdx.GdxMapApp;
+import org.oscim.layers.vector.VectorLayer;
+import org.oscim.layers.vector.geometries.PointDrawable;
+import org.oscim.layers.vector.geometries.Style;
+import org.oscim.map.Map;
+import org.oscim.utils.ColorUtil;
+
+public class VectorLayerTest extends GdxMapApp {
+
+ @Override
+ public void createLayers() {
+ Map map = getMap();
+
+ //VectorTileLayer tileLayer = map.setBaseMap(new OSciMap4TileSource());
+
+ VectorLayer vectorLayer = new VectorLayer(map);
+
+ // vectorLayer.add(new PointDrawable(0, 180, Style.builder()
+ // .setBuffer(10)
+ // .setFillColor(Color.RED)
+ // .setFillAlpha(0.5)
+ // .build()));
+ //
+ // Geometry g = new GeomBuilder()
+ // .point(180, 0)
+ // .point()
+ // .buffer(6)
+ // .get();
+ //
+ // vectorLayer.add(new PolygonDrawable(g, defaultStyle()));
+ //
+
+ Style.Builder sb = Style.builder()
+ .buffer(0.4)
+ .fillColor(Color.RED)
+ .fillAlpha(0.2);
+
+ Style style = sb.fillAlpha(0.2).build();
+
+ // int tileSize = 5;
+ // for (int x = -180; x < 200; x += tileSize) {
+ // for (int y = -90; y < 90; y += tileSize) {
+ // // Style style = sb.setFillAlpha(FastMath.clamp(FastMath.length(x, y) / 180, 0.2, 1))
+ // // .build();
+ //
+ // vectorLayer.add(new RectangleDrawable(FastMath.clamp(y, -85, 85), x,
+ // FastMath.clamp(y + tileSize - 0.1, -85, 85),
+ // x + tileSize - 0.1, style));
+ //
+ // }
+ // }
+
+ for (int i = 0; i < 1000; i++) {
+ style = sb.buffer(Math.random() * 1)
+ .fillColor(ColorUtil.setHue(Color.RED,
+ Math.random()))
+ .fillAlpha(0.5)
+ .build();
+
+ vectorLayer.add(new PointDrawable(Math.random() * 180 - 90,
+ Math.random() * 360 - 180,
+ style));
+
+ }
+
+ map.layers().add(vectorLayer);
+
+ //map.layers().add(new LabelLayer(map, tileLayer));
+ //map.setTheme(VtmThemes.DEFAULT);
+
+ map.setMapPosition(0, 0, 1 << 2);
+ }
+
+ public static void main(String[] args) {
+ GdxMapApp.init();
+ GdxMapApp.run(new VectorLayerTest(), null, 400);
+ }
+}
diff --git a/vtm-web-app/src/org/oscim/web/client/SearchBox.java b/vtm-web-app/src/org/oscim/web/client/SearchBox.java
index 9acd9c5df..40044c549 100644
--- a/vtm-web-app/src/org/oscim/web/client/SearchBox.java
+++ b/vtm-web-app/src/org/oscim/web/client/SearchBox.java
@@ -268,7 +268,7 @@ public void onSelectionChange(SelectionChangeEvent event) {
} catch (Exception e) {
log.debug(wkt);
}
- mOverlay.setGeom(g);
+ //FIXME mOverlay.setGeom(g);
//log.debug("add polygon " + p.length());
} else {
diff --git a/vtm-web/src/org/oscim/gdx/emu/org/oscim/layers/tile/TileLoader.java b/vtm-web/src/org/oscim/gdx/emu/org/oscim/layers/tile/TileLoader.java
index fd0fea69c..9b5d184c9 100644
--- a/vtm-web/src/org/oscim/gdx/emu/org/oscim/layers/tile/TileLoader.java
+++ b/vtm-web/src/org/oscim/gdx/emu/org/oscim/layers/tile/TileLoader.java
@@ -14,13 +14,13 @@
*/
package org.oscim.layers.tile;
-import static org.oscim.tiling.ITileDataSink.QueryResult.FAILED;
-import static org.oscim.tiling.ITileDataSink.QueryResult.SUCCESS;
+import static org.oscim.tiling.QueryResult.FAILED;
import org.oscim.backend.canvas.Bitmap;
import org.oscim.core.MapElement;
import org.oscim.renderer.MapRenderer;
import org.oscim.tiling.ITileDataSink;
+import org.oscim.tiling.QueryResult;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -115,13 +115,12 @@ public void go() {
*/
@Override
public void completed(QueryResult result) {
- boolean success = (result == SUCCESS) && !isInterrupted;
long now = MapRenderer.frametime;
//log.debug("completed {} diff time:{}", mTile, (now - lastLoadTime));
lastLoadTime = now;
- mTileManager.jobCompleted(mTile, success);
+ mTileManager.jobCompleted(mTile, result);
mTile = null;
mWorking = false;
diff --git a/vtm-web/src/org/oscim/gdx/emu/org/oscim/tiling/source/UrlTileDataSource.java b/vtm-web/src/org/oscim/gdx/emu/org/oscim/tiling/source/UrlTileDataSource.java
index 544d6c7b3..e8d5b45bd 100644
--- a/vtm-web/src/org/oscim/gdx/emu/org/oscim/tiling/source/UrlTileDataSource.java
+++ b/vtm-web/src/org/oscim/gdx/emu/org/oscim/tiling/source/UrlTileDataSource.java
@@ -14,8 +14,8 @@
*/
package org.oscim.tiling.source;
-import static org.oscim.tiling.ITileDataSink.QueryResult.FAILED;
-import static org.oscim.tiling.ITileDataSink.QueryResult.SUCCESS;
+import static org.oscim.tiling.QueryResult.FAILED;
+import static org.oscim.tiling.QueryResult.SUCCESS;
import java.io.IOException;
import java.io.InputStream;
diff --git a/vtm-web/src/org/oscim/gdx/emu/org/oscim/tiling/source/bitmap/BitmapTileSource.java b/vtm-web/src/org/oscim/gdx/emu/org/oscim/tiling/source/bitmap/BitmapTileSource.java
index 8e7186bc8..66fa1defb 100644
--- a/vtm-web/src/org/oscim/gdx/emu/org/oscim/tiling/source/bitmap/BitmapTileSource.java
+++ b/vtm-web/src/org/oscim/gdx/emu/org/oscim/tiling/source/bitmap/BitmapTileSource.java
@@ -5,8 +5,8 @@
import org.oscim.layers.tile.MapTile;
import org.oscim.layers.tile.TileLoader;
import org.oscim.tiling.ITileDataSink;
-import org.oscim.tiling.ITileDataSink.QueryResult;
import org.oscim.tiling.ITileDataSource;
+import org.oscim.tiling.QueryResult;
import org.oscim.tiling.source.LwHttp;
import org.oscim.tiling.source.UrlTileSource;
import org.slf4j.Logger;
diff --git a/vtm-web/src/org/oscim/gdx/emu/org/oscim/utils/ThreadUtils.java b/vtm-web/src/org/oscim/gdx/emu/org/oscim/utils/ThreadUtils.java
new file mode 100644
index 000000000..56ee2076f
--- /dev/null
+++ b/vtm-web/src/org/oscim/gdx/emu/org/oscim/utils/ThreadUtils.java
@@ -0,0 +1,16 @@
+package org.oscim.utils;
+
+public class ThreadUtils {
+
+ public static void assertMainThread() {
+ }
+
+ public static boolean isMainThread() {
+ return true;
+ }
+
+ public static void init() {
+
+ }
+
+}
diff --git a/vtm-web/src/org/oscim/tiling/source/JsonTileDataSource.java b/vtm-web/src/org/oscim/tiling/source/JsonTileDataSource.java
index c8fb1bee0..8584b3872 100644
--- a/vtm-web/src/org/oscim/tiling/source/JsonTileDataSource.java
+++ b/vtm-web/src/org/oscim/tiling/source/JsonTileDataSource.java
@@ -16,8 +16,8 @@
*/
package org.oscim.tiling.source;
-import static org.oscim.tiling.ITileDataSink.QueryResult.FAILED;
-import static org.oscim.tiling.ITileDataSink.QueryResult.SUCCESS;
+import static org.oscim.tiling.QueryResult.FAILED;
+import static org.oscim.tiling.QueryResult.SUCCESS;
import java.io.InputStream;
diff --git a/vtm/build.gradle b/vtm/build.gradle
index 19ad73c7b..019598519 100644
--- a/vtm/build.gradle
+++ b/vtm/build.gradle
@@ -5,6 +5,7 @@ configurations { providedCompile }
dependencies {
compile 'org.slf4j:slf4j-api:1.7.6'
+ compile 'com.vividsolutions:jts:1.13'
providedCompile 'com.squareup.okhttp:okhttp:1.5.2'
providedCompile 'com.google.code.findbugs:annotations:2.0.1'
}
@@ -29,7 +30,10 @@ eclipse.classpath {
file.whenMerged { classpath ->
classpath.entries.findAll { entry ->
- entry.path.contains('annotations') }*.exported = false
+ entry.path.contains('annotations') ||
+ entry.path.contains('okhttp') ||
+ entry.path.contains('okio')
+ }*.exported = false
}
//if you don't want some classpath entries 'exported' in Eclipse
diff --git a/vtm/src/org/oscim/core/Box.java b/vtm/src/org/oscim/core/Box.java
index 96dda049a..e27c97585 100644
--- a/vtm/src/org/oscim/core/Box.java
+++ b/vtm/src/org/oscim/core/Box.java
@@ -17,20 +17,13 @@
package org.oscim.core;
/**
- * The Class Box.
+ * The Classic Box.
*/
public class Box {
- /** The min x. */
public double xmin;
-
- /** The max x. */
public double xmax;
-
- /** The min y. */
public double ymin;
-
- /** The max y. */
public double ymax;
/**
@@ -49,6 +42,8 @@ public Box() {
* @param ymax the max y
*/
public Box(double xmin, double ymin, double xmax, double ymax) {
+ if (xmin > xmax || ymin > ymax)
+ throw new IllegalArgumentException("min > max !");
this.xmin = xmin;
this.ymin = ymin;
this.xmax = xmax;
@@ -70,21 +65,30 @@ public Box(Box bbox) {
* @return true, if point is inside box.
*/
public boolean contains(double x, double y) {
- return (x >= xmin && x <= ymax && y >= ymin && y <= ymax);
+ return (x >= xmin
+ && x <= xmax
+ && y >= ymin
+ && y <= ymax);
}
/**
* Check if Box contains Point.
*/
public boolean contains(Point p) {
- return (p.x >= xmin && p.x <= ymax && p.y >= ymin && p.y <= ymax);
+ return (p.x >= xmin
+ && p.x <= xmax
+ && p.y >= ymin
+ && p.y <= ymax);
}
/**
* Check if this Box is inside box.
*/
public boolean inside(Box box) {
- return xmin >= box.xmin && xmax <= box.xmax && ymin >= box.ymin && ymax <= box.ymax;
+ return xmin >= box.xmin
+ && xmax <= box.xmax
+ && ymin >= box.ymin
+ && ymax <= box.ymax;
}
public double getWidth() {
@@ -96,7 +100,10 @@ public double getHeight() {
}
public boolean overlap(Box other) {
- return !(xmin > other.xmax || xmax < other.xmin || ymin > other.ymax || ymax < other.ymin);
+ return !(xmin > other.xmax
+ || xmax < other.xmin
+ || ymin > other.ymax
+ || ymax < other.ymin);
}
@Override
@@ -104,4 +111,82 @@ public String toString() {
return "[" + xmin + ',' + ymin + ',' + xmax + ',' + ymax + ']';
}
+ public static Box createSafe(double x1, double y1, double x2, double y2) {
+ return new Box(x1 < x2 ? x1 : x2,
+ y1 < y2 ? y1 : y2,
+ x1 > x2 ? x1 : x2,
+ y1 > y2 ? y1 : y2);
+ }
+
+ public void setExtents(float[] points) {
+ float x1, y1, x2, y2;
+ x1 = x2 = points[0];
+ y1 = y2 = points[1];
+
+ for (int i = 2, n = points.length; i < n; i += 2) {
+ float x = points[i];
+ if (x < x1)
+ x1 = x;
+ else if (x > x2)
+ x2 = x;
+
+ float y = points[i + 1];
+ if (y < y1)
+ y1 = y;
+ else if (y > y2)
+ y2 = y;
+ }
+ this.xmin = x1;
+ this.ymin = y1;
+ this.xmax = x2;
+ this.ymax = y2;
+ }
+
+ public void add(Box bbox) {
+ if (bbox.xmin < xmin)
+ xmin = bbox.xmin;
+ if (bbox.ymin < ymin)
+ ymin = bbox.ymin;
+ if (bbox.xmax > xmax)
+ xmax = bbox.xmax;
+ if (bbox.ymax > ymax)
+ ymax = bbox.ymax;
+ }
+
+ public void add(double x, double y) {
+ if (x < xmin)
+ xmin = x;
+ if (y < ymin)
+ ymin = y;
+ if (x > xmax)
+ xmax = x;
+ if (y > ymax)
+ ymax = y;
+ }
+
+ public void translate(double dx, double dy) {
+ xmin += dx;
+ xmax += dx;
+ ymin += dy;
+ ymax += dy;
+ }
+
+ public void scale(double d) {
+ xmin *= d;
+ xmax *= d;
+ ymin *= d;
+ ymax *= d;
+ }
+
+ /** convrt map coordinates to lat/lon. */
+ public void map2mercator() {
+ double minLon = MercatorProjection.toLongitude(xmin);
+ double maxLon = MercatorProjection.toLongitude(xmax);
+ double minLat = MercatorProjection.toLatitude(ymax);
+ double maxLat = MercatorProjection.toLatitude(ymin);
+ xmin = minLon;
+ xmax = maxLon;
+ ymin = minLat;
+ ymax = maxLat;
+ }
}
diff --git a/vtm/src/org/oscim/core/GeometryBuffer.java b/vtm/src/org/oscim/core/GeometryBuffer.java
index 8640e9f7a..40319b1a2 100644
--- a/vtm/src/org/oscim/core/GeometryBuffer.java
+++ b/vtm/src/org/oscim/core/GeometryBuffer.java
@@ -70,6 +70,20 @@ private GeometryType(int type) {
private PointF mTmpPoint = new PointF();
private int pointLimit;
+ public GeometryBuffer() {
+ this(32, 4);
+ }
+
+ /**
+ * Instantiates a new geometry buffer.
+ *
+ * @param numPoints the num of expected points
+ * @param numIndices the num of expected indices
+ */
+ public GeometryBuffer(int numPoints, int numIndices) {
+ this(new float[numPoints * 2], new int[numIndices]);
+ }
+
/**
* Instantiates a new geometry buffer.
*
@@ -122,24 +136,15 @@ public int getNumPoints() {
return pointPos >> 1;
}
- /**
- * Instantiates a new geometry buffer.
- *
- * @param numPoints the num points
- * @param numIndices the num indices
- */
- public GeometryBuffer(int numPoints, int numIndices) {
- this(new float[numPoints * 2], new int[numIndices]);
- }
-
/**
* Reset buffer.
*/
- public void clear() {
+ public GeometryBuffer clear() {
index[0] = 0;
indexPos = 0;
pointPos = 0;
type = GeometryType.NONE;
+ return this;
}
/**
@@ -423,4 +428,23 @@ public String toString() {
return sb.toString();
}
+ public static GeometryBuffer makeCircle(float x, float y,
+ float radius, int segments) {
+ GeometryBuffer g = new GeometryBuffer(segments, 1);
+ makeCircle(g, x, y, radius, segments);
+ return g;
+ }
+
+ public static GeometryBuffer makeCircle(GeometryBuffer g,
+ float x, float y, float radius, int segments) {
+ g.clear();
+ g.startPolygon();
+ for (int i = 0; i < segments; i++) {
+ double rad = Math.toRadians(i * (360f / segments));
+
+ g.addPoint((float) (x + Math.cos(rad) * radius),
+ (float) (y + Math.sin(rad) * radius));
+ }
+ return g;
+ }
}
diff --git a/vtm/src/org/oscim/core/MapElement.java b/vtm/src/org/oscim/core/MapElement.java
index f98b3d022..81331e3c5 100644
--- a/vtm/src/org/oscim/core/MapElement.java
+++ b/vtm/src/org/oscim/core/MapElement.java
@@ -44,9 +44,10 @@ public void setLayer(int layer) {
}
@Override
- public void clear() {
+ public MapElement clear() {
layer = 5;
super.clear();
+ return this;
}
@Override
diff --git a/vtm/src/org/oscim/layers/PathLayer.java b/vtm/src/org/oscim/layers/PathLayer.java
index b16eb0694..b1a97d1b4 100644
--- a/vtm/src/org/oscim/layers/PathLayer.java
+++ b/vtm/src/org/oscim/layers/PathLayer.java
@@ -21,39 +21,30 @@
import java.util.ArrayList;
import java.util.List;
-import org.oscim.backend.canvas.Paint.Cap;
import org.oscim.core.GeoPoint;
-import org.oscim.core.GeometryBuffer;
-import org.oscim.core.MapPosition;
-import org.oscim.core.MercatorProjection;
-import org.oscim.core.Tile;
+import org.oscim.layers.vector.VectorLayer;
+import org.oscim.layers.vector.geometries.LineDrawable;
+import org.oscim.layers.vector.geometries.Style;
import org.oscim.map.Map;
-import org.oscim.renderer.BucketRenderer;
-import org.oscim.renderer.GLViewport;
-import org.oscim.renderer.bucket.LineBucket;
-import org.oscim.renderer.bucket.RenderBuckets;
-import org.oscim.theme.styles.LineStyle;
-import org.oscim.utils.FastMath;
-import org.oscim.utils.async.SimpleWorker;
-import org.oscim.utils.geom.LineClipper;
+import org.oscim.utils.geom.GeomBuilder;
+
+import com.vividsolutions.jts.geom.LineString;
/** This class draws a path line in given color. */
-public class PathLayer extends Layer {
+public class PathLayer extends VectorLayer {
- /** Stores points, converted to the map projection. */
protected final ArrayList mPoints;
- protected boolean mUpdatePoints;
-
- /** Line style */
- LineStyle mLineStyle;
- final Worker mWorker;
+ protected Style mStyle;
+ protected LineDrawable mDrawable;
public PathLayer(Map map, int lineColor, float lineWidth) {
super(map);
- mWorker = new Worker(map);
- mLineStyle = new LineStyle(lineColor, lineWidth, Cap.BUTT);
- mRenderer = new RenderPath();
+ mStyle = Style.builder()
+ .strokeColor(lineColor)
+ .strokeWidth(lineWidth)
+ .build();
+
mPoints = new ArrayList();
}
@@ -61,60 +52,59 @@ public PathLayer(Map map, int lineColor) {
this(map, lineColor, 2);
}
- public void clearPath() {
- if (mPoints.isEmpty())
- return;
+ public void setStyle(int lineColor, float lineWidth) {
+ mStyle = Style.builder()
+ .strokeColor(lineColor)
+ .strokeWidth(lineWidth)
+ .build();
+ }
- synchronized (mPoints) {
+ public void clearPath() {
+ if (!mPoints.isEmpty())
mPoints.clear();
- }
+
updatePoints();
}
public void setPoints(List pts) {
- synchronized (mPoints) {
- mPoints.clear();
- mPoints.addAll(pts);
- }
+ mPoints.clear();
+ mPoints.addAll(pts);
updatePoints();
}
public void addPoint(GeoPoint pt) {
- synchronized (mPoints) {
- mPoints.add(pt);
- }
+ mPoints.add(pt);
updatePoints();
}
public void addPoint(int latitudeE6, int longitudeE6) {
- synchronized (mPoints) {
- mPoints.add(new GeoPoint(latitudeE6, longitudeE6));
- }
+ mPoints.add(new GeoPoint(latitudeE6, longitudeE6));
updatePoints();
}
private void updatePoints() {
- mWorker.submit(10);
- mUpdatePoints = true;
+ synchronized (this) {
+
+ if (mDrawable != null) {
+ remove(mDrawable);
+ mDrawable = null;
+ }
+
+ if (!mPoints.isEmpty()) {
+ mDrawable = new LineDrawable(mPoints, mStyle);
+ if (mDrawable.getGeometry() == null)
+ mDrawable = null;
+ else
+ add(mDrawable);
+ }
+ }
+ mWorker.submit(0);
}
public List getPoints() {
return mPoints;
}
- /**
- * FIXME To be removed
- *
- * @deprecated
- *
- */
- public void setGeom(GeometryBuffer geom) {
- mGeom = geom;
- mWorker.submit(10);
- }
-
- GeometryBuffer mGeom;
-
/**
* Draw a great circle. Calculate a point for every 100km along the path.
*
@@ -148,11 +138,14 @@ public void addGreatCircle(GeoPoint startPoint, GeoPoint endPoint) {
*/
public void addGreatCircle(GeoPoint startPoint, GeoPoint endPoint,
final int numberOfPoints) {
- // adapted from page
- // http://compastic.blogspot.co.uk/2011/07/how-to-draw-great-circle-on-map-in.html
- // which was adapted from page http://maps.forum.nu/gm_flight_path.html
+ /* adapted from page
+ * http://compastic.blogspot.co.uk/2011/07/how-to-draw-great-circle-on-map
+ * -in.html
+ * which was adapted from page http://maps.forum.nu/gm_flight_path.html */
+
+ GeomBuilder gb = new GeomBuilder();
- // convert to radians
+ /* convert to radians */
double lat1 = startPoint.getLatitude() * Math.PI / 180;
double lon1 = startPoint.getLongitude() * Math.PI / 180;
double lat2 = endPoint.getLatitude() * Math.PI / 180;
@@ -181,230 +174,31 @@ public void addGreatCircle(GeoPoint startPoint, GeoPoint endPoint,
double latN = Math.atan2(z, Math.sqrt(Math.pow(x, 2) + Math.pow(y, 2)));
double lonN = Math.atan2(y, x);
- addPoint((int) (latN / (Math.PI / 180) * 1E6), (int) (lonN / (Math.PI / 180) * 1E6));
- }
- }
-
- /***
- * everything below runs on GL- and Worker-Thread
- ***/
- final class RenderPath extends BucketRenderer {
-
- public RenderPath() {
-
- buckets.addLineBucket(0, mLineStyle);
- }
-
- private int mCurX = -1;
- private int mCurY = -1;
- private int mCurZ = -1;
-
- @Override
- public synchronized void update(GLViewport v) {
- int tz = 1 << v.pos.zoomLevel;
- int tx = (int) (v.pos.x * tz);
- int ty = (int) (v.pos.y * tz);
-
- // update layers when map moved by at least one tile
- if ((tx != mCurX || ty != mCurY || tz != mCurZ)) {
- mWorker.submit(100);
- mCurX = tx;
- mCurY = ty;
- mCurZ = tz;
- }
-
- Task t = mWorker.poll();
- if (t == null)
- return;
- // keep position to render relative to current state
- mMapPosition.copy(t.pos);
-
- // compile new layers
- buckets.set(t.bucket.get());
- compile();
+ gb.point(latN / (Math.PI / 180), lonN / (Math.PI / 180));
}
- }
- final static class Task {
- RenderBuckets bucket = new RenderBuckets();
- MapPosition pos = new MapPosition();
+ setLineString(gb.toLineString());
}
- final class Worker extends SimpleWorker {
-
- // limit coords
- private final int max = 2048;
-
- public Worker(Map map) {
- super(map, 0, new Task(), new Task());
- mClipper = new LineClipper(-max, -max, max, max);
- mPPoints = new float[0];
- }
-
- private static final int MIN_DIST = 3;
-
- // pre-projected points
- private double[] mPreprojected = new double[2];
-
- // projected points
- private float[] mPPoints;
- private final LineClipper mClipper;
- private int mNumPoints;
-
- @Override
- public boolean doWork(Task task) {
-
- int size = mNumPoints;
-
- if (mUpdatePoints) {
- synchronized (mPoints) {
- mUpdatePoints = false;
- mNumPoints = size = mPoints.size();
-
- ArrayList geopoints = mPoints;
- double[] points = mPreprojected;
-
- if (size * 2 >= points.length) {
- points = mPreprojected = new double[size * 2];
- mPPoints = new float[size * 2];
- }
-
- for (int i = 0; i < size; i++)
- MercatorProjection.project(geopoints.get(i), points, i);
- }
-
- } else if (mGeom != null) {
- GeometryBuffer geom = mGeom;
- mGeom = null;
- size = geom.index[0];
-
- double[] points = mPreprojected;
-
- if (size > points.length) {
- points = mPreprojected = new double[size * 2];
- mPPoints = new float[size * 2];
- }
-
- for (int i = 0; i < size; i += 2)
- MercatorProjection.project(geom.points[i + 1],
- geom.points[i], points,
- i >> 1);
- mNumPoints = size = size >> 1;
-
- }
- if (size == 0) {
- if (task.bucket.get() != null) {
- task.bucket.clear();
- mMap.render();
- }
- return true;
- }
-
- RenderBuckets layers = task.bucket;
-
- LineBucket ll = layers.getLineBucket(0);
- ll.line = mLineStyle;
- ll.scale = ll.line.width;
-
- mMap.getMapPosition(task.pos);
-
- int zoomlevel = task.pos.zoomLevel;
- task.pos.scale = 1 << zoomlevel;
-
- double mx = task.pos.x;
- double my = task.pos.y;
- double scale = Tile.SIZE * task.pos.scale;
-
- // flip around dateline
- int flip = 0;
- int maxx = Tile.SIZE << (zoomlevel - 1);
-
- int x = (int) ((mPreprojected[0] - mx) * scale);
- int y = (int) ((mPreprojected[1] - my) * scale);
-
- if (x > maxx) {
- x -= (maxx * 2);
- flip = -1;
- } else if (x < -maxx) {
- x += (maxx * 2);
- flip = 1;
- }
-
- mClipper.clipStart(x, y);
-
- float[] projected = mPPoints;
- int i = addPoint(projected, 0, x, y);
-
- float prevX = x;
- float prevY = y;
-
- float[] segment = null;
-
- for (int j = 2; j < size * 2; j += 2) {
- x = (int) ((mPreprojected[j + 0] - mx) * scale);
- y = (int) ((mPreprojected[j + 1] - my) * scale);
-
- int flipDirection = 0;
- if (x > maxx) {
- x -= maxx * 2;
- flipDirection = -1;
- } else if (x < -maxx) {
- x += maxx * 2;
- flipDirection = 1;
- }
-
- if (flip != flipDirection) {
- flip = flipDirection;
- if (i > 2)
- ll.addLine(projected, i, false);
-
- mClipper.clipStart(x, y);
- i = addPoint(projected, 0, x, y);
- continue;
- }
-
- int clip = mClipper.clipNext(x, y);
- if (clip < 1) {
- if (i > 2)
- ll.addLine(projected, i, false);
-
- if (clip < 0) {
- /* add line segment */
- segment = mClipper.getLine(segment, 0);
- ll.addLine(segment, 4, false);
- prevX = mClipper.outX2;
- prevY = mClipper.outY2;
- }
- i = 0;
- continue;
- }
-
- float dx = x - prevX;
- float dy = y - prevY;
- if ((i == 0) || FastMath.absMaxCmp(dx, dy, MIN_DIST)) {
- projected[i++] = prevX = x;
- projected[i++] = prevY = y;
- }
- }
- if (i > 2)
- ll.addLine(projected, i, false);
-
- // trigger redraw to let renderer fetch the result.
- mMap.render();
-
- return true;
- }
-
- @Override
- public void cleanup(Task task) {
- task.bucket.clear();
+ public void setLineString(LineString path) {
+ synchronized (this) {
+ if (mDrawable != null)
+ remove(mDrawable);
+ mDrawable = new LineDrawable(path, mStyle);
+ add(mDrawable);
}
+ mWorker.submit(0);
+ }
- private int addPoint(float[] points, int i, int x, int y) {
- points[i++] = x;
- points[i++] = y;
- return i;
+ public void setLineString(double[] lonLat) {
+ synchronized (this) {
+ if (mDrawable != null)
+ remove(mDrawable);
+ mDrawable = new LineDrawable(lonLat, mStyle);
+ add(mDrawable);
}
+ mWorker.submit(0);
}
+
}
diff --git a/vtm/src/org/oscim/layers/marker/ItemizedLayer.java b/vtm/src/org/oscim/layers/marker/ItemizedLayer.java
index 3e180624a..6f822483a 100644
--- a/vtm/src/org/oscim/layers/marker/ItemizedLayer.java
+++ b/vtm/src/org/oscim/layers/marker/ItemizedLayer.java
@@ -21,7 +21,7 @@
import java.util.ArrayList;
import java.util.List;
-import org.oscim.core.BoundingBox;
+import org.oscim.core.Box;
import org.oscim.core.Point;
import org.oscim.event.Gesture;
import org.oscim.event.GestureListener;
@@ -167,7 +167,9 @@ protected boolean activateSelectedItems(MotionEvent event, ActiveItem task) {
int eventY = (int) event.getY() - mMap.getHeight() / 2;
Viewport mapPosition = mMap.viewport();
- BoundingBox bbox = mapPosition.getBBox(128);
+ Box box = mapPosition.getBBox(null, 128);
+ box.map2mercator();
+ box.scale(1E6);
int nearest = -1;
int inside = -1;
@@ -179,7 +181,8 @@ protected boolean activateSelectedItems(MotionEvent event, ActiveItem task) {
for (int i = 0; i < size; i++) {
Item item = mItemList.get(i);
- if (!bbox.contains(item.geoPoint))
+ if (!box.contains(item.geoPoint.longitudeE6,
+ item.geoPoint.latitudeE6))
continue;
mapPosition.toScreenPoint(item.getPoint(), mTmpPoint);
diff --git a/vtm/src/org/oscim/layers/tile/TileLoader.java b/vtm/src/org/oscim/layers/tile/TileLoader.java
index 6b5019006..d77726c57 100644
--- a/vtm/src/org/oscim/layers/tile/TileLoader.java
+++ b/vtm/src/org/oscim/layers/tile/TileLoader.java
@@ -16,12 +16,13 @@
*/
package org.oscim.layers.tile;
-import static org.oscim.tiling.ITileDataSink.QueryResult.FAILED;
-import static org.oscim.tiling.ITileDataSink.QueryResult.SUCCESS;
+import static org.oscim.tiling.QueryResult.FAILED;
+import static org.oscim.tiling.QueryResult.SUCCESS;
import org.oscim.backend.canvas.Bitmap;
import org.oscim.core.MapElement;
import org.oscim.tiling.ITileDataSink;
+import org.oscim.tiling.QueryResult;
import org.oscim.utils.PausableThread;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -95,9 +96,9 @@ public void completed(QueryResult result) {
boolean ok = (result == SUCCESS);
if (ok && (isCanceled() || isInterrupted()))
- ok = false;
+ result = QueryResult.FAILED;
- mTileManager.jobCompleted(mTile, ok);
+ mTileManager.jobCompleted(mTile, result);
mTile = null;
}
diff --git a/vtm/src/org/oscim/layers/tile/TileManager.java b/vtm/src/org/oscim/layers/tile/TileManager.java
index 7bb134146..d953be4a8 100644
--- a/vtm/src/org/oscim/layers/tile/TileManager.java
+++ b/vtm/src/org/oscim/layers/tile/TileManager.java
@@ -37,6 +37,7 @@
import org.oscim.map.Map;
import org.oscim.map.Viewport;
import org.oscim.renderer.BufferObject;
+import org.oscim.tiling.QueryResult;
import org.oscim.utils.ScanBox;
import org.oscim.utils.quadtree.TileIndex;
import org.slf4j.Logger;
@@ -576,29 +577,33 @@ private void limitCache(MapPosition pos, int remove) {
* @param tile
* Tile ready for upload in TileRenderLayer
*/
- public void jobCompleted(MapTile tile, boolean success) {
+ public void jobCompleted(MapTile tile, QueryResult result) {
/* send TILE_LOADED event on main-loop */
- mMap.post(new JobCompletedEvent(tile, success));
+ mMap.post(new JobCompletedEvent(tile, result));
/* locked means the tile is visible or referenced by
* a tile that might be visible. */
- if (tile.isLocked())
- mMap.render();
+ if (tile.isLocked()) {
+ if (result == QueryResult.DELAYED && tile.isLocked())
+ mMap.updateMap(false);
+ else
+ mMap.render();
+ }
}
class JobCompletedEvent implements Runnable {
final MapTile tile;
- final boolean success;
+ final QueryResult result;
- public JobCompletedEvent(MapTile tile, boolean success) {
+ public JobCompletedEvent(MapTile tile, QueryResult result) {
this.tile = tile;
- this.success = success;
+ this.result = result;
}
@Override
public void run() {
- if (success && tile.state(LOADING)) {
+ if (result == QueryResult.SUCCESS && tile.state(LOADING)) {
tile.setState(NEW_DATA);
events.fire(TILE_LOADED, tile);
mTilesToUpload++;
@@ -606,7 +611,7 @@ public void run() {
}
// TODO use mMap.update(true) to retry tile loading?
log.debug("Load: {} {} state:{}",
- tile, success ? "success" : "failed",
+ tile, result,
tile.state());
/* got orphaned tile */
diff --git a/vtm/src/org/oscim/layers/tile/buildings/BuildingLayer.java b/vtm/src/org/oscim/layers/tile/buildings/BuildingLayer.java
index 7414d6771..010f4d3b0 100644
--- a/vtm/src/org/oscim/layers/tile/buildings/BuildingLayer.java
+++ b/vtm/src/org/oscim/layers/tile/buildings/BuildingLayer.java
@@ -65,7 +65,7 @@ public BuildingLayer(Map map, VectorTileLayer tileLayer, int zoomMin, int zoomMa
/** TileLoaderThemeHook */
@Override
- public boolean render(MapTile tile, RenderBuckets buckets, MapElement element,
+ public boolean process(MapTile tile, RenderBuckets buckets, MapElement element,
RenderStyle style, int level) {
if (!(style instanceof ExtrusionStyle))
diff --git a/vtm/src/org/oscim/layers/tile/buildings/S3DBTileLoader.java b/vtm/src/org/oscim/layers/tile/buildings/S3DBTileLoader.java
index 47b271da6..b8219ca7d 100644
--- a/vtm/src/org/oscim/layers/tile/buildings/S3DBTileLoader.java
+++ b/vtm/src/org/oscim/layers/tile/buildings/S3DBTileLoader.java
@@ -13,6 +13,7 @@
import org.oscim.layers.tile.TileManager;
import org.oscim.renderer.bucket.ExtrusionBucket;
import org.oscim.tiling.ITileDataSource;
+import org.oscim.tiling.QueryResult;
import org.oscim.tiling.TileSource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
diff --git a/vtm/src/org/oscim/layers/tile/vector/VectorTileLayer.java b/vtm/src/org/oscim/layers/tile/vector/VectorTileLayer.java
index 47a912bc7..f5b628c25 100644
--- a/vtm/src/org/oscim/layers/tile/vector/VectorTileLayer.java
+++ b/vtm/src/org/oscim/layers/tile/vector/VectorTileLayer.java
@@ -145,7 +145,7 @@ public interface TileLoaderProcessHook {
*/
public interface TileLoaderThemeHook {
/** Called for each RenderStyle found for a MapElement. */
- public boolean render(MapTile tile, RenderBuckets buckets,
+ public boolean process(MapTile tile, RenderBuckets buckets,
MapElement element, RenderStyle style, int level);
/** Called on loader thread when tile loading is completed */
@@ -177,7 +177,7 @@ public void callThemeHooks(MapTile tile, RenderBuckets layers, MapElement elemen
LList th = mLoaderThemeHooks.head();
while (th != null) {
- if (th.data.render(tile, layers, element, style, level))
+ if (th.data.process(tile, layers, element, style, level))
return;
th = th.next;
diff --git a/vtm/src/org/oscim/layers/tile/vector/VectorTileLoader.java b/vtm/src/org/oscim/layers/tile/vector/VectorTileLoader.java
index 720630b3a..12c1c38db 100644
--- a/vtm/src/org/oscim/layers/tile/vector/VectorTileLoader.java
+++ b/vtm/src/org/oscim/layers/tile/vector/VectorTileLoader.java
@@ -41,6 +41,7 @@
import org.oscim.theme.styles.SymbolStyle;
import org.oscim.theme.styles.TextStyle;
import org.oscim.tiling.ITileDataSource;
+import org.oscim.tiling.QueryResult;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
diff --git a/vtm/src/org/oscim/layers/tile/vector/labeling/LabelTileLoaderHook.java b/vtm/src/org/oscim/layers/tile/vector/labeling/LabelTileLoaderHook.java
index b30b8e31e..6686014c9 100644
--- a/vtm/src/org/oscim/layers/tile/vector/labeling/LabelTileLoaderHook.java
+++ b/vtm/src/org/oscim/layers/tile/vector/labeling/LabelTileLoaderHook.java
@@ -31,7 +31,7 @@ private LabelTileData get(MapTile tile) {
}
@Override
- public boolean render(MapTile tile, RenderBuckets buckets, MapElement element,
+ public boolean process(MapTile tile, RenderBuckets buckets, MapElement element,
RenderStyle style, int level) {
if (style instanceof TextStyle) {
diff --git a/vtm/src/org/oscim/layers/vector/AbstractVectorLayer.java b/vtm/src/org/oscim/layers/vector/AbstractVectorLayer.java
index 25192667c..a3c90a20c 100644
--- a/vtm/src/org/oscim/layers/vector/AbstractVectorLayer.java
+++ b/vtm/src/org/oscim/layers/vector/AbstractVectorLayer.java
@@ -1,9 +1,8 @@
package org.oscim.layers.vector;
-import org.oscim.core.BoundingBox;
+import org.oscim.core.Box;
import org.oscim.core.GeometryBuffer;
import org.oscim.core.MapPosition;
-import org.oscim.core.Tile;
import org.oscim.event.Event;
import org.oscim.layers.Layer;
import org.oscim.map.Map;
@@ -26,13 +25,10 @@ public abstract class AbstractVectorLayer extends Layer implements UpdateList
protected final TileClipper mClipper = new TileClipper(-1024, -1024, 1024, 1024);
protected final Worker mWorker;
- protected long mUpdateDelay = 100;
+ protected long mUpdateDelay = 50;
protected boolean mUpdate = true;
- protected double mMinX;
- protected double mMinY;
-
public AbstractVectorLayer(Map map) {
super(map);
mWorker = new Worker(mMap);
@@ -52,7 +48,7 @@ public void onMapEvent(Event e, MapPosition pos) {
mUpdate = false;
mWorker.submit(0);
} else if (e == Map.POSITION_EVENT || e == Map.CLEAR_EVENT) {
- // throttle worker
+ /* throttle worker */
mWorker.submit(mUpdateDelay);
}
}
@@ -61,7 +57,7 @@ public void update() {
mWorker.submit(0);
}
- abstract protected void processFeatures(Task t, BoundingBox b);
+ abstract protected void processFeatures(Task t, Box b);
protected static class Task {
public final RenderBuckets buckets = new RenderBuckets();
@@ -84,28 +80,69 @@ public void cleanup(Task t) {
/** running on worker thread */
@Override
public boolean doWork(Task t) {
- Viewport v = mMap.viewport();
- BoundingBox bbox;
+
+ Box bbox;
+ float[] box = new float[8];
+
+ Viewport v = mMap.viewport().getSyncViewport();
synchronized (v) {
- bbox = v.getBBox();
+ bbox = v.getBBox(null, 0);
+ v.getMapExtents(box, 0);
v.getMapPosition(t.position);
}
- double scale = t.position.scale * Tile.SIZE;
+ /* Hmm what is this for? */
+ // double scale = t.position.scale * Tile.SIZE;
+ // t.position.x = (long) (t.position.x * scale) / scale;
+ // t.position.y = (long) (t.position.y * scale) / scale;
+
+ bbox.map2mercator();
+
+ // double xmin = bbox.xmin;
+ // double xmax = bbox.xmax;
+ // Box lbox = null;
+ // Box rbox = null;
+ // if (bbox.xmin < -180) {
+ // bbox.xmin = -180;
+ // lbox = new Box(bbox);
+ // }
+ // if (bbox.xmax > 180) {
+ // bbox.xmax = 180;
+ // rbox = new Box(bbox);
+ // }
- t.position.x = (long) (t.position.x * scale) / scale;
- t.position.y = (long) (t.position.y * scale) / scale;
processFeatures(t, bbox);
+ //if (lbox != null) {
+ // t.position.x += 1;
+ // lbox.xmax = 180;
+ // lbox.xmin = xmin + 180;
+ // processFeatures(t, lbox);
+ // t.position.x -= 1;
+ //}
+ //
+ //if (rbox != null) {
+ // t.position.x -= 1;
+ // rbox.xmin = -180;
+ // rbox.xmax = xmax - 180;
+ // processFeatures(t, rbox);
+ // t.position.x += 1;
+ //}
+
+ t.buckets.prepare();
+
mMap.render();
return true;
}
-
}
public class Renderer extends BucketRenderer {
MapPosition mTmpPos = new MapPosition();
+ public Renderer() {
+ mFlipOnDateLine = true;
+ }
+
@Override
public void update(GLViewport v) {
@@ -120,7 +157,6 @@ public void update(GLViewport v) {
buckets.setFrom(t.buckets);
compile();
- //log.debug("is ready " + isReady() + " " + layers.getSize());
}
}
}
diff --git a/vtm/src/org/oscim/layers/vector/JtsConverter.java b/vtm/src/org/oscim/layers/vector/JtsConverter.java
new file mode 100644
index 000000000..ec62c5352
--- /dev/null
+++ b/vtm/src/org/oscim/layers/vector/JtsConverter.java
@@ -0,0 +1,81 @@
+package org.oscim.layers.vector;
+
+import static org.oscim.core.MercatorProjection.latitudeToY;
+import static org.oscim.core.MercatorProjection.longitudeToX;
+
+import org.oscim.core.GeometryBuffer;
+
+import com.vividsolutions.jts.geom.Coordinate;
+import com.vividsolutions.jts.geom.CoordinateSequence;
+import com.vividsolutions.jts.geom.LineString;
+import com.vividsolutions.jts.geom.Point;
+import com.vividsolutions.jts.geom.Polygon;
+
+public class JtsConverter {
+ double x, y, scale;
+ final double outScale;
+
+ public void setPosition(double x, double y, double scale) {
+ this.x = x;
+ this.y = y;
+ this.scale = scale * outScale;
+ }
+
+ public JtsConverter(double outScale) {
+ this.outScale = outScale;
+ }
+
+ private final Coordinate mTmpCoord = new Coordinate();
+
+ public void transformPolygon(GeometryBuffer g, Polygon polygon) {
+ Coordinate coord = mTmpCoord;
+
+ CoordinateSequence ring = polygon.getExteriorRing().getCoordinateSequence();
+
+ g.startPolygon();
+ for (int j = 0; j < ring.size() - 1; j++) {
+ ring.getCoordinate(j, coord);
+ addPoint(g, coord);
+ }
+ for (int j = 0, n = polygon.getNumInteriorRing(); j < n; j++) {
+ g.startHole();
+ ring = polygon.getInteriorRingN(j).getCoordinateSequence();
+ for (int k = 0; k < ring.size() - 1; k++) {
+ ring.getCoordinate(k, coord);
+ addPoint(g, coord);
+ }
+ }
+ }
+
+ public void transformLineString(GeometryBuffer g, LineString linestring) {
+ Coordinate coord = mTmpCoord;
+
+ CoordinateSequence line = linestring.getCoordinateSequence();
+
+ g.startLine();
+ for (int j = 0, n = line.size(); j < n; j++) {
+ line.getCoordinate(j, coord);
+ addPoint(g, coord);
+ }
+ }
+
+ public void transformPoint(GeometryBuffer g, Point point) {
+ Coordinate coord = mTmpCoord;
+
+ g.startPoints();
+ coord.x = point.getX();
+ coord.y = point.getY();
+ addPoint(g, coord);
+ }
+
+ public void addPoint(GeometryBuffer g, Coordinate coord) {
+ g.addPoint((float) ((longitudeToX(coord.x) - x) * scale),
+ (float) ((latitudeToY(coord.y) - y) * scale));
+ }
+
+ public void addPoint(GeometryBuffer g, double lon, double lat) {
+ g.addPoint((float) ((longitudeToX(lon) - x) * scale),
+ (float) ((latitudeToY(lat) - y) * scale));
+ }
+
+}
diff --git a/vtm/src/org/oscim/layers/vector/VectorLayer.java b/vtm/src/org/oscim/layers/vector/VectorLayer.java
new file mode 100644
index 000000000..a4067c22c
--- /dev/null
+++ b/vtm/src/org/oscim/layers/vector/VectorLayer.java
@@ -0,0 +1,321 @@
+package org.oscim.layers.vector;
+
+import static org.oscim.core.MercatorProjection.latitudeToY;
+import static org.oscim.core.MercatorProjection.longitudeToX;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.oscim.backend.canvas.Color;
+import org.oscim.core.Box;
+import org.oscim.core.GeometryBuffer;
+import org.oscim.core.MapPosition;
+import org.oscim.core.Tile;
+import org.oscim.layers.vector.geometries.Drawable;
+import org.oscim.layers.vector.geometries.LineDrawable;
+import org.oscim.layers.vector.geometries.PointDrawable;
+import org.oscim.layers.vector.geometries.Style;
+import org.oscim.map.Map;
+import org.oscim.renderer.bucket.LineBucket;
+import org.oscim.renderer.bucket.MeshBucket;
+import org.oscim.theme.styles.AreaStyle;
+import org.oscim.theme.styles.LineStyle;
+import org.oscim.utils.FastMath;
+import org.oscim.utils.QuadTree;
+import org.oscim.utils.SpatialIndex;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.vividsolutions.jts.geom.Envelope;
+import com.vividsolutions.jts.geom.Geometry;
+import com.vividsolutions.jts.geom.LineString;
+import com.vividsolutions.jts.geom.Point;
+import com.vividsolutions.jts.geom.Polygon;
+import com.vividsolutions.jts.simplify.DouglasPeuckerSimplifier;
+
+/* TODO keep bounding box of geometries - only try to render when bbox intersects viewport */
+
+/**
+ * Use this layer to draw predefined geometries from layers.vector.geometries
+ * package and
+ * JTS geometries together with a GeometryStyle
+ *
+ */
+public class VectorLayer extends AbstractVectorLayer {
+
+ public static final Logger log = LoggerFactory.getLogger(VectorLayer.class);
+
+ //private final SpatialIndex mDrawables = new RTree();
+ protected final SpatialIndex mDrawables = new QuadTree(1 << 30, 18);
+
+ protected final List tmpDrawables = new ArrayList(128);
+
+ protected final JtsConverter mConverter;
+ protected double mMinX;
+ protected double mMinY;
+
+ private static class GeometryWithStyle implements Drawable {
+ final Geometry geometry;
+ final Style style;
+
+ GeometryWithStyle(Geometry g, Style s) {
+ geometry = g;
+ style = s;
+ }
+
+ @Override
+ public Style getStyle() {
+ return style;
+ }
+
+ @Override
+ public Geometry getGeometry() {
+ return geometry;
+ }
+ }
+
+ protected Polygon mEnvelope;
+
+ public VectorLayer(Map map, SpatialIndex index) {
+ this(map);
+ }
+
+ public VectorLayer(Map map) {
+ super(map);
+ mConverter = new JtsConverter(Tile.SIZE / UNSCALE_COORD);
+ }
+
+ private static Box bbox(Geometry geometry, Style style) {
+ Envelope e = geometry.getEnvelopeInternal();
+ Box bbox = new Box(e.getMinX(), e.getMinY(), e.getMaxX(), e.getMaxY());
+ //if ("Point".equals(geometry.getGeometryType())){
+ // bbox.
+ //}
+
+ bbox.scale(1E6);
+ return bbox;
+ }
+
+ /**
+ * Adds a drawable to a list of geometries that have to be drawn in the next
+ * map update.
+ *
+ * @param drawable
+ */
+ public void add(Drawable drawable) {
+ mDrawables.insert(bbox(drawable.getGeometry(), drawable.getStyle()), drawable);
+ }
+
+ /**
+ * Adds a JTS geometry and a style to a list of geometries that have to be
+ * drawn in the next map update.
+ *
+ * @param geometry
+ * @param style
+ */
+ public synchronized void add(Geometry geometry, Style style) {
+ mDrawables.insert(bbox(geometry, style), new GeometryWithStyle(geometry, style));
+ }
+
+ /**
+ * Removes the drawable from the list of drawn geometries.
+ *
+ * @param drawable
+ */
+ public synchronized void remove(Drawable drawable) {
+ mDrawables.remove(bbox(drawable.getGeometry(), drawable.getStyle()), drawable);
+ }
+
+ /**
+ * removes the JTS geometry and its style from the list of drawn geometries.
+ *
+ * @param geometry
+ */
+ public synchronized void remove(Geometry geometry) {
+ Drawable toRemove = null;
+ Box bbox = bbox(geometry, null);
+
+ synchronized (this) {
+ tmpDrawables.clear();
+ mDrawables.search(bbox, tmpDrawables);
+ for (Drawable d : tmpDrawables) {
+ if (d.getGeometry() == geometry)
+ toRemove = d;
+ }
+ }
+
+ if (toRemove == null) {
+ log.error("Can't find geometry to remove.");
+ return;
+ }
+
+ mDrawables.remove(bbox, toRemove);
+ //mMap.render();
+ }
+
+ @Override
+ protected void processFeatures(Task t, Box bbox) {
+ //log.debug("bbox {}", bbox);
+ if (Double.isNaN(bbox.xmin))
+ return;
+
+ // mEnvelope = new GeomBuilder()
+ // .point(bbox.xmin, bbox.ymin)
+ // .point(bbox.xmin, bbox.ymax)
+ // .point(bbox.xmax, bbox.ymax)
+ // .point(bbox.xmax, bbox.ymin)
+ // .point(bbox.xmin, bbox.ymin)
+ // .toPolygon();
+
+ /* reduce lines points min distance */
+ mMinX = ((bbox.xmax - bbox.xmin) / mMap.getWidth());
+ mMinY = ((bbox.ymax - bbox.ymin) / mMap.getHeight());
+
+ mConverter.setPosition(t.position.x, t.position.y, t.position.scale);
+
+ bbox.scale(1E6);
+
+ int level = 0;
+ Style lastStyle = null;
+
+ /* go through features, find the matching style and draw */
+ synchronized (this) {
+ tmpDrawables.clear();
+ mDrawables.search(bbox, tmpDrawables);
+ // TODO sort by some order...
+
+ for (Drawable d : tmpDrawables) {
+ Style style = d.getStyle();
+ draw(t, level, d, style);
+
+ if (style != lastStyle)
+ level += 2;
+
+ lastStyle = style;
+ }
+ }
+ }
+
+ protected void draw(Task task, int level, Drawable d, Style style) {
+ Geometry geom = d.getGeometry();
+
+ if (d instanceof LineDrawable) {
+ drawLine(task, level, geom, style);
+ } else if (d instanceof PointDrawable) {
+ drawPoint(task, level, geom, style);
+ } else {
+ drawPolygon(task, level, geom, style);
+ }
+ }
+
+ protected void drawPoint(Task t, int level, Geometry points, Style style) {
+
+ MeshBucket mesh = t.buckets.getMeshBucket(level);
+ if (mesh.area == null) {
+ mesh.area = new AreaStyle(Color.fade(style.fillColor,
+ style.fillAlpha));
+ }
+
+ LineBucket ll = t.buckets.getLineBucket(level + 1);
+ if (ll.line == null) {
+ ll.line = new LineStyle(2, style.strokeColor, style.strokeWidth);
+ }
+
+ for (int i = 0; i < points.getNumGeometries(); i++) {
+ Point p = (Point) points.getGeometryN(i);
+ addCircle(mGeom.clear(), t.position, p.getX(), p.getY(), style);
+
+ if (!mClipper.clip(mGeom))
+ continue;
+
+ mesh.addConvexMesh(mGeom);
+ ll.addLine(mGeom);
+ }
+ }
+
+ protected void drawLine(Task t, int level, Geometry line, Style style) {
+
+ LineBucket ll = t.buckets.getLineBucket(level);
+ if (ll.line == null) {
+ ll.line = new LineStyle(0, style.strokeColor, style.strokeWidth);
+ }
+
+ if (style.generalization != Style.GENERALIZATION_NONE) {
+ line = DouglasPeuckerSimplifier.simplify(line, mMinX * style.generalization);
+ }
+
+ //line = line.intersection(mEnvelope);
+
+ for (int i = 0; i < line.getNumGeometries(); i++) {
+ mConverter.transformLineString(mGeom.clear(), (LineString) line.getGeometryN(i));
+ if (!mClipper.clip(mGeom))
+ continue;
+
+ ll.addLine(mGeom);
+ }
+ }
+
+ protected void drawPolygon(Task t, int level, Geometry polygon, Style style) {
+
+ MeshBucket mesh = t.buckets.getMeshBucket(level);
+ if (mesh.area == null) {
+ mesh.area = new AreaStyle(Color.fade(style.fillColor,
+ style.fillAlpha));
+ }
+
+ LineBucket ll = t.buckets.getLineBucket(level + 1);
+ if (ll.line == null) {
+ ll.line = new LineStyle(2, style.strokeColor, style.strokeWidth);
+ }
+
+ if (style.generalization != Style.GENERALIZATION_NONE) {
+ polygon = DouglasPeuckerSimplifier.simplify(polygon, mMinX * style.generalization);
+ }
+
+ // if (polygon.isRectangle())
+
+ for (int i = 0; i < polygon.getNumGeometries(); i++) {
+ mConverter.transformPolygon(mGeom.clear(), (Polygon) polygon.getGeometryN(i));
+
+ if (mGeom.getNumPoints() < 3)
+ continue;
+
+ if (!mClipper.clip(mGeom))
+ continue;
+
+ mesh.addMesh(mGeom);
+ ll.addLine(mGeom);
+ }
+ }
+
+ protected void addCircle(GeometryBuffer g, MapPosition pos,
+ double px, double py, Style style) {
+
+ double scale = pos.scale * Tile.SIZE / UNSCALE_COORD;
+ double x = (longitudeToX(px) - pos.x) * scale;
+ double y = (latitudeToY(py) - pos.y) * scale;
+
+ /* TODO in the next line I was only able to interpolate a function
+ * that makes up for the zoom level. The circle should not grow, it
+ * should stickto the map. 0.01 / (1 << startLvl) makes it retain
+ * its size. Correction? */
+ int zoomScale = (1 << style.scalingZoomLevel);
+
+ /* Keep the circle's size constant in relation to the underlying map */
+ double radius = style.buffer;
+
+ if (pos.scale > zoomScale)
+ radius = (radius * 0.01) / zoomScale * (scale - zoomScale);
+
+ int quality = (int) (Math.sqrt(radius) * 8);
+ quality = FastMath.clamp(quality, 4, 32);
+
+ double step = 2.0 * Math.PI / quality;
+
+ g.startPolygon();
+ for (int i = 0; i < quality; i++) {
+ g.addPoint((float) (x + radius * Math.cos(i * step)),
+ (float) (y + radius * Math.sin(i * step)));
+ }
+ }
+}
diff --git a/vtm/src/org/oscim/layers/vector/geometries/CircleDrawable.java b/vtm/src/org/oscim/layers/vector/geometries/CircleDrawable.java
new file mode 100644
index 000000000..916b15d6d
--- /dev/null
+++ b/vtm/src/org/oscim/layers/vector/geometries/CircleDrawable.java
@@ -0,0 +1,149 @@
+package org.oscim.layers.vector.geometries;
+
+import org.oscim.core.GeoPoint;
+import org.oscim.utils.geom.GeomBuilder;
+
+/**
+ * Predefined class for drawing circles on the map. Circles are by default
+ * made of 32 segments.
+ */
+public class CircleDrawable extends JtsDrawable {
+
+ public static int MEDIUM_QUALITY = 32;
+ public static int HIGH_QUALITY = 64;
+
+ /**
+ * Constructs a circle given the real-world radius in km. Keep in mind that
+ * this technique is computationally costly for circles with huge number or
+ * segments.
+ *
+ * @param center GeoPoint - center of the circle
+ * @param radiusKm Radius of the circle in kilometers.
+ */
+ public CircleDrawable(GeoPoint center, double radiusKm) {
+ super(Style.DEFAULT_STYLE);
+ GeomBuilder gb = new GeomBuilder();
+ for (int i = 0; i < MEDIUM_QUALITY; i++) {
+ GeoPoint point = findGeoPointWithGivenDistance(center,
+ i * Math.PI / MEDIUM_QUALITY * 2,
+ radiusKm);
+ gb.points(point.getLongitude(), point.getLatitude());
+ }
+ geometry = gb.toPolygon();
+ }
+
+ /**
+ * Constructs a circle given the real-world radius in km. Keep in mind that
+ * this technique is computationally costly for circles with huge number or
+ * segments.
+ *
+ * @param center GeoPoint - center of the circle
+ * @param radiusKm Radius of the circle in kilometers. The size of the
+ * circle may be distorted due to the Mercator projections
+ * properties.
+ * @param style FillableGeometryStyle with color and transparency
+ * information for the circle
+ */
+ public CircleDrawable(GeoPoint center, double radiusKm, Style style) {
+ super(style);
+ GeomBuilder gb = new GeomBuilder();
+ for (int i = 0; i < MEDIUM_QUALITY; i++) {
+ GeoPoint point = findGeoPointWithGivenDistance(center,
+ i * Math.PI / MEDIUM_QUALITY * 2,
+ radiusKm);
+ gb.points(point.getLongitude(), point.getLatitude());
+ }
+ geometry = gb.toPolygon();
+ }
+
+ /**
+ * Constructs a circle given the real-world radius in km. Keep in mind that
+ * this technique is computationally costly for circles with huge number or
+ * segments.
+ *
+ * @param center GeoPoint - center of the circle
+ * @param radiusKm Radius of the circle in kilometers. The size of the
+ * circle may be distorted due to the Mercator projections
+ * properties.
+ * @param quadrantSegments the number of segments a quarter of circle will
+ * have. Use Circle.LOW_PRECISION for quick rendering,
+ * Circle.MEDIUM_PRECISION for good rendering and quality or
+ * Circle.HIGH_PRECISION for high quality.
+ * @param style FillableGeometryStyle with color and transparency
+ * information for the circle
+ */
+ public CircleDrawable(GeoPoint center, double radiusKm, int quadrantSegments,
+ Style style) {
+ super(style);
+ GeomBuilder gb = new GeomBuilder();
+ for (int i = 0; i < quadrantSegments; i++) {
+ GeoPoint point = findGeoPointWithGivenDistance(center,
+ i * Math.PI / quadrantSegments * 2,
+ radiusKm);
+ gb.points(point.getLongitude(), point.getLatitude());
+ }
+ geometry = gb.toPolygon();
+ }
+
+ /**
+ * This function finds a GeoPoint offset by a distance in the direction
+ * given in the bearing parameter. It is an approximation due to the
+ * Mercator projections properties
+ *
+ * @param startPoint
+ * @param initialBearingRadians
+ * @param distanceKilometres
+ * @return a new GeoPoint located distanceKilometers away from the
+ * startPoint in the direction of the initialBearing
+ */
+ private static GeoPoint findGeoPointWithGivenDistance(GeoPoint startPoint,
+ double initialBearingRadians, double distanceKilometres)
+ {
+ double radiusEarthKilometres = 6371.01;
+ double distRatio = distanceKilometres / radiusEarthKilometres;
+ double distRatioSine = Math.sin(distRatio);
+ double distRatioCosine = Math.cos(distRatio);
+
+ double startLatRad = degreesToRadians(startPoint.getLatitude());
+ double startLonRad = degreesToRadians(startPoint.getLongitude());
+
+ double startLatCos = Math.cos(startLatRad);
+ double startLatSin = Math.sin(startLatRad);
+
+ double endLatRads = Math.asin((startLatSin * distRatioCosine)
+ + (startLatCos * distRatioSine * Math.cos(initialBearingRadians)));
+
+ double endLonRads = startLonRad
+ + Math.atan2(
+ Math.sin(initialBearingRadians) * distRatioSine * startLatCos,
+ distRatioCosine - startLatSin * Math.sin(endLatRads));
+
+ return new GeoPoint(radiansToDegrees(endLatRads), radiansToDegrees(endLonRads));
+
+ }
+
+ /**
+ * translates an angle from degrees to radians
+ *
+ * @param degrees
+ * @return the angle in radians
+ */
+ private static double degreesToRadians(double degrees)
+ {
+ double degToRadFactor = Math.PI / 180;
+ return degrees * degToRadFactor;
+ }
+
+ /**
+ * translates an angle from radians to degrees
+ *
+ * @param radians
+ * @return the angle in degrees
+ */
+ private static double radiansToDegrees(double radians)
+ {
+ double radToDegFactor = 180 / Math.PI;
+ return radians * radToDegFactor;
+ }
+
+}
diff --git a/vtm/src/org/oscim/layers/vector/geometries/Drawable.java b/vtm/src/org/oscim/layers/vector/geometries/Drawable.java
new file mode 100644
index 000000000..9214e1e43
--- /dev/null
+++ b/vtm/src/org/oscim/layers/vector/geometries/Drawable.java
@@ -0,0 +1,16 @@
+package org.oscim.layers.vector.geometries;
+
+import com.vividsolutions.jts.geom.Geometry;
+
+public interface Drawable {
+
+ /**
+ * @return
+ */
+ public Style getStyle();
+
+ /**
+ * @return
+ */
+ public Geometry getGeometry();
+}
diff --git a/vtm/src/org/oscim/layers/vector/geometries/HexagonDrawable.java b/vtm/src/org/oscim/layers/vector/geometries/HexagonDrawable.java
new file mode 100644
index 000000000..74d919e08
--- /dev/null
+++ b/vtm/src/org/oscim/layers/vector/geometries/HexagonDrawable.java
@@ -0,0 +1,88 @@
+package org.oscim.layers.vector.geometries;
+
+import org.oscim.core.GeoPoint;
+import org.oscim.core.MercatorProjection;
+import org.oscim.core.Point;
+import org.oscim.utils.geom.GeomBuilder;
+
+/**
+ * Predefined class for drawing hexagons on the map.
+ */
+public class HexagonDrawable extends JtsDrawable {
+
+ /**
+ * @param center GeoPoint - center of the hexagon
+ * @param radiusKm Radius of the hexagon in kilometers. The size of the
+ * hexagon may be distorted due to the Mercator projections
+ * properties.
+ */
+ public HexagonDrawable(GeoPoint center, double radiusKm) {
+ super(Style.DEFAULT_STYLE);
+ GeomBuilder gb = new GeomBuilder();
+
+ for (int i = 0; i < 6; i++) {
+ GeoPoint point = findGeoPointWithGivenDistance(center, i * Math.PI / 3, radiusKm);
+ gb.points(point.getLongitude(), point.getLatitude());
+ }
+ geometry = gb.toPolygon();
+ }
+
+ /**
+ * @param center GeoPoint - center of the hexagon
+ * @param radiusKm Radius of the hexagon in kilometers. The size of the
+ * hexagon may be distorted due to the Mercator projections
+ * properties.
+ * @param rotationRad rotation of the hexagon in radians
+ * @param style
+ */
+ public HexagonDrawable(GeoPoint center, double radiusKm, double rotationRad, Style style) {
+ super(style);
+ GeomBuilder gb = new GeomBuilder();
+ Point tmp = new Point();
+
+ for (int i = 0; i < 6; i++) {
+ GeoPoint point = findGeoPointWithGivenDistance(center,
+ rotationRad + i * Math.PI / 3,
+ radiusKm);
+ MercatorProjection.project(point, tmp);
+ gb.points(tmp.x, tmp.y);
+ }
+ geometry = gb.toPolygon();
+ }
+
+ /**
+ * This function finds a GeoPoint offset by a distance in the direction
+ * given in the bearing parameter. It is an approximation due to the
+ * Mercator projections properties
+ *
+ * @param startPoint
+ * @param initialBearingRadians
+ * @param distanceKilometres
+ * @return a new GeoPoint located distanceKilometers away from the
+ * startPoint in the direction of the initialBearing
+ */
+ private static GeoPoint findGeoPointWithGivenDistance(GeoPoint startPoint,
+ double initialBearingRadians, double distanceKilometres)
+ {
+ double radiusEarthKilometres = 6371.01;
+ double distRatio = distanceKilometres / radiusEarthKilometres;
+ double distRatioSine = Math.sin(distRatio);
+ double distRatioCosine = Math.cos(distRatio);
+
+ double startLatRad = Math.toRadians(startPoint.getLatitude());
+ double startLonRad = Math.toRadians(startPoint.getLongitude());
+
+ double startLatCos = Math.cos(startLatRad);
+ double startLatSin = Math.sin(startLatRad);
+
+ double endLatRads = Math.asin((startLatSin * distRatioCosine)
+ + (startLatCos * distRatioSine * Math.cos(initialBearingRadians)));
+
+ double endLonRads = startLonRad
+ + Math.atan2(
+ Math.sin(initialBearingRadians) * distRatioSine * startLatCos,
+ distRatioCosine - startLatSin * Math.sin(endLatRads));
+
+ return new GeoPoint(Math.toDegrees(endLatRads), Math.toDegrees(endLonRads));
+ }
+}
diff --git a/vtm/src/org/oscim/layers/vector/geometries/JtsDrawable.java b/vtm/src/org/oscim/layers/vector/geometries/JtsDrawable.java
new file mode 100644
index 000000000..beea3093c
--- /dev/null
+++ b/vtm/src/org/oscim/layers/vector/geometries/JtsDrawable.java
@@ -0,0 +1,64 @@
+package org.oscim.layers.vector.geometries;
+
+import java.util.List;
+
+import org.oscim.core.GeoPoint;
+import org.oscim.utils.geom.GeomBuilder;
+
+import com.vividsolutions.jts.geom.Geometry;
+import com.vividsolutions.jts.geom.GeometryFactory;
+import com.vividsolutions.jts.geom.impl.PackedCoordinateSequenceFactory;
+
+public class JtsDrawable implements Drawable {
+
+ public static final PackedCoordinateSequenceFactory coordFactory;
+ public static final GeometryFactory geomFactory;
+ static {
+ coordFactory = new PackedCoordinateSequenceFactory();
+ geomFactory = new GeometryFactory(coordFactory);
+ }
+
+ protected Style style;
+ protected Geometry geometry;
+
+ public JtsDrawable(Style style) {
+ this.style = style;
+ }
+
+ public JtsDrawable(Geometry geometry, Style style) {
+ this.geometry = geometry;
+ this.style = style;
+ }
+
+ /**
+ * @param style
+ */
+ public void setStyle(Style style) {
+ this.style = style;
+ }
+
+ /* (non-Javadoc)
+ *
+ * @see org.oscim.core.geometries.Drawable#getStyle() */
+ @Override
+ public Style getStyle() {
+ return style;
+ }
+
+ /* (non-Javadoc)
+ *
+ * @see org.oscim.core.geometries.Drawable#getGeometry() */
+ @Override
+ public Geometry getGeometry() {
+ return geometry;
+ }
+
+ protected static GeomBuilder loadPoints(GeomBuilder gb, List points) {
+ for (GeoPoint point : points) {
+ gb.point(point.getLongitude(),
+ point.getLatitude());
+ }
+ return gb;
+ }
+
+}
diff --git a/vtm/src/org/oscim/layers/vector/geometries/LineDrawable.java b/vtm/src/org/oscim/layers/vector/geometries/LineDrawable.java
new file mode 100644
index 000000000..ed608ef3a
--- /dev/null
+++ b/vtm/src/org/oscim/layers/vector/geometries/LineDrawable.java
@@ -0,0 +1,44 @@
+package org.oscim.layers.vector.geometries;
+
+import java.util.List;
+
+import org.oscim.core.GeoPoint;
+
+import com.vividsolutions.jts.geom.Geometry;
+import com.vividsolutions.jts.geom.LineString;
+
+/**
+ * Predefined class for drawing lines and line strings on the map.
+ */
+public class LineDrawable extends JtsDrawable {
+
+ public LineDrawable(Geometry line, Style style) {
+ super(style);
+ if (line.getDimension() != 1)
+ throw new IllegalArgumentException("Geometry not a Line");
+
+ this.geometry = line;
+ }
+
+ public LineDrawable(List points) {
+ this(points, Style.defaultStyle());
+ }
+
+ public LineDrawable(List points, Style style) {
+ super(style);
+ if (points.size() < 2)
+ return;
+
+ double[] coords = new double[points.size() * 2];
+ int c = 0;
+ for (GeoPoint p : points) {
+ coords[c++] = p.getLongitude();
+ coords[c++] = p.getLatitude();
+ }
+ this.geometry = new LineString(coordFactory.create(coords, 2), geomFactory);
+ }
+
+ public LineDrawable(double[] lonLat, Style style) {
+ this(new LineString(coordFactory.create(lonLat, 2), geomFactory), style);
+ }
+}
diff --git a/vtm/src/org/oscim/layers/vector/geometries/PointDrawable.java b/vtm/src/org/oscim/layers/vector/geometries/PointDrawable.java
new file mode 100644
index 000000000..b410f57ce
--- /dev/null
+++ b/vtm/src/org/oscim/layers/vector/geometries/PointDrawable.java
@@ -0,0 +1,36 @@
+package org.oscim.layers.vector.geometries;
+
+import org.oscim.core.GeoPoint;
+import org.oscim.utils.geom.GeomBuilder;
+
+/**
+ * Use this class to draw points and circles which size has to be specified in
+ * screen units. Points (and circles resulting from this class) do not have
+ * area,
+ * however during rendering to make the point visible at varying zoom levels
+ * a buffer area is built around it.
+ * To give the point custom size, create a GeometryBuffer with, set buffer to
+ * your value and assign the point the final style.
+ *
+ * Note that since points do not have any area, they are not generalized.
+ *
+ * Normally points retain their size in the screen units across all zoom levels
+ * but this can be customized. Use setStartLevel on the point's style to specify
+ * from which zoom level the point should "stick to the map" and not decrease in
+ * size.
+ */
+public class PointDrawable extends JtsDrawable {
+
+ public PointDrawable(GeoPoint point) {
+ this(point, Style.defaultStyle());
+ }
+
+ public PointDrawable(GeoPoint point, Style style) {
+ this(point.getLongitude(), point.getLatitude(), style);
+ }
+
+ public PointDrawable(double lat, double lon, Style style) {
+ super(style);
+ this.geometry = new GeomBuilder().points(lon, lat).toPoint();
+ }
+}
diff --git a/vtm/src/org/oscim/layers/vector/geometries/PolygonDrawable.java b/vtm/src/org/oscim/layers/vector/geometries/PolygonDrawable.java
new file mode 100644
index 000000000..febe2d464
--- /dev/null
+++ b/vtm/src/org/oscim/layers/vector/geometries/PolygonDrawable.java
@@ -0,0 +1,116 @@
+package org.oscim.layers.vector.geometries;
+
+import java.util.Arrays;
+import java.util.List;
+
+import org.oscim.core.GeoPoint;
+import org.oscim.utils.geom.GeomBuilder;
+
+import com.vividsolutions.jts.geom.Geometry;
+
+/**
+ * Predefined class to draw polygons on the map.
+ */
+public class PolygonDrawable extends JtsDrawable {
+
+ /**
+ * Creates a polygon using a JTS geometry and a FillableGeometryStyle
+ *
+ * @param polygon
+ * @param style
+ */
+ public PolygonDrawable(Geometry polygon, Style style) {
+ super(style);
+
+ if (polygon.getDimension() != 2)
+ throw new IllegalArgumentException("Geometry not a Polygon");
+
+ this.geometry = polygon;
+ }
+
+ /**
+ * Creates a polygon using the coordinates provided in the List
+ *
+ * @param points
+ */
+ public PolygonDrawable(List points) {
+ this(points, Style.defaultStyle());
+ }
+
+ /**
+ * Create a polygon given the array of GeoPoints and a FillableGeometryStyle
+ *
+ * @param points
+ * @param style
+ */
+ public PolygonDrawable(Style style, GeoPoint... points) {
+ this(Arrays.asList(points), style);
+ }
+
+ /**
+ * @param points
+ * @param style
+ */
+ public PolygonDrawable(List points, Style style) {
+ this(loadPoints(new GeomBuilder(), points).toPolygon(), style);
+ }
+
+ /**
+ * Create a polygon given the array of GeoPoints for the boundary, the array
+ * of GeoPoints for the hole and outline and fill color and alpha
+ *
+ * @param points
+ * @param holePoints
+ * @param outlineColor
+ * @param outlineAlpha
+ * @param fillColor
+ * @param fillAlpha
+ */
+ public PolygonDrawable(GeoPoint[] points, GeoPoint[] holePoints, float lineWidth,
+ int lineColor,
+ int fillColor, float fillAlpha) {
+ this(Arrays.asList(points),
+ Arrays.asList(holePoints),
+ lineWidth, lineColor, fillColor, fillAlpha);
+ }
+
+ /**
+ * Create a polygon using the Coordinates provided in the first List, with a
+ * hole build from the Coordinates in the second List and outline and fill -
+ * color and alpha
+ *
+ * @param points
+ * @param holePoints
+ * @param outlineColor
+ * @param outlineAlpha
+ * @param fillColor
+ * @param fillAlpha
+ */
+ public PolygonDrawable(List points, List holePoints,
+ float lineWidth, int lineColor, int fillColor, float fillAlpha) {
+ this(points, holePoints, new Style.Builder()
+ .strokeWidth(lineWidth)
+ .strokeColor(lineColor)
+ .fillColor(fillColor)
+ .fillAlpha(fillAlpha)
+ .build());
+ }
+
+ /**
+ * Creates a polygon from a List of coordinates in the first List, with a
+ * hole from coordinates in the second List and requires a
+ * FillableGeometryStyle for the color information
+ *
+ * @param points
+ * @param holePoints
+ * @param style
+ */
+ public PolygonDrawable(List points, List holePoints, Style style) {
+ super(style);
+ GeomBuilder gb = new GeomBuilder();
+ loadPoints(gb, points).ring();
+ loadPoints(gb, holePoints).ring();
+ this.geometry = gb.toPolygon();
+ this.style = style;
+ }
+}
diff --git a/vtm/src/org/oscim/layers/vector/geometries/RectangleDrawable.java b/vtm/src/org/oscim/layers/vector/geometries/RectangleDrawable.java
new file mode 100644
index 000000000..7f8472b0f
--- /dev/null
+++ b/vtm/src/org/oscim/layers/vector/geometries/RectangleDrawable.java
@@ -0,0 +1,55 @@
+package org.oscim.layers.vector.geometries;
+
+import org.oscim.core.GeoPoint;
+import org.oscim.utils.geom.GeomBuilder;
+
+/**
+ * Predefined class to draw rectangles on the map
+ */
+public class RectangleDrawable extends JtsDrawable {
+
+ /**
+ * Creates a Rectangle given the top-left and the bottom-right coordinate of
+ * it
+ *
+ * @param topLeft
+ * @param bottomRight
+ */
+ public RectangleDrawable(GeoPoint topLeft, GeoPoint bottomRight) {
+ this(topLeft, bottomRight, Style.defaultStyle());
+ }
+
+ /**
+ * Creates a Rectangle given the top-left and the bottom-right coordinate of
+ * it
+ *
+ * @param topLeft
+ * @param bottomRight
+ */
+ public RectangleDrawable(GeoPoint topLeft, GeoPoint bottomRight, Style style) {
+ super(style);
+ geometry = new GeomBuilder()
+ .point(topLeft.getLongitude(), topLeft.getLatitude())
+ .point(bottomRight.getLongitude(), topLeft.getLatitude())
+ .point(bottomRight.getLongitude(), bottomRight.getLatitude())
+ .point(topLeft.getLongitude(), bottomRight.getLatitude())
+ .toPolygon();
+ }
+
+ /**
+ * Creates a Rectangle given the top-left and the bottom-right coordinate of
+ * it
+ *
+ * @param topLeft
+ * @param bottomRight
+ */
+ public RectangleDrawable(double minLat, double minLon, double maxLat, double maxLon, Style style) {
+ super(style);
+ geometry = new GeomBuilder()
+ .point(minLon, minLat)
+ .point(minLon, maxLat)
+ .point(maxLon, maxLat)
+ .point(maxLon, minLat)
+ .toPolygon();
+ }
+}
diff --git a/vtm/src/org/oscim/layers/vector/geometries/Style.java b/vtm/src/org/oscim/layers/vector/geometries/Style.java
new file mode 100644
index 000000000..7298dc230
--- /dev/null
+++ b/vtm/src/org/oscim/layers/vector/geometries/Style.java
@@ -0,0 +1,198 @@
+package org.oscim.layers.vector.geometries;
+
+import org.oscim.backend.canvas.Color;
+
+/**
+ * Class encapsulating style information for drawing geometries on the map.
+ */
+public class Style {
+
+ public static final int GENERALIZATION_HIGH = 1 << 3;
+ public static final int GENERALIZATION_MEDIUM = 1 << 2;
+ public static final int GENERALIZATION_SMALL = 1 << 0;
+ public static final int GENERALIZATION_NONE = 0;
+
+ public final float strokeWidth;
+ public final int strokeColor;
+
+ public final int fillColor;
+ public final float fillAlpha;
+
+ public final double buffer;
+ public final int scalingZoomLevel;
+
+ public final int generalization;
+
+ private Style(Builder builder) {
+ strokeWidth = builder.strokeWidth;
+ strokeColor = builder.strokeColor;
+
+ fillColor = builder.fillColor;
+ fillAlpha = builder.fillAlpha;
+
+ buffer = builder.buffer;
+ scalingZoomLevel = builder.scalingZoomLevel;
+
+ generalization = builder.generalization;
+ }
+
+ /**
+ * Geometry style builder. Usage example:
+ *
+ *
+ * {
+ * Style style = Style.builder()
+ * .strokeWidth(1f).strokeColor(Color.BLACK).build();
+ * }
+ *
+ */
+ public static class Builder {
+
+ private float strokeWidth = 1f;
+ private int strokeColor = Color.GRAY;
+ private int fillColor = Color.GRAY;
+ private float fillAlpha = 0.25f;
+
+ private double buffer = 1;
+ private int scalingZoomLevel = 1;
+
+ private int generalization = GENERALIZATION_NONE;
+
+ protected Builder() {
+
+ }
+
+ /**
+ * Builds the GeometryStyle from the specified parameters.
+ *
+ * @return
+ */
+ public Style build() {
+ return new Style(this);
+ }
+
+ /**
+ * Sets the line width for the geometry's line or outline.
+ *
+ * @param lineWidth
+ * @return
+ */
+ public Builder strokeWidth(float lineWidth) {
+ this.strokeWidth = lineWidth;
+ return this;
+ }
+
+ /**
+ * Sets the color for the geometry's line or outline.
+ *
+ * @param stokeColor
+ * @return
+ */
+ public Builder strokeColor(int stokeColor) {
+ this.strokeColor = stokeColor;
+ return this;
+ }
+
+ /**
+ * Sets the color for the geometry's area.
+ *
+ * @param fillColor
+ * @return
+ */
+ public Builder fillColor(int fillColor) {
+ this.fillColor = fillColor;
+ return this;
+ }
+
+ /**
+ * Sets alpha channel value for the geometry's area.
+ *
+ * @param fillAlpha
+ * @return
+ */
+ public Builder fillAlpha(double fillAlpha) {
+ this.fillAlpha = (float) fillAlpha;
+ return this;
+ }
+
+ /**
+ * This function has effect only on Points:
+ * use it to control the size on the circle that
+ * will be built from a buffer around the point.
+ *
+ * @param buffer
+ * @return itself
+ */
+ public Builder buffer(double buffer) {
+ this.buffer = buffer;
+ return this;
+ }
+
+ /**
+ * This function has effect only on Points:
+ * use it to specify from which zoom level the point
+ * should stop decreasing in size and "stick to the map".
+ *
+ * @param zoomlvl
+ */
+ public Builder scaleZoomLevel(int zoomlvl) {
+ this.scalingZoomLevel = zoomlvl;
+ return this;
+ }
+
+ /**
+ * Sets generalization factor for the geometry.
+ * Use predefined GeometryStyle.GENERALIZATION_HIGH,
+ * GENERALIZATION_MEDIUM or GENERALIZATION_SMALL
+ *
+ * @param generalization
+ * @return
+ */
+ public Builder generalization(int generalization) {
+ this.generalization = generalization;
+ return this;
+ }
+ }
+
+ public float getStrokeWidth() {
+ return strokeWidth;
+ }
+
+ public int getStrokeColor() {
+ return strokeColor;
+ }
+
+ public int getFillColor() {
+ return fillColor;
+ }
+
+ public float getFillAlpha() {
+ return fillAlpha;
+ }
+
+ public int getGeneralization() {
+ return generalization;
+ }
+
+ public double getBuffer() {
+ return buffer;
+ }
+
+ public int getScalingZoomLevel() {
+ return scalingZoomLevel;
+ }
+
+ static final Style DEFAULT_STYLE = new Builder()
+ .fillColor(0xcccccccc)
+ .fillAlpha(1)
+ .build();
+
+ public static Style defaultStyle() {
+ return DEFAULT_STYLE;
+ }
+
+ public static Style.Builder builder() {
+ return new Style.Builder();
+ }
+
+}
diff --git a/vtm/src/org/oscim/map/Animator.java b/vtm/src/org/oscim/map/Animator.java
index 0bf182b2c..50ced6602 100644
--- a/vtm/src/org/oscim/map/Animator.java
+++ b/vtm/src/org/oscim/map/Animator.java
@@ -27,14 +27,14 @@
import org.oscim.core.Point;
import org.oscim.core.Tile;
import org.oscim.renderer.MapRenderer;
+import org.oscim.utils.ThreadUtils;
+import org.oscim.utils.async.Task;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class Animator {
static final Logger log = LoggerFactory.getLogger(Animator.class);
- //static final Logger log = LoggerFactory.getLogger(MapAnimator.class);
-
private final static int ANIM_NONE = 0;
private final static int ANIM_MOVE = 1 << 0;
private final static int ANIM_SCALE = 1 << 1;
@@ -62,6 +62,8 @@ public Animator(Map map) {
}
public synchronized void animateTo(long duration, BoundingBox bbox) {
+ ThreadUtils.assertMainThread();
+
mMap.getMapPosition(mStartPos);
/* TODO for large distance first scale out, then in
* calculate the maximum scale at which the BoundingBox
@@ -89,18 +91,28 @@ public synchronized void animateTo(long duration, BoundingBox bbox) {
animStart(duration, ANIM_MOVE | ANIM_SCALE | ANIM_ROTATE | ANIM_TILT);
}
- public synchronized void animateTo(BoundingBox bbox) {
+ public void animateTo(BoundingBox bbox) {
animateTo(1000, bbox);
}
- public synchronized void animateTo(long duration, GeoPoint geoPoint,
+ /**
+ * Animate to GeoPoint
+ *
+ * @param duration in ms
+ * @param geoPoint
+ * @param scale
+ * @param relative alter scale relative to current scale
+ */
+ public void animateTo(long duration, GeoPoint geoPoint,
double scale, boolean relative) {
+ ThreadUtils.assertMainThread();
+
mMap.getMapPosition(mStartPos);
if (relative)
scale = mStartPos.scale * scale;
- scale = clamp(scale, Viewport.MIN_SCALE, Viewport.MAX_SCALE);
+ scale = mMap.viewport().limitScale(scale);
mDeltaPos.set(longitudeToX(geoPoint.getLongitude()) - mStartPos.x,
latitudeToY(geoPoint.getLatitude()) - mStartPos.y,
@@ -110,28 +122,30 @@ public synchronized void animateTo(long duration, GeoPoint geoPoint,
animStart(duration, ANIM_MOVE | ANIM_SCALE);
}
- public synchronized void animateTo(GeoPoint p) {
+ public void animateTo(GeoPoint p) {
animateTo(500, p, 1, true);
}
- public synchronized void animateTo(long duration, MapPosition pos) {
+ public void animateTo(long duration, MapPosition pos) {
+ ThreadUtils.assertMainThread();
+
mMap.getMapPosition(mStartPos);
- pos.scale = clamp(pos.scale,
- Viewport.MIN_SCALE,
- Viewport.MAX_SCALE);
+ pos.scale = mMap.viewport().limitScale(pos.scale);
mDeltaPos.set(pos.x - mStartPos.x,
pos.y - mStartPos.y,
pos.scale - mStartPos.scale,
pos.bearing - mStartPos.bearing,
- clamp(pos.tilt, 0, Viewport.MAX_TILT) - mStartPos.tilt);
+ mMap.viewport().limitTilt(pos.tilt) - mStartPos.tilt);
animStart(duration, ANIM_MOVE | ANIM_SCALE | ANIM_ROTATE | ANIM_TILT);
}
- public synchronized void animateZoom(long duration, double scaleBy,
+ public void animateZoom(long duration, double scaleBy,
float pivotX, float pivotY) {
+ ThreadUtils.assertMainThread();
+
mMap.getMapPosition(mCurPos);
if (mState == ANIM_SCALE)
@@ -140,7 +154,7 @@ public synchronized void animateZoom(long duration, double scaleBy,
scaleBy = mCurPos.scale * scaleBy;
mStartPos.copy(mCurPos);
- scaleBy = clamp(scaleBy, Viewport.MIN_SCALE, Viewport.MAX_SCALE);
+ scaleBy = mMap.viewport().limitScale(scaleBy);
mDeltaPos.scale = scaleBy - mStartPos.scale;
@@ -150,9 +164,11 @@ public synchronized void animateZoom(long duration, double scaleBy,
animStart(duration, ANIM_SCALE);
}
- public synchronized void animateFling(float velocityX, float velocityY,
+ public void animateFling(float velocityX, float velocityY,
int xmin, int xmax, int ymin, int ymax) {
+ ThreadUtils.assertMainThread();
+
if (velocityX * velocityX + velocityY * velocityY < 2048)
return;
@@ -177,87 +193,87 @@ public synchronized void animateFling(float velocityX, float velocityY,
}
private void animStart(float duration, int state) {
- mState = state;
mCurPos.copy(mStartPos);
+ mState = state;
mDuration = duration;
mAnimEnd = System.currentTimeMillis() + (long) duration;
mMap.render();
}
- private void animCancel() {
- mState = ANIM_NONE;
- mPivot.x = 0;
- mPivot.y = 0;
- }
-
/**
* called by MapRenderer at begin of each frame.
*/
- public synchronized void updateAnimation() {
+ void updateAnimation() {
if (mState == ANIM_NONE)
return;
long millisLeft = mAnimEnd - MapRenderer.frametime;
- boolean changed = false;
-
ViewController v = mMap.viewport();
- synchronized (v) {
- /* cancel animation when position was changed since last
- * update, i.e. when it was modified outside the animator. */
- if (v.getMapPosition(mCurPos)) {
- animCancel();
- return;
- }
-
- float adv = clamp(1.0f - millisLeft / mDuration, 0, 1);
+ /* cancel animation when position was changed since last
+ * update, i.e. when it was modified outside the animator. */
+ if (v.getMapPosition(mCurPos)) {
+ log.debug("cancel anim - changed");
+ cancel();
+ return;
+ }
- double scaleAdv = 1;
- if ((mState & ANIM_SCALE) != 0) {
- scaleAdv = doScale(v, adv);
- }
+ float adv = clamp(1.0f - millisLeft / mDuration, 0, 1);
- if ((mState & ANIM_MOVE) != 0) {
- v.moveTo(mStartPos.x + mDeltaPos.x * (adv / scaleAdv),
- mStartPos.y + mDeltaPos.y * (adv / scaleAdv));
- }
+ double scaleAdv = 1;
+ if ((mState & ANIM_SCALE) != 0) {
+ scaleAdv = doScale(v, adv);
+ }
- if ((mState & ANIM_FLING) != 0) {
- adv = (float) Math.sqrt(adv);
- double dx = mVelocity.x * adv;
- double dy = mVelocity.y * adv;
- if ((dx - mScroll.x) != 0 || (dy - mScroll.y) != 0) {
- v.moveMap((float) (dx - mScroll.x),
- (float) (dy - mScroll.y));
- mScroll.x = dx;
- mScroll.y = dy;
- }
- }
- if ((mState & ANIM_ROTATE) != 0) {
- v.setRotation(mStartPos.bearing + mDeltaPos.bearing * adv);
- }
+ if ((mState & ANIM_MOVE) != 0) {
+ v.moveTo(mStartPos.x + mDeltaPos.x * (adv / scaleAdv),
+ mStartPos.y + mDeltaPos.y * (adv / scaleAdv));
+ }
- if ((mState & ANIM_TILT) != 0) {
- v.setTilt(mStartPos.tilt + mDeltaPos.tilt * adv);
+ if ((mState & ANIM_FLING) != 0) {
+ adv = (float) Math.sqrt(adv);
+ double dx = mVelocity.x * adv;
+ double dy = mVelocity.y * adv;
+ if ((dx - mScroll.x) != 0 || (dy - mScroll.y) != 0) {
+ v.moveMap((float) (dx - mScroll.x),
+ (float) (dy - mScroll.y));
+ mScroll.x = dx;
+ mScroll.y = dy;
}
+ }
+ if ((mState & ANIM_ROTATE) != 0) {
+ v.setRotation(mStartPos.bearing + mDeltaPos.bearing * adv);
+ }
- if (millisLeft <= 0)
- animCancel();
+ if ((mState & ANIM_TILT) != 0) {
+ v.setTilt(mStartPos.tilt + mDeltaPos.tilt * adv);
+ }
- /* remember current map position */
- changed = v.getMapPosition(mCurPos);
+ if (millisLeft <= 0) {
+ //log.debug("animate END");
+ cancel();
}
+ /* remember current map position */
+ final boolean changed = v.getMapPosition(mCurPos);
+
if (changed) {
- /* render and inform layers that position has changed */
mMap.updateMap(true);
} else {
- /* just render next frame */
- mMap.render();
+ mMap.postDelayed(updateTask, 10);
}
}
+ private Task updateTask = new Task() {
+ @Override
+ public int go(boolean canceled) {
+ if (!canceled)
+ updateAnimation();
+ return Task.DONE;
+ }
+ };
+
private double doScale(ViewController v, float adv) {
double newScale = mStartPos.scale + mDeltaPos.scale * Math.sqrt(adv);
@@ -267,7 +283,15 @@ private double doScale(ViewController v, float adv) {
return newScale / (mStartPos.scale + mDeltaPos.scale);
}
- public synchronized void cancel() {
+ public void cancel() {
+ //ThreadUtils.assertMainThread();
mState = ANIM_NONE;
+ mPivot.x = 0;
+ mPivot.y = 0;
+ mMap.events.fire(Map.ANIM_END, mMap.mMapPosition);
+ }
+
+ public boolean isActive() {
+ return mState != ANIM_NONE;
}
}
diff --git a/vtm/src/org/oscim/map/Map.java b/vtm/src/org/oscim/map/Map.java
index 8d0270997..65c5acd5f 100644
--- a/vtm/src/org/oscim/map/Map.java
+++ b/vtm/src/org/oscim/map/Map.java
@@ -16,6 +16,8 @@
*/
package org.oscim.map;
+import org.oscim.core.BoundingBox;
+import org.oscim.core.Box;
import org.oscim.core.MapPosition;
import org.oscim.event.Event;
import org.oscim.event.EventDispatcher;
@@ -32,6 +34,7 @@
import org.oscim.theme.ThemeFile;
import org.oscim.theme.ThemeLoader;
import org.oscim.tiling.TileSource;
+import org.oscim.utils.ThreadUtils;
import org.oscim.utils.async.AsyncExecutor;
import org.oscim.utils.async.TaskQueue;
import org.slf4j.Logger;
@@ -65,30 +68,33 @@ public interface InputListener extends EventListener {
/**
* UpdateListener event. Map position has changed.
*/
- public static Event POSITION_EVENT = new Event();
+ public static final Event POSITION_EVENT = new Event();
/**
* UpdateLister event. Delivered on main-thread when updateMap() was called
* and no CLEAR_EVENT or POSITION_EVENT was triggered.
*/
- public static Event UPDATE_EVENT = new Event();
+ public static final Event UPDATE_EVENT = new Event();
/**
* UpdateListerner event. Map state has changed in a way that all layers
* should clear their state e.g. the theme or the TilesSource has changed.
* TODO should have an event-source to only clear affected layers.
*/
- public static Event CLEAR_EVENT = new Event();
+ public static final Event CLEAR_EVENT = new Event();
+
+ public static final Event ANIM_END = new Event();
public final EventDispatcher input;
public final EventDispatcher events;
private final Layers mLayers;
private final ViewController mViewport;
- private final Animator mAnimator;
- private final MapPosition mMapPosition;
private final AsyncExecutor mAsyncExecutor;
+ protected final Animator mAnimator;
+ protected final MapPosition mMapPosition;
+
protected final MapEventLayer mEventLayer;
protected GestureDetector mGestureDetector;
@@ -97,6 +103,8 @@ public interface InputListener extends EventListener {
protected boolean mClearMap = true;
public Map() {
+ ThreadUtils.init();
+
mViewport = new ViewController();
mAnimator = new Animator(this);
mLayers = new Layers(this);
@@ -237,9 +245,19 @@ public void clearMap() {
/**
* Set {@link MapPosition} of {@link Viewport} and trigger a redraw.
*/
- public void setMapPosition(MapPosition mapPosition) {
- mViewport.setMapPosition(mapPosition);
- updateMap(true);
+ public void setMapPosition(final MapPosition mapPosition) {
+ if (!ThreadUtils.isMainThread())
+ post(new Runnable() {
+ @Override
+ public void run() {
+ mViewport.setMapPosition(mapPosition);
+ updateMap(true);
+ }
+ });
+ else {
+ mViewport.setMapPosition(mapPosition);
+ updateMap(true);
+ }
}
public void setMapPosition(double latitude, double longitude, double scale) {
@@ -253,6 +271,10 @@ public void setMapPosition(double latitude, double longitude, double scale) {
* @return true when MapPosition was updated (has changed)
*/
public boolean getMapPosition(MapPosition mapPosition) {
+ if (!ThreadUtils.isMainThread()) {
+ return mViewport.getSyncMapPosition(mapPosition);
+ }
+
return mViewport.getMapPosition(mapPosition);
}
@@ -267,6 +289,13 @@ public MapPosition getMapPosition() {
return pos;
}
+ public BoundingBox getBoundingBox(int expand) {
+ Box box = new Box();
+ mViewport.getBBox(box, expand);
+ box.map2mercator();
+ return new BoundingBox(box.ymin, box.xmin, box.ymax, box.xmax);
+ }
+
/**
* @return Viewport instance
*/
@@ -289,14 +318,18 @@ public Animator animator() {
}
/**
- * This function is run on main-loop before rendering a frame.
- * Caution: Do not call directly!
+ * This function is run on main-thread before rendering a frame.
+ *
+ * For internal use only. Do not call!
*/
- protected void updateLayers() {
- boolean changed = false;
+ protected void prepareFrame() {
+ ThreadUtils.assertMainThread();
+
MapPosition pos = mMapPosition;
- changed |= mViewport.getMapPosition(pos);
+ mAnimator.updateAnimation();
+
+ boolean changed = mViewport.getMapPosition(pos);
if (mClearMap)
events.fire(CLEAR_EVENT, pos);
@@ -306,9 +339,19 @@ else if (changed)
events.fire(UPDATE_EVENT, pos);
mClearMap = false;
+
+ mAnimator.updateAnimation();
+
+ mViewport.syncViewport();
}
public boolean handleGesture(Gesture g, MotionEvent e) {
return mLayers.handleGesture(g, e);
}
+
+ /** Called on render thread, use synchronized! */
+ public abstract void beginFrame();
+
+ /** Called on render thread, use synchronized! */
+ public abstract void doneFrame(boolean needsRedraw);
}
diff --git a/vtm/src/org/oscim/map/ViewController.java b/vtm/src/org/oscim/map/ViewController.java
index c7b9fabc9..3494f74a8 100644
--- a/vtm/src/org/oscim/map/ViewController.java
+++ b/vtm/src/org/oscim/map/ViewController.java
@@ -1,14 +1,23 @@
package org.oscim.map;
+import static org.oscim.utils.FastMath.clamp;
+
import org.oscim.core.MapPosition;
import org.oscim.core.Point;
import org.oscim.core.Tile;
import org.oscim.renderer.GLMatrix;
import org.oscim.utils.FastMath;
+import org.oscim.utils.ThreadUtils;
public class ViewController extends Viewport {
- public synchronized void setScreenSize(int width, int height) {
+ protected float mPivotY = 0.0f;
+
+ private final float[] mat = new float[16];
+
+ public void setScreenSize(int width, int height) {
+ ThreadUtils.assertMainThread();
+
mHeight = height;
mWidth = width;
@@ -21,19 +30,19 @@ public synchronized void setScreenSize(int width, int height) {
* 1. invert translate to VIEW_DISTANCE */
float ratio = (mHeight / mWidth) * VIEW_SCALE;
- float[] tmp = new float[16];
- GLMatrix.frustumM(tmp, 0, -VIEW_SCALE, VIEW_SCALE,
+ GLMatrix.frustumM(mat, 0, -VIEW_SCALE, VIEW_SCALE,
ratio, -ratio, VIEW_NEAR, VIEW_FAR);
- mProjMatrix.set(tmp);
+ mProjMatrix.set(mat);
+
mTmpMatrix.setTranslation(0, 0, -VIEW_DISTANCE);
mProjMatrix.multiplyRhs(mTmpMatrix);
/* set inverse projection matrix (without scaling) */
- mProjMatrix.get(tmp);
- GLMatrix.invertM(tmp, 0, tmp, 0);
- mProjMatrixInverse.set(tmp);
+ mProjMatrix.get(mat);
+ GLMatrix.invertM(mat, 0, mat, 0);
+ mProjMatrixInverse.set(mat);
mProjMatrixUnscaled.copy(mProjMatrix);
@@ -44,13 +53,24 @@ public synchronized void setScreenSize(int width, int height) {
updateMatrices();
}
+ /**
+ * Set pivot height relative to screen center. E.g. 0.5 is usually preferred
+ * for navigation, moving the center to 25% of the screen height.
+ * Range is [-1, 1].
+ */
+ public void setMapScreenCenter(float pivotY) {
+ mPivotY = FastMath.clamp(pivotY, -1, 1) * 0.5f;
+ }
+
/**
* Moves this Viewport by the given amount of pixels.
*
* @param mx the amount of pixels to move the map horizontally.
* @param my the amount of pixels to move the map vertically.
*/
- public synchronized void moveMap(float mx, float my) {
+ public void moveMap(float mx, float my) {
+ ThreadUtils.assertMainThread();
+
Point p = applyRotation(mx, my);
double tileScale = mPos.scale * Tile.SIZE;
moveTo(mPos.x - p.x / tileScale, mPos.y - p.y / tileScale);
@@ -94,7 +114,9 @@ private Point applyRotation(double mx, double my) {
* @param pivotY
* @return true if scale was changed
*/
- public synchronized boolean scaleMap(float scale, float pivotX, float pivotY) {
+ public boolean scaleMap(float scale, float pivotX, float pivotY) {
+ ThreadUtils.assertMainThread();
+
// just sanitize input
//scale = FastMath.clamp(scale, 0.5f, 2);
if (scale < 0.000001)
@@ -102,7 +124,7 @@ public synchronized boolean scaleMap(float scale, float pivotX, float pivotY) {
double newScale = mPos.scale * scale;
- newScale = FastMath.clamp(newScale, MIN_SCALE, MAX_SCALE);
+ newScale = clamp(newScale, mMinScale, mMaxScale);
if (newScale == mPos.scale)
return false;
@@ -111,10 +133,12 @@ public synchronized boolean scaleMap(float scale, float pivotX, float pivotY) {
mPos.scale = newScale;
- if (pivotX != 0 || pivotY != 0)
+ if (pivotX != 0 || pivotY != 0) {
+ pivotY -= mHeight * mPivotY;
+
moveMap(pivotX * (1.0f - scale),
pivotY * (1.0f - scale));
-
+ }
return true;
}
@@ -126,11 +150,14 @@ public synchronized boolean scaleMap(float scale, float pivotX, float pivotY) {
* @param pivotX
* @param pivotY
*/
- public synchronized void rotateMap(double radians, float pivotX, float pivotY) {
+ public void rotateMap(double radians, float pivotX, float pivotY) {
+ ThreadUtils.assertMainThread();
double rsin = Math.sin(radians);
double rcos = Math.cos(radians);
+ pivotY -= mHeight * mPivotY;
+
float x = (float) (pivotX - pivotX * rcos + pivotY * rsin);
float y = (float) (pivotY - pivotX * rsin - pivotY * rcos);
@@ -139,35 +166,47 @@ public synchronized void rotateMap(double radians, float pivotX, float pivotY) {
setRotation(mPos.bearing + Math.toDegrees(radians));
}
- public synchronized void setRotation(double degree) {
+ public void setRotation(double degree) {
+ ThreadUtils.assertMainThread();
+
while (degree > 180)
degree -= 360;
while (degree < -180)
degree += 360;
mPos.bearing = (float) degree;
+
updateMatrices();
}
- public synchronized boolean tiltMap(float move) {
+ public boolean tiltMap(float move) {
return setTilt(mPos.tilt + move);
}
- public synchronized boolean setTilt(float tilt) {
- tilt = FastMath.clamp(tilt, 0, MAX_TILT);
+ public boolean setTilt(float tilt) {
+ ThreadUtils.assertMainThread();
+
+ tilt = limitTilt(tilt);
if (tilt == mPos.tilt)
return false;
+
mPos.tilt = tilt;
updateMatrices();
return true;
}
- public synchronized void setMapPosition(MapPosition mapPosition) {
- mPos.scale = FastMath.clamp(mapPosition.scale, MIN_SCALE, MAX_SCALE);
- mPos.x = mapPosition.x;
- mPos.y = mapPosition.y;
- mPos.tilt = mapPosition.tilt;
- mPos.bearing = mapPosition.bearing;
+ public void setMapPosition(MapPosition mapPosition) {
+ ThreadUtils.assertMainThread();
+
+ mPos.copy(mapPosition);
+ limitPosition(mPos);
+
+ // mPos.scale = clamp(mapPosition.scale, mMinScale, mMaxScale);
+ // mPos.x = mapPosition.x;
+ // mPos.y = mapPosition.y;
+ // mPos.tilt = limitTilt(mapPosition.tilt);
+ // mPos.bearing = mapPosition.bearing;
+
updateMatrices();
}
@@ -184,19 +223,39 @@ private void updateMatrices() {
mViewMatrix.copy(mRotationMatrix);
+ mTmpMatrix.setTranslation(0, mPivotY * mHeight, 0);
+ mViewMatrix.multiplyLhs(mTmpMatrix);
+
mViewProjMatrix.multiplyMM(mProjMatrix, mViewMatrix);
- /* inverse projection matrix: */
- /* invert scale */
- mUnprojMatrix.setScale(mWidth, mWidth, 1);
+ mViewProjMatrix.get(mat);
+ GLMatrix.invertM(mat, 0, mat, 0);
+ mUnprojMatrix.set(mat);
+ }
+
+ public final Viewport mNextFrame = new Viewport();
- /* invert rotation and tilt */
- mTmpMatrix.transposeM(mRotationMatrix);
+ /** synchronize on this object when doing multiple calls on it */
+ public final Viewport getSyncViewport() {
+ return mNextFrame;
+ }
+
+ void syncViewport() {
+ synchronized (mNextFrame) {
+ mNextFrame.copy(this);
+ }
+ }
- /* (AB)^-1 = B^-1*A^-1, invert scale, tilt and rotation */
- mTmpMatrix.multiplyLhs(mUnprojMatrix);
+ public boolean getSyncViewport(Viewport v) {
+ synchronized (mNextFrame) {
+ return v.copy(mNextFrame);
+ }
+ }
- /* (AB)^-1 = B^-1*A^-1, invert projection */
- mUnprojMatrix.multiplyMM(mTmpMatrix, mProjMatrixInverse);
+ public boolean getSyncMapPosition(MapPosition mapPosition) {
+ synchronized (mNextFrame) {
+ return mNextFrame.getMapPosition(mapPosition);
+ }
}
+
}
diff --git a/vtm/src/org/oscim/map/Viewport.java b/vtm/src/org/oscim/map/Viewport.java
index fd07da6d6..da0fa45dd 100644
--- a/vtm/src/org/oscim/map/Viewport.java
+++ b/vtm/src/org/oscim/map/Viewport.java
@@ -16,7 +16,6 @@
*/
package org.oscim.map;
-import org.oscim.core.BoundingBox;
import org.oscim.core.Box;
import org.oscim.core.GeoPoint;
import org.oscim.core.MapPosition;
@@ -25,6 +24,8 @@
import org.oscim.core.Tile;
import org.oscim.renderer.GLMatrix;
import org.oscim.utils.FastMath;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
/**
* The Viewport class contains a MapPosition and the projection matrices.
@@ -34,15 +35,27 @@
* Public methods are thread safe.
*/
public class Viewport {
- //static final Logger log = LoggerFactory.getLogger(Viewport.class);
- public final static int MAX_ZOOMLEVEL = 20;
- public final static int MIN_ZOOMLEVEL = 2;
+ static final Logger log = LoggerFactory.getLogger(Viewport.class);
- public final static double MAX_SCALE = (1 << MAX_ZOOMLEVEL);
- public final static double MIN_SCALE = (1 << MIN_ZOOMLEVEL);
+ private final static int MAX_ZOOMLEVEL = 20;
+ private final static int MIN_ZOOMLEVEL = 2;
+ private final static float MIN_TILT = 0;
+ private final static float MAX_TILT = 65;
- public final static float MAX_TILT = 65;
+ protected double mMaxScale = (1 << MAX_ZOOMLEVEL);
+ protected double mMinScale = (1 << MIN_ZOOMLEVEL);
+
+ protected float mMinTilt = MIN_TILT;
+ protected float mMaxTilt = MAX_TILT;
+
+ protected float mMinBearing = -180;
+ protected float mMaxBearing = 180;
+
+ protected double mMinX = 0;
+ protected double mMaxX = 1;
+ protected double mMinY = 0;
+ protected double mMaxY = 1;
protected final MapPosition mPos = new MapPosition();
@@ -61,8 +74,6 @@ public class Viewport {
protected final float[] mu = new float[4];
protected final float[] mViewCoords = new float[8];
- protected final Box mMapBBox = new Box();
-
protected float mHeight, mWidth;
public final static float VIEW_DISTANCE = 3.0f;
@@ -71,14 +82,77 @@ public class Viewport {
/** scale map plane at VIEW_DISTANCE to near plane */
public final static float VIEW_SCALE = (VIEW_NEAR / VIEW_DISTANCE) * 0.5f;
- protected Viewport() {
- mPos.scale = MIN_SCALE;
+ public Viewport() {
+ mPos.scale = mMinScale;
mPos.x = 0.5;
mPos.y = 0.5;
mPos.bearing = 0;
mPos.tilt = 0;
}
+ public double limitScale(double scale) {
+ if (scale > mMaxScale)
+ return mMaxScale;
+ else if (scale < mMinScale)
+ return mMinScale;
+
+ return scale;
+ }
+
+ public float limitTilt(float tilt) {
+ if (tilt > mMaxTilt)
+ return mMaxTilt;
+ else if (tilt < mMinTilt)
+ return mMinTilt;
+
+ return tilt;
+ }
+
+ public boolean limitPosition(MapPosition pos) {
+ boolean changed = false;
+ if (pos.scale > mMaxScale) {
+ pos.scale = mMaxScale;
+ changed = true;
+ } else if (pos.scale < mMinScale) {
+ pos.scale = mMinScale;
+ changed = true;
+ }
+
+ if (pos.tilt > mMaxTilt) {
+ pos.tilt = mMaxTilt;
+ changed = true;
+ } else if (pos.tilt < mMinTilt) {
+ pos.tilt = mMinTilt;
+ changed = true;
+ }
+
+ if (pos.bearing > mMaxBearing) {
+ pos.bearing = mMaxBearing;
+ changed = true;
+ } else if (pos.bearing < mMinBearing) {
+ pos.bearing = mMinBearing;
+ changed = true;
+ }
+
+ if (pos.x > mMaxX) {
+ pos.x = mMaxX;
+ changed = true;
+ } else if (pos.x < mMinX) {
+ pos.x = mMinX;
+ changed = true;
+ }
+
+ if (pos.y > mMaxY) {
+ pos.y = mMaxY;
+ changed = true;
+ } else if (pos.y < mMinY) {
+ pos.y = mMinY;
+ changed = true;
+ }
+
+ return changed;
+ }
+
/**
* Get the current MapPosition.
*
@@ -87,7 +161,7 @@ protected Viewport() {
* @return true iff current position is different from
* passed position.
*/
- public synchronized boolean getMapPosition(MapPosition pos) {
+ public boolean getMapPosition(MapPosition pos) {
boolean changed = (pos.scale != mPos.scale
|| pos.x != mPos.x
@@ -114,18 +188,15 @@ public synchronized boolean getMapPosition(MapPosition pos) {
* @param box float[8] will be set.
* @param add increase extents of box
*/
- public synchronized void getMapExtents(float[] box, float add) {
- float t = getDepth(1);
- float t2 = getDepth(-1);
-
- // top-right
- unproject(1, -1, t, box, 0);
- // top-left
- unproject(-1, -1, t, box, 2);
- // bottom-left
- unproject(-1, 1, t2, box, 4);
- // bottom-right
- unproject(1, 1, t2, box, 6);
+ public void getMapExtents(float[] box, float add) {
+ /* top-right */
+ unproject(1, -1, box, 0);
+ /* top-left */
+ unproject(-1, -1, box, 2);
+ /* bottom-left */
+ unproject(-1, 1, box, 4);
+ /* bottom-right */
+ unproject(1, 1, box, 6);
if (add == 0)
return;
@@ -139,78 +210,42 @@ public synchronized void getMapExtents(float[] box, float add) {
}
}
- /**
- * Get Z-value of the map-plane for a point on screen -
- * calculate the intersection of a ray from camera origin
- * and the map plane
- */
- protected float getDepth(float y) {
- // origin is moved by VIEW_DISTANCE
- double cx = VIEW_DISTANCE;
- // 'height' of the ray
- double ry = y * (mHeight / mWidth) * 0.5f;
-
- double ua;
-
- if (y == 0)
- ua = 1;
- else {
- // tilt of the plane (center is kept on x = 0)
- double t = Math.toRadians(mPos.tilt);
- double px = y * Math.sin(t);
- double py = y * Math.cos(t);
- ua = 1 + (px * ry) / (py * cx);
- }
-
- mv[0] = 0;
- mv[1] = (float) (ry / ua);
- mv[2] = (float) (cx - cx / ua);
-
- mProjMatrixUnscaled.prj(mv);
-
- return mv[2];
- }
-
- protected void unproject(float x, float y, float z, float[] coords, int position) {
+ protected void unproject(float x, float y, float[] coords, int position) {
mv[0] = x;
mv[1] = y;
- mv[2] = z;
-
+ mv[2] = -1;
mUnprojMatrix.prj(mv);
+ double nx = mv[0];
+ double ny = mv[1];
+ double nz = mv[2];
- coords[position + 0] = mv[0];
- coords[position + 1] = mv[1];
- }
-
- /**
- * Get the minimal axis-aligned BoundingBox that encloses
- * the visible part of the map.
- *
- * @return BoundingBox containing view
- */
- public synchronized BoundingBox getBBox(int expand) {
- getBBox(mMapBBox, expand);
+ mv[0] = x;
+ mv[1] = y;
+ mv[2] = 1;
+ mUnprojMatrix.prj(mv);
+ double fx = mv[0];
+ double fy = mv[1];
+ double fz = mv[2];
- /* scale map-pixel coordinates at current scale to
- * absolute coordinates and apply mercator projection. */
- double minLon = MercatorProjection.toLongitude(mMapBBox.xmin);
- double maxLon = MercatorProjection.toLongitude(mMapBBox.xmax);
- double minLat = MercatorProjection.toLatitude(mMapBBox.ymax);
- double maxLat = MercatorProjection.toLatitude(mMapBBox.ymin);
+ double dx = fx - nx;
+ double dy = fy - ny;
+ double dz = fz - nz;
- return new BoundingBox(minLat, minLon, maxLat, maxLon);
- }
+ double dist = -nz / dz;
- public synchronized BoundingBox getBBox() {
- return getBBox(0);
+ coords[position + 0] = (float) (nx + dist * dx);
+ coords[position + 1] = (float) (ny + dist * dy);
}
/**
* Get the minimal axis-aligned BoundingBox that encloses
* the visible part of the map. Sets box to map coordinates:
- * xmin,ymin,ymax,ymax
+ * xmin,ymin,xmax,ymax
*/
- public synchronized void getBBox(Box box, int expand) {
+ public Box getBBox(Box box, int expand) {
+ if (box == null)
+ box = new Box();
+
float[] coords = mViewCoords;
getMapExtents(coords, expand);
@@ -226,7 +261,6 @@ public synchronized void getBBox(Box box, int expand) {
box.ymax = Math.max(box.ymax, coords[i + 1]);
}
- //updatePosition();
double cs = mPos.scale * Tile.SIZE;
double cx = mPos.x * cs;
double cy = mPos.y * cs;
@@ -235,6 +269,8 @@ public synchronized void getBBox(Box box, int expand) {
box.xmax = (cx + box.xmax) / cs;
box.ymin = (cy + box.ymin) / cs;
box.ymax = (cy + box.ymax) / cs;
+
+ return box;
}
/**
@@ -244,25 +280,29 @@ public synchronized void getBBox(Box box, int expand) {
* @param y screen coordinate
* @return the corresponding GeoPoint
*/
- public synchronized GeoPoint fromScreenPoint(float x, float y) {
+ public GeoPoint fromScreenPoint(float x, float y) {
fromScreenPoint(x, y, mMovePoint);
return new GeoPoint(
MercatorProjection.toLatitude(mMovePoint.y),
MercatorProjection.toLongitude(mMovePoint.x));
}
+ protected void unprojectScreen(double x, double y, float[] out) {
+ /* scale to -1..1 */
+ float mx = (float) (1 - (x / mWidth * 2));
+ float my = (float) (1 - (y / mHeight * 2));
+
+ unproject(-mx, my, out, 0);
+ }
+
/**
* Get the map position for x,y in screen coordinates.
*
* @param x screen coordinate
* @param y screen coordinate
*/
- public synchronized void fromScreenPoint(double x, double y, Point out) {
- // scale to -1..1
- float mx = (float) (1 - (x / mWidth * 2));
- float my = (float) (1 - (y / mHeight * 2));
-
- unproject(-mx, my, getDepth(-my), mu, 0);
+ public void fromScreenPoint(double x, double y, Point out) {
+ unprojectScreen(x, y, mu);
double cs = mPos.scale * Tile.SIZE;
double cx = mPos.x * cs;
@@ -294,7 +334,7 @@ else if (dy < 0)
* @param geoPoint the GeoPoint
* @param out Point projected to screen pixel relative to center
*/
- public synchronized void toScreenPoint(GeoPoint geoPoint, Point out) {
+ public void toScreenPoint(GeoPoint geoPoint, Point out) {
MercatorProjection.project(geoPoint, out);
toScreenPoint(out.x, out.y, out);
}
@@ -304,7 +344,7 @@ public synchronized void toScreenPoint(GeoPoint geoPoint, Point out) {
*
* @param out Point projected to screen coordinate
*/
- public synchronized void toScreenPoint(double x, double y, Point out) {
+ public void toScreenPoint(double x, double y, Point out) {
double cs = mPos.scale * Tile.SIZE;
double cx = mPos.x * cs;
@@ -322,20 +362,17 @@ public synchronized void toScreenPoint(double x, double y, Point out) {
out.y = -(mv[1] * (mHeight / 2));
}
- public synchronized boolean copy(Viewport viewport) {
+ protected boolean copy(Viewport viewport) {
+ mHeight = viewport.mHeight;
+ mWidth = viewport.mWidth;
+ mProjMatrix.copy(viewport.mProjMatrix);
+ mProjMatrixUnscaled.copy(viewport.mProjMatrixUnscaled);
+ mProjMatrixInverse.copy(viewport.mProjMatrixInverse);
+
mUnprojMatrix.copy(viewport.mUnprojMatrix);
mRotationMatrix.copy(viewport.mRotationMatrix);
mViewMatrix.copy(viewport.mViewMatrix);
mViewProjMatrix.copy(viewport.mViewProjMatrix);
return viewport.getMapPosition(mPos);
}
-
- public synchronized void initFrom(Viewport viewport) {
- mProjMatrix.copy(viewport.mProjMatrix);
- mProjMatrixUnscaled.copy(viewport.mProjMatrixUnscaled);
- mProjMatrixInverse.copy(viewport.mProjMatrixInverse);
-
- mHeight = viewport.mHeight;
- mWidth = viewport.mWidth;
- }
}
diff --git a/vtm/src/org/oscim/renderer/GLViewport.java b/vtm/src/org/oscim/renderer/GLViewport.java
index e735f7c2e..c6f25a2df 100644
--- a/vtm/src/org/oscim/renderer/GLViewport.java
+++ b/vtm/src/org/oscim/renderer/GLViewport.java
@@ -1,6 +1,7 @@
package org.oscim.renderer;
import org.oscim.core.MapPosition;
+import org.oscim.map.Map;
import org.oscim.map.Viewport;
public class GLViewport extends Viewport {
@@ -40,8 +41,8 @@ public boolean changed() {
return changed;
}
- void setFrom(Viewport viewport) {
- changed = super.copy(viewport);
+ void setFrom(Map map) {
+ changed = map.viewport().getSyncViewport(this);
getMapExtents(plane, 0);
}
diff --git a/vtm/src/org/oscim/renderer/MapRenderer.java b/vtm/src/org/oscim/renderer/MapRenderer.java
index 81d40e93b..f55fc2bcf 100644
--- a/vtm/src/org/oscim/renderer/MapRenderer.java
+++ b/vtm/src/org/oscim/renderer/MapRenderer.java
@@ -72,13 +72,20 @@ public static void setBackgroundColor(int color) {
public void onDrawFrame() {
frametime = System.currentTimeMillis();
+ rerender = false;
+
+ mMap.beginFrame();
+
draw();
+ mMap.doneFrame(rerender);
+
mBufferPool.releaseBuffers();
TextureItem.disposeTextures();
}
private void draw() {
+
GLState.setClearColor(mClearColor);
gl.depthMask(true);
@@ -98,8 +105,7 @@ private void draw() {
GLState.bindElementBuffer(-1);
GLState.bindVertexBuffer(-1);
- mMap.animator().updateAnimation();
- mViewport.setFrom(mMap.viewport());
+ mViewport.setFrom(mMap);
if (GLAdapter.debugView) {
/* modify this to scale only the view, to see
@@ -133,10 +139,6 @@ private void draw() {
BufferObject.checkBufferUsage(true);
// FIXME also throw out some textures etc
}
- if (rerender) {
- mMap.render();
- rerender = false;
- }
}
public void onSurfaceChanged(int width, int height) {
@@ -145,8 +147,6 @@ public void onSurfaceChanged(int width, int height) {
if (width <= 0 || height <= 0)
return;
- //mMap.viewport().getMatrix(null, mMatrices.proj, null);
- mViewport.initFrom(mMap.viewport());
gl.viewport(0, 0, width, height);
//GL.scissor(0, 0, width, height);
diff --git a/vtm/src/org/oscim/tiling/ITileDataSink.java b/vtm/src/org/oscim/tiling/ITileDataSink.java
index dac9e2b07..7a597cd0f 100644
--- a/vtm/src/org/oscim/tiling/ITileDataSink.java
+++ b/vtm/src/org/oscim/tiling/ITileDataSink.java
@@ -40,11 +40,4 @@ public interface ITileDataSink {
* Notify loader that tile loading is completed.
*/
void completed(QueryResult result);
-
- public static enum QueryResult {
- SUCCESS,
- FAILED,
- TILE_NOT_FOUND,
- DELAYED,
- }
}
diff --git a/vtm/src/org/oscim/tiling/QueryResult.java b/vtm/src/org/oscim/tiling/QueryResult.java
new file mode 100644
index 000000000..efe832473
--- /dev/null
+++ b/vtm/src/org/oscim/tiling/QueryResult.java
@@ -0,0 +1,8 @@
+package org.oscim.tiling;
+
+public enum QueryResult {
+ SUCCESS,
+ FAILED,
+ TILE_NOT_FOUND,
+ DELAYED,
+}
\ No newline at end of file
diff --git a/vtm/src/org/oscim/tiling/source/UrlTileDataSource.java b/vtm/src/org/oscim/tiling/source/UrlTileDataSource.java
index e04fbbdbd..a808f290e 100644
--- a/vtm/src/org/oscim/tiling/source/UrlTileDataSource.java
+++ b/vtm/src/org/oscim/tiling/source/UrlTileDataSource.java
@@ -16,8 +16,9 @@
*/
package org.oscim.tiling.source;
-import static org.oscim.tiling.ITileDataSink.QueryResult.FAILED;
-import static org.oscim.tiling.ITileDataSink.QueryResult.SUCCESS;
+import static org.oscim.tiling.QueryResult.DELAYED;
+import static org.oscim.tiling.QueryResult.FAILED;
+import static org.oscim.tiling.QueryResult.SUCCESS;
import java.io.IOException;
import java.io.InputStream;
@@ -31,6 +32,7 @@
import org.oscim.tiling.ITileCache.TileWriter;
import org.oscim.tiling.ITileDataSink;
import org.oscim.tiling.ITileDataSource;
+import org.oscim.tiling.QueryResult;
import org.oscim.utils.IOUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -71,7 +73,8 @@ public void query(MapTile tile, ITileDataSink sink) {
}
}
- boolean ok = false;
+ QueryResult res = FAILED;
+
TileWriter cacheWriter = null;
try {
mConn.sendRequest(tile);
@@ -80,21 +83,27 @@ public void query(MapTile tile, ITileDataSink sink) {
cacheWriter = cache.writeTile(tile);
mConn.setCache(cacheWriter.getOutputStream());
}
- ok = mTileDecoder.decode(tile, sink, is);
+ if (mTileDecoder.decode(tile, sink, is))
+ res = SUCCESS;
} catch (SocketException e) {
log.debug("{} Socket Error: {}", tile, e.getMessage());
} catch (SocketTimeoutException e) {
log.debug("{} Socket Timeout", tile);
+ res = DELAYED;
} catch (UnknownHostException e) {
log.debug("{} Unknown host: {}", tile, e.getMessage());
} catch (IOException e) {
log.debug("{} Network Error: {}", tile, e.getMessage());
} finally {
- ok = mConn.requestCompleted(ok);
+ boolean ok = (res == SUCCESS);
+
+ if (!mConn.requestCompleted(ok) && ok)
+ res = FAILED;
+
if (cacheWriter != null)
cacheWriter.complete(ok);
- sink.completed(ok ? SUCCESS : FAILED);
+ sink.completed(res);
}
}
diff --git a/vtm/src/org/oscim/tiling/source/mapfile/MapDatabase.java b/vtm/src/org/oscim/tiling/source/mapfile/MapDatabase.java
index fe6de0870..5a0418433 100644
--- a/vtm/src/org/oscim/tiling/source/mapfile/MapDatabase.java
+++ b/vtm/src/org/oscim/tiling/source/mapfile/MapDatabase.java
@@ -19,8 +19,8 @@
import static org.oscim.core.GeometryBuffer.GeometryType.LINE;
import static org.oscim.core.GeometryBuffer.GeometryType.POLY;
-import static org.oscim.tiling.ITileDataSink.QueryResult.FAILED;
-import static org.oscim.tiling.ITileDataSink.QueryResult.SUCCESS;
+import static org.oscim.tiling.QueryResult.FAILED;
+import static org.oscim.tiling.QueryResult.SUCCESS;
import java.io.IOException;
import java.io.RandomAccessFile;
diff --git a/vtm/src/org/oscim/tiling/source/test/TestTileSource.java b/vtm/src/org/oscim/tiling/source/test/TestTileSource.java
index 4f734edca..b64044444 100644
--- a/vtm/src/org/oscim/tiling/source/test/TestTileSource.java
+++ b/vtm/src/org/oscim/tiling/source/test/TestTileSource.java
@@ -16,7 +16,7 @@
*/
package org.oscim.tiling.source.test;
-import static org.oscim.tiling.ITileDataSink.QueryResult.SUCCESS;
+import static org.oscim.tiling.QueryResult.SUCCESS;
import org.oscim.core.MapElement;
import org.oscim.core.Tag;
diff --git a/vtm/src/org/oscim/utils/QuadTree.java b/vtm/src/org/oscim/utils/QuadTree.java
index 31726e285..7002ca506 100644
--- a/vtm/src/org/oscim/utils/QuadTree.java
+++ b/vtm/src/org/oscim/utils/QuadTree.java
@@ -9,14 +9,19 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+/**
+ * Quad-tree with fixed extents.
+ * This implementation uses int bounding-boxes internally,
+ * so items extents should be greater than 1. FIXME tests this case
+ */
public class QuadTree extends BoxTree, T> implements SpatialIndex {
+ static final Logger log = LoggerFactory.getLogger(QuadTree.class);
+
public QuadTree(int extents, int maxDepth) {
super(extents, maxDepth);
}
- static final Logger log = LoggerFactory.getLogger(QuadTree.class);
-
final Pool> boxPool = new Pool>() {
@Override
protected BoxItem createItem() {
@@ -67,10 +72,10 @@ public List search(Box bbox, List results) {
}
@Override
- public int search(Box bbox, SearchCb cb, Object context) {
+ public boolean search(Box bbox, SearchCb cb, Object context) {
BoxItem box = getBox(bbox);
- search(box, cb, context);
+ boolean finished = search(box, cb, context);
boxPool.release(box);
- return 0;
+ return finished;
}
}
diff --git a/vtm/src/org/oscim/utils/RTree.java b/vtm/src/org/oscim/utils/RTree.java
index 38b61ab69..b7b18105b 100644
--- a/vtm/src/org/oscim/utils/RTree.java
+++ b/vtm/src/org/oscim/utils/RTree.java
@@ -316,32 +316,24 @@ public boolean remove(Box box, T item) {
* @param a_context User context to pass as parameter to a_resultCallback
* @return Returns the number of entries found
*/
- public int search(double min[], double max[], SearchCb cb, Object context) {
+ public boolean search(double min[], double max[], SearchCb cb, Object context) {
Rect r = getRect();
r.set(min, max);
- /* NOTE: May want to return search result another way,
- * perhaps returning the number of found elements here. */
- //int[] foundCount = { 0 };
- //search(mRoot, r, foundCount, cb, context);
searchStack(r, cb, context);
releaseRect(r);
- return 0; //foundCount[0];
+ return true;
}
- public int search(Box bbox, SearchCb cb, Object context) {
+ public boolean search(Box bbox, SearchCb cb, Object context) {
Rect r = getRect();
r.set(bbox);
- /* NOTE: May want to return search result another way,
- * perhaps returning the number of found elements here. */
- //int[] foundCount = { 0 };
- //search(mRoot, r, foundCount, cb, context);
searchStack(r, cb, context);
releaseRect(r);
- return 0; //foundCount[0];
+ return true;
}
public List search(Box bbox, List results) {
@@ -385,7 +377,7 @@ private void countRec(Node node, int[] count) {
/**
* Remove all entries from tree.
*/
- public void removeAll() {
+ public void clear() {
/* Delete all existing nodes */
reset();
diff --git a/vtm/src/org/oscim/utils/SpatialIndex.java b/vtm/src/org/oscim/utils/SpatialIndex.java
index b6e745091..fa1954414 100644
--- a/vtm/src/org/oscim/utils/SpatialIndex.java
+++ b/vtm/src/org/oscim/utils/SpatialIndex.java
@@ -6,6 +6,14 @@
public interface SpatialIndex {
public interface SearchCb {
+ /**
+ *
+ * TODO should be able to return 'continue', 'stop',
+ * 'remove-current'
+ *
+ * @return false to stop search
+ */
+
boolean call(T item, Object context);
}
@@ -15,7 +23,9 @@ public interface SearchCb {
public List search(Box bbox, List results);
- public int search(Box bbox, SearchCb cb, Object context);
+ public boolean search(Box bbox, SearchCb cb, Object context);
public int size();
+
+ public void clear();
}
diff --git a/vtm/src/org/oscim/utils/ThreadUtils.java b/vtm/src/org/oscim/utils/ThreadUtils.java
new file mode 100644
index 000000000..2f7d53449
--- /dev/null
+++ b/vtm/src/org/oscim/utils/ThreadUtils.java
@@ -0,0 +1,20 @@
+package org.oscim.utils;
+
+public class ThreadUtils {
+
+ private static Thread MAIN_THREAD;
+
+ public static void assertMainThread() {
+ if (MAIN_THREAD != Thread.currentThread())
+ throw new RuntimeException("Access from non-main thread!");
+ }
+
+ public static boolean isMainThread() {
+ return MAIN_THREAD == Thread.currentThread();
+ }
+
+ public static void init() {
+ MAIN_THREAD = Thread.currentThread();
+ }
+
+}
diff --git a/vtm/src/org/oscim/utils/async/SimpleWorker.java b/vtm/src/org/oscim/utils/async/SimpleWorker.java
index c2de6a3a5..8ae5af08b 100644
--- a/vtm/src/org/oscim/utils/async/SimpleWorker.java
+++ b/vtm/src/org/oscim/utils/async/SimpleWorker.java
@@ -146,7 +146,8 @@ public synchronized void cancel(boolean clear) {
return;
}
- cleanup(mTaskTodo);
+ if (mTaskTodo != null)
+ cleanup(mTaskTodo);
finish();
}
diff --git a/vtm/src/org/oscim/utils/geom/GeomBuilder.java b/vtm/src/org/oscim/utils/geom/GeomBuilder.java
new file mode 100644
index 000000000..b79cffc33
--- /dev/null
+++ b/vtm/src/org/oscim/utils/geom/GeomBuilder.java
@@ -0,0 +1,453 @@
+/* Copyright 2013 The jeo project. All rights reserved.
+ *
+ * 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.utils.geom;
+
+import java.lang.reflect.Array;
+import java.util.ArrayDeque;
+import java.util.Arrays;
+import java.util.Deque;
+import java.util.Iterator;
+
+import com.vividsolutions.jts.geom.Coordinate;
+import com.vividsolutions.jts.geom.Geometry;
+import com.vividsolutions.jts.geom.GeometryCollection;
+import com.vividsolutions.jts.geom.GeometryFactory;
+import com.vividsolutions.jts.geom.LineString;
+import com.vividsolutions.jts.geom.LinearRing;
+import com.vividsolutions.jts.geom.MultiLineString;
+import com.vividsolutions.jts.geom.MultiPoint;
+import com.vividsolutions.jts.geom.MultiPolygon;
+import com.vividsolutions.jts.geom.Point;
+import com.vividsolutions.jts.geom.Polygon;
+import com.vividsolutions.jts.geom.PrecisionModel;
+
+/**
+ * Builder for geometry objects.
+ *
+ * Example usage:
+ *
+ *
+ *
+ * GeometryBuilder gb = new GeometryBuilder();
+ *
+ * // create array two 2d points and turn into a line string
+ * gb.points(1,2,3,4,5,6).toLineString();
+ *
+ * // build a polygon with holes
+ * gb.points(0,0,10,0,10,10,0,10,0,0).ring()
+ * .points(4,4,6,4,6,6,4,6,4,4).ring()
+ * .toPolygon();
+ *
+ *
+ *
+ *
+ *
+ *
+ * @author Justin Deoliveira, OpenGeo
+ *
+ */
+public class GeomBuilder {
+
+ GeometryFactory factory;
+ Deque cstack = new ArrayDeque();
+ Deque gstack = new ArrayDeque();
+
+ /**
+ * Constructs a builder with the default geometry factory.
+ */
+ public GeomBuilder() {
+ this(new GeometryFactory());
+ }
+
+ /**
+ * Constructs a builder with an explicit geometry factory.
+ */
+ public GeomBuilder(GeometryFactory factory) {
+ this.factory = factory;
+ }
+
+ /**
+ * Constructs a builder with a specific srid for geometry objects.
+ */
+ public GeomBuilder(int srid) {
+ this.factory = new GeometryFactory(new PrecisionModel(), srid);
+ }
+
+ /**
+ * Adds a 2d point to the coordinate stack.
+ */
+ public GeomBuilder point(double x, double y) {
+ cstack.push(new Coordinate(x, y));
+ return this;
+ }
+
+ /**
+ * Adds a 3d point to the coordinate stack.
+ */
+ public GeomBuilder pointz(double x, double y, double z) {
+ cstack.push(new Coordinate(x, y, z));
+ return this;
+ }
+
+ /**
+ * Adds an array of 2d points to the coordinate stack.
+ */
+ public GeomBuilder points(double... ord) {
+ if (ord.length % 2 != 0) {
+ throw new IllegalArgumentException("Must specify even number of ordinates");
+ }
+
+ for (int i = 0; i < ord.length; i += 2) {
+ point(ord[i], ord[i + 1]);
+ }
+
+ return this;
+ }
+
+ /**
+ * Adds an array of 3d points to the coordinate stack.
+ */
+ public GeomBuilder pointsz(double... ord) {
+ if (ord.length % 3 != 0) {
+ throw new IllegalArgumentException("Must specify ordinates as triples");
+ }
+
+ for (int i = 0; i < ord.length; i += 3) {
+ pointz(ord[i], ord[i + 1], ord[i + 2]);
+ }
+
+ return this;
+ }
+
+ /**
+ * Creates a Point from the last point on the coordinate stack, and places
+ * the result
+ * on the geometry stack.
+ */
+ public GeomBuilder point() {
+ gstack.push(factory.createPoint(cpop()));
+ return this;
+ }
+
+ /**
+ * Creates a LineString from all points on the coordinate stack, and places
+ * the result
+ * on the geometry stack.
+ */
+ public GeomBuilder lineString() {
+ gstack.push(factory.createLineString(cpopAll()));
+ return this;
+ }
+
+ /**
+ * Creates a LinearRing from all points on the coordinate stack, and places
+ * the result
+ * on the geometry stack.
+ *
+ * If the first and last coordinate on the point stack are not equal an
+ * additional point will be added.
+ *
+ */
+ public GeomBuilder ring() {
+ Coordinate[] coords = cpopAll();
+ if (coords.length > 1 && !coords[0].equals(coords[coords.length - 1])) {
+ Coordinate[] tmp = new Coordinate[coords.length + 1];
+ System.arraycopy(coords, 0, tmp, 0, coords.length);
+ tmp[tmp.length - 1] = new Coordinate(tmp[0]);
+ coords = tmp;
+ }
+
+ gstack.push(factory.createLinearRing(coords));
+ return this;
+ }
+
+ /**
+ * Creates a Polygon from all LinearRings on the geometry stack and places
+ * the result back
+ * on the geometry stack.
+ */
+ public GeomBuilder polygon() {
+ if (gstack.isEmpty() || !(gstack.peek() instanceof LinearRing)) {
+ ring();
+ }
+
+ LinearRing[] rings = gpopAll(LinearRing.class);
+ LinearRing outer = rings[0];
+ LinearRing[] inner = null;
+ if (rings.length > 1) {
+ inner = Arrays.copyOfRange(rings, 1, rings.length);
+ }
+
+ gstack.push(factory.createPolygon(outer, inner));
+ return this;
+ }
+
+ /**
+ * Creates a MultiPoint from all coordinates on the coordinate stack,
+ * plaching the result
+ * back on the geometry stack.
+ *
+ * If the coordinate stack is empty this method will consume all Point
+ * geometries on the geometry stack.
+ *
+ */
+ public GeomBuilder multiPoint() {
+ if (!cstack.isEmpty()) {
+ gstack.push(factory.createMultiPoint(cpopAll()));
+ }
+ else {
+ gstack.push(factory.createMultiPoint(gpopAll(Point.class)));
+ }
+ return this;
+ }
+
+ /**
+ * Creates a MultiLineString from all LineStrings on the geometry stack and
+ * places the result
+ * back on the geometry stack.
+ */
+ public GeomBuilder multiLineString() {
+ gstack.push(factory.createMultiLineString(gpopAll(LineString.class)));
+ return this;
+ }
+
+ /**
+ * Creates a MultiPolygon from all Polygons on the geometry stack and places
+ * the result
+ * back on the geometry stack.
+ */
+ public GeomBuilder multiPolygon() {
+ gstack.push(factory.createMultiPolygon(gpopAll(Polygon.class)));
+ return this;
+ }
+
+ /**
+ * Creates a GeometryCollection from all Geometries on the geometry stack
+ * and places the result
+ * back on the geometry stack.
+ */
+ public GeomBuilder collection() {
+ gstack.push(factory.createGeometryCollection(gpopAll(Geometry.class)));
+ return this;
+ }
+
+ /**
+ * Buffers the geometry at the top of the geometry stack, and places the
+ * result back on the
+ * geometry stack.
+ */
+ public GeomBuilder buffer(double amt) {
+ gstack.push(gpop(Geometry.class).buffer(amt));
+ return this;
+ }
+
+ /**
+ * Consumes the top of the geometry stack.
+ */
+ public Geometry get() {
+ return gpop(Geometry.class);
+ }
+
+ /**
+ * Builds and returns a Point.
+ *
+ * This method is equivalent to:
+ *
+ *
+ * (Point) point().get();
+ *
+ *
+ *
+ */
+ public Point toPoint() {
+ return point().gpop(Point.class);
+ }
+
+ /**
+ * Builds and returns a LineString.
+ *
+ * This method is equivalent to:
+ *
+ *
+ * (LineString) lineString().get();
+ *
+ *
+ *
+ */
+ public LineString toLineString() {
+ return lineString().gpop(LineString.class);
+ }
+
+ /**
+ * Builds and returns a LineString.
+ *
+ * This method is equivalent to:
+ *
+ *
+ * (LinearRing) ring().get();
+ *
+ *
+ *
+ */
+ public LinearRing toLinearRing() {
+ return ring().gpop(LinearRing.class);
+ }
+
+ /**
+ * Builds and returns a Polygon.
+ *
+ * This method is equivalent to:
+ *
+ *
+ * (Polygon) polygon().get();
+ *
+ *
+ *
+ */
+ public Polygon toPolygon() {
+ return polygon().gpop(Polygon.class);
+ }
+
+ /**
+ * Builds and returns a MultiPoint.
+ *
+ * This method is equivalent to:
+ *
+ *
+ * (MultiPoint) multiPoint().get();
+ *
+ *
+ *
+ */
+ public MultiPoint toMultiPoint() {
+ return multiPoint().gpop(MultiPoint.class);
+ }
+
+ /**
+ * Builds and returns a MultiLineString.
+ *
+ * This method is equivalent to:
+ *
+ *
+ * (MultiLineString) multiLineString().get();
+ *
+ *
+ *
+ */
+ public MultiLineString toMultiLineString() {
+ return multiLineString().gpop(MultiLineString.class);
+ }
+
+ /**
+ * Builds and returns a MultiPolygon.
+ *
+ * This method is equivalent to:
+ *
+ *
+ * (MultiPolygon) multiPolygon().get();
+ *
+ *
+ *
+ */
+ public MultiPolygon toMultiPolygon() {
+ return multiPolygon().gpop(MultiPolygon.class);
+ }
+
+ /**
+ * Builds and returns a GEometryCollection.
+ *
+ * This method is equivalent to:
+ *
+ *
+ * (GeometryCollection) collection().get();
+ *
+ *
+ *
+ */
+ public GeometryCollection toCollection() {
+ return collection().gpop(GeometryCollection.class);
+ }
+
+ Coordinate cpop() {
+ return cpop(1)[0];
+ }
+
+ Coordinate[] cpop(int n) {
+ if (cstack.size() < n) {
+ throw new IllegalStateException(String.format("Expected %d values on coordinate stack, "
+ + "but found %d",
+ n,
+ cstack.size()));
+ }
+
+ Coordinate[] c = new Coordinate[n];
+ for (int i = 0; i < n; i++) {
+ c[n - i - 1] = cstack.pop();
+ }
+ return c;
+ }
+
+ Coordinate[] cpopAll() {
+ if (cstack.isEmpty()) {
+ throw new IllegalStateException("Coordinate stack is empty");
+ }
+
+ return cpop(cstack.size());
+ }
+
+ T gpop(Class clazz) {
+ return gpop(1, clazz)[0];
+ }
+
+ T[] gpop(int n, Class clazz) {
+ if (gstack.size() < n) {
+ throw new IllegalStateException(String.format("Expected %d values on geometry stack, "
+ + "but found %d", n, gstack.size()));
+ }
+
+ @SuppressWarnings("unchecked")
+ T[] l = (T[]) Array.newInstance(clazz, n);
+ for (int i = 0; i < n; i++) {
+ Object g = gstack.pop();
+ if (!clazz.isInstance(g)) {
+ throw new IllegalStateException(String.format("Expected %s on geometry stack, but "
+ + "found %s", clazz.getSimpleName(), g.getClass().getSimpleName()));
+ }
+
+ l[n - i - 1] = clazz.cast(g);
+ }
+ return l;
+ }
+
+ T[] gpopAll(Class clazz) {
+ if (gstack.isEmpty()) {
+ throw new IllegalArgumentException("Geometry stack is empty");
+ }
+
+ int n = 0;
+ Iterator it = gstack.iterator();
+ while (it.hasNext() && clazz.isInstance(it.next())) {
+ n++;
+ }
+
+ if (n == 0) {
+ throw new IllegalArgumentException(
+ String.format("Expected %s on geometry stack",
+ clazz.getSimpleName()));
+ }
+
+ return gpop(n, clazz);
+ }
+}