diff --git a/vtm-jeo-android/AndroidManifest.xml b/vtm-jeo-android/AndroidManifest.xml new file mode 100644 index 00000000..d1f57c85 --- /dev/null +++ b/vtm-jeo-android/AndroidManifest.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/vtm-jeo-android/project.properties b/vtm-jeo-android/project.properties new file mode 100644 index 00000000..b351fa60 --- /dev/null +++ b/vtm-jeo-android/project.properties @@ -0,0 +1,15 @@ +# This file is automatically generated by Android Tools. +# Do not modify this file -- YOUR CHANGES WILL BE ERASED! +# +# This file must be checked in Version Control Systems. +# +# To customize properties used by the Ant build system edit +# "ant.properties", and override values to adapt the script to your +# project structure. +# +# To enable ProGuard to shrink and obfuscate your code, uncomment this (available properties: sdk.dir, user.home): +#proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt + +# Project target. +target=android-17 +android.library.reference.1=../../vtm-android diff --git a/vtm-jeo-android/res/drawable/ic_launcher.png b/vtm-jeo-android/res/drawable/ic_launcher.png new file mode 100644 index 00000000..6496c5ad Binary files /dev/null and b/vtm-jeo-android/res/drawable/ic_launcher.png differ diff --git a/vtm-jeo-android/res/layout/activity_map.xml b/vtm-jeo-android/res/layout/activity_map.xml new file mode 100644 index 00000000..e761d147 --- /dev/null +++ b/vtm-jeo-android/res/layout/activity_map.xml @@ -0,0 +1,93 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/vtm-jeo-android/src/org/oscim/jeo/android/TestActivity.java b/vtm-jeo-android/src/org/oscim/jeo/android/TestActivity.java new file mode 100644 index 00000000..8128a707 --- /dev/null +++ b/vtm-jeo-android/src/org/oscim/jeo/android/TestActivity.java @@ -0,0 +1,162 @@ +package org.oscim.jeo.android; + +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.util.Arrays; + +import org.jeo.data.VectorDataset; +import org.jeo.map.Style; +import org.oscim.android.MapActivity; +import org.oscim.layers.OSMIndoorLayer; +import org.oscim.layers.tile.vector.BuildingLayer; +import org.oscim.layers.tile.vector.VectorTileLayer; +import org.oscim.layers.tile.vector.labeling.LabelLayer; +import org.oscim.renderer.MapRenderer; +import org.oscim.test.JeoTest; +import org.oscim.theme.VtmThemes; +import org.oscim.tiling.source.oscimap4.OSciMap4TileSource; +import org.oscim.utils.IOUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import android.content.Context; +import android.os.Bundle; +import android.os.Environment; +import android.view.View; +import android.widget.Toast; +import android.widget.ToggleButton; + +public class TestActivity extends MapActivity { + public static final Logger log = LoggerFactory.getLogger(TestActivity.class); + + //String PATH = "http://opensciencemap.org/featureserver/featureserver.cgi/osm_indoor"; + + // from http://overpass-turbo.eu/s/2vp + String PATH = "https://gist.github.com/hjanetzek/8959418/raw/overpass.geojson"; + //String PATH = "https://gist.github.com/anonymous/8960337/raw/overpass.geojson"; + + private OSMIndoorLayer mIndoorLayer; + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_map); + + MapRenderer.setBackgroundColor(0xff909090); + + mMap.addTask(new Runnable() { + @Override + public void run() { + showToast("load data"); + InputStream is = null; + try { + File file = new File(Environment.getExternalStorageDirectory() + .getAbsolutePath(), "osmindoor.json"); + is = new FileInputStream(file); + + //URL url = new URL(PATH); + //URLConnection conn = url.openConnection(); + //is = conn.getInputStream(); + loadJson(is); + } catch (IOException e) { + e.printStackTrace(); + } finally { + IOUtils.closeQuietly(is); + } + } + }); + + VectorTileLayer baseLayer = mMap.setBaseMap(new OSciMap4TileSource()); + mMap.layers().add(new BuildingLayer(mMap, baseLayer)); + mMap.layers().add(new LabelLayer(mMap, baseLayer)); + mMap.setTheme(VtmThemes.TRON2); + + mMap.setMapPosition(49.417, 8.673, 1 << 17); + // mMap.setMapPosition(53.5620092, 9.9866457, 1 << 16); + + // mMap.layers().add(new TileGridLayer(mMap)); + // String file = Environment.getExternalStorageDirectory().getAbsolutePath(); + // VectorDataset data = (VectorDataset) JeoTest.getJsonData(file + "/states.json", true); + // Style style = JeoTest.getStyle(); + // mMap.layers().add(new JeoVectorLayer(mMap, data, style)); + } + + void loadJson(InputStream is) { + showToast("got data"); + + VectorDataset data = JeoTest.readGeoJson(is); + Style style = JeoTest.getStyle(); + mIndoorLayer = new OSMIndoorLayer(mMap, data, style); + mMap.layers().add(mIndoorLayer); + + showToast("data ready"); + mMap.updateMap(true); + + mIndoorLayer.activeLevels[0] = true; + shift(); + } + + public void showToast(final String text) { + final Context ctx = this; + runOnUiThread(new Runnable() { + @Override + public void run() { + Toast toast = Toast.makeText(ctx, text, Toast.LENGTH_SHORT); + toast.show(); + } + }); + } + + boolean mShift = true; + + public void shift() { + if (!mShift) + return; + + mMap.postDelayed(new Runnable() { + + @Override + public void run() { + for (int i = 0; i < 10; i++) { + if (mIndoorLayer.activeLevels[i]) { + mIndoorLayer.activeLevels[i] = false; + mIndoorLayer.activeLevels[(i + 1) % 9] = true; + mIndoorLayer.update(); + break; + } + } + shift(); + } + }, 200); + + } + + public void onClick(View v) { + mShift = false; + + if (mIndoorLayer == null) + return; + + int i = 0; + + if (v instanceof ToggleButton) { + ToggleButton b = (ToggleButton) v; + i = (b.getTextOn().charAt(0) - '0') + 1; + } + + if (i < 0 || i > 9) + i = 0; + + mIndoorLayer.activeLevels[i] ^= true; + ((ToggleButton) v).setChecked(mIndoorLayer.activeLevels[i]); + log.debug(Arrays.toString(mIndoorLayer.activeLevels)); + mIndoorLayer.update(); + } + + @Override + protected void onStop() { + super.onStop(); + } +} diff --git a/vtm-jeo-desktop/src/org/oscim/jeo/test/LayerTest.java b/vtm-jeo-desktop/src/org/oscim/jeo/test/LayerTest.java new file mode 100644 index 00000000..5fe5a2ed --- /dev/null +++ b/vtm-jeo-desktop/src/org/oscim/jeo/test/LayerTest.java @@ -0,0 +1,27 @@ +package org.oscim.jeo.test; + +import org.jeo.data.VectorDataset; +import org.jeo.map.Style; +import org.oscim.gdx.GdxMap; +import org.oscim.gdx.GdxMapApp; +import org.oscim.layers.JeoVectorLayer; +import org.oscim.test.JeoTest; + +public class LayerTest extends GdxMap { + + @Override + public void createLayers() { + //JeoTest.indoorSketch(mMap, "osmindoor.json"); + //mMap.setMapPosition(49.417, 8.673, 1 << 17); + + VectorDataset data = (VectorDataset) JeoTest.getJsonData("states.json", true); + Style style = JeoTest.getStyle(); + + mMap.layers().add(new JeoVectorLayer(mMap, data, style)); + } + + public static void main(String[] args) { + GdxMapApp.init(); + GdxMapApp.run(new LayerTest(), null, 256); + } +} diff --git a/vtm-jeo-desktop/src/org/oscim/jeo/test/ThemeTest.java b/vtm-jeo-desktop/src/org/oscim/jeo/test/ThemeTest.java new file mode 100644 index 00000000..57eff695 --- /dev/null +++ b/vtm-jeo-desktop/src/org/oscim/jeo/test/ThemeTest.java @@ -0,0 +1,34 @@ +package org.oscim.jeo.test; + +import org.oscim.gdx.GdxMapApp; +import org.oscim.layers.TileGridLayer; +import org.oscim.layers.tile.vector.VectorTileLayer; +import org.oscim.renderer.MapRenderer; +import org.oscim.theme.carto.RenderTheme; +import org.oscim.tiling.source.UrlTileSource; +import org.oscim.tiling.source.oscimap4.OSciMap4TileSource; + +public class ThemeTest extends GdxMapApp { + + public static void main(String[] args) { + GdxMapApp.init(); + GdxMapApp.run(new ThemeTest(), null, 256); + } + + @Override + public void createLayers() { + UrlTileSource ts = new OSciMap4TileSource(); + + VectorTileLayer l = mMap.setBaseMap(ts); + + l.setRenderTheme(new RenderTheme()); + + MapRenderer.setBackgroundColor(0xffcccccc); + + // mMap.getLayers().add(new LabelLayer(mMap, + // mMapLayer.getTileLayer())); + // mMap.getLayers().add(new JeoMapLayer(mMap)); + + mMap.layers().add(new TileGridLayer(mMap)); + } +} diff --git a/vtm-jeo/src/org/oscim/jeo/JeoUtils.java b/vtm-jeo/src/org/oscim/jeo/JeoUtils.java new file mode 100644 index 00000000..0395d589 --- /dev/null +++ b/vtm-jeo/src/org/oscim/jeo/JeoUtils.java @@ -0,0 +1,12 @@ +package org.oscim.jeo; + +import org.jeo.map.RGB; + +public class JeoUtils { + public static int color(RGB rgb) { + return rgb.getAlpha() << 24 + | rgb.getRed() << 16 + | rgb.getGreen() << 8 + | rgb.getBlue(); + } +} diff --git a/vtm-jeo/src/org/oscim/layers/JeoMapLayer.java b/vtm-jeo/src/org/oscim/layers/JeoMapLayer.java deleted file mode 100644 index 083a11f0..00000000 --- a/vtm-jeo/src/org/oscim/layers/JeoMapLayer.java +++ /dev/null @@ -1,80 +0,0 @@ -package org.oscim.layers; - -import org.jeo.data.Dataset; -import org.jeo.map.Style; -import org.oscim.core.MapPosition; -import org.oscim.layers.JeoMapLoader.Task; -import org.oscim.map.Map; -import org.oscim.map.Map.UpdateListener; -import org.oscim.renderer.ElementRenderer; -import org.oscim.renderer.MapRenderer.Matrices; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public class JeoMapLayer extends Layer implements UpdateListener { - - public static final Logger log = LoggerFactory.getLogger(JeoMapLayer.class); - - final org.jeo.map.View view; - private final org.jeo.map.Map mJeoMap; - - private final JeoMapLoader mWorker; - - public JeoMapLayer(Map map, Dataset data, Style style) { - super(map); - - mJeoMap = org.jeo.map.Map.build().layer(data).style(style).map(); - view = mJeoMap.getView(); - - mRenderer = new ElementRenderer() { - @Override - protected synchronized void update(MapPosition position, boolean changed, - Matrices matrices) { - - if (mNewLayers != null) { - mMapPosition.copy(mNewLayers); - - this.layers.clear(); - this.layers.baseLayers = mNewLayers.layers; - mNewLayers = null; - - compile(); - log.debug("is ready " + isReady() + " " + layers.getSize()); - } - } - }; - - mWorker = new JeoMapLoader(this); - mWorker.start(); - } - - @Override - public void onDetach() { - super.onDetach(); - - mWorker.awaitPausing(); - try { - mWorker.join(); - } catch (Exception e) { - log.error(e.toString()); - } - } - - @Override - public void onMapUpdate(MapPosition pos, boolean changed, boolean clear) { - if (changed) { - log.debug("go"); - mWorker.go(); - } - } - - Task mNewLayers; - - void setLayers(Task newLayers) { - synchronized (mRenderer) { - mNewLayers = newLayers; - } - mMap.render(); - } - -} diff --git a/vtm-jeo/src/org/oscim/layers/JeoMapLoader.java b/vtm-jeo/src/org/oscim/layers/JeoMapLoader.java deleted file mode 100644 index ad7da174..00000000 --- a/vtm-jeo/src/org/oscim/layers/JeoMapLoader.java +++ /dev/null @@ -1,346 +0,0 @@ -package org.oscim.layers; - -// FIXME -// Apache License 2.0 - -import java.io.IOException; - -import org.jeo.data.Dataset; -import org.jeo.data.Query; -import org.jeo.data.VectorDataset; -import org.jeo.feature.Feature; -import org.jeo.geom.CoordinatePath; -import org.jeo.geom.Envelopes; -import org.jeo.geom.Geom; -import org.jeo.map.CartoCSS; -import org.jeo.map.Map; -import org.jeo.map.RGB; -import org.jeo.map.Rule; -import org.jeo.map.RuleList; -import org.jeo.map.View; -import org.oscim.core.BoundingBox; -import org.oscim.core.GeometryBuffer; -import org.oscim.core.MapPosition; -import org.oscim.core.MercatorProjection; -import org.oscim.core.Tile; -import org.oscim.renderer.elements.ElementLayers; -import org.oscim.renderer.elements.LineLayer; -import org.oscim.renderer.elements.MeshLayer; -import org.oscim.renderer.elements.RenderElement; -import org.oscim.theme.renderinstruction.Line; -import org.oscim.utils.PausableThread; -import org.oscim.utils.TileClipper; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import com.vividsolutions.jts.geom.Coordinate; -import com.vividsolutions.jts.geom.Envelope; -import com.vividsolutions.jts.geom.Geometry; - -/** - * Does the work of actually rendering the map, outside of the ui thread. - * - * @author Justin Deoliveira, OpenGeo - * @author Hannes Janetzek, OpenScienceMap - */ - -public class JeoMapLoader extends PausableThread { - - static final Logger log = LoggerFactory.getLogger(JeoMapLoader.class); - - private final JeoMapLayer mMapLayer; - - public JeoMapLoader(JeoMapLayer mapLayer) { - mMapLayer = mapLayer; - } - - private ElementLayers layers; - private final GeometryBuffer mGeom = new GeometryBuffer(128, 4); - - private Task mCurrentTask; - - private double mMinX; - private double mMinY; - - @Override - protected void doWork() throws InterruptedException { - log.debug("start"); - mWork = false; - Envelope env = new Envelope(); - BoundingBox bbox = mMapLayer.mMap.getViewport().getViewBox(); - - env.init(bbox.getMinLongitude(), bbox.getMaxLongitude(), - bbox.getMinLatitude(), bbox.getMaxLatitude()); - int w = mMapLayer.mMap.getWidth(); - int h = mMapLayer.mMap.getHeight(); - mMapLayer.view.setWidth(w); - mMapLayer.view.setHeight(h); - - mClipper.setRect(-w, -h, w, h); - - mMapLayer.view.zoomto(env); - - Task task = new Task(); - task.view = mMapLayer.view.clone(); - - mMapLayer.mMap.getMapPosition(task); - - mCurrentTask = task; - layers = new ElementLayers(); - - Envelope b = task.view.getBounds(); - - // reduce lines points min distance - mMinX = ((b.getMaxX() - b.getMinX()) / task.view.getWidth()) * 2; - mMinY = ((b.getMaxY() - b.getMinY()) / task.view.getHeight()) * 2; - - Map map = mMapLayer.view.getMap(); - - for (org.jeo.map.Layer l : map.getLayers()) { - - if (!l.isVisible()) - continue; - - Dataset data = l.getData(); - - RuleList rules = - map.getStyle().getRules().selectById(l.getName(), true).flatten(); - - log.debug("data {}", data); - - if (data instanceof VectorDataset) { - for (RuleList ruleList : rules.zgroup()) { - render(task.view, (VectorDataset) data, ruleList); - } - } - } - - if (layers.baseLayers != null) { - mCurrentTask.layers = layers.baseLayers; - - //layers.baseLayers = null; - //layers.clear(); - - mMapLayer.setLayers(mCurrentTask); - } - layers = null; - mCurrentTask = null; - - } - - void render(View view, VectorDataset data, RuleList rules) { - - try { - Query q = new Query().bounds(view.getBounds()); - log.debug("query {}", q); - - // reproject - // if (data.getCRS() != null) { - // if (!Proj.equal(view.getCRS(), data.getCRS())) { - // q.reproject(view.getCRS()); - // } - //} - //else { - // log.debug("Layer " + data.getName() - // + " specifies no projection, assuming map projection"); - //} - - for (Feature f : data.cursor(q)) { - - RuleList rs = rules.match(f); - if (rs.isEmpty()) { - continue; - } - - Rule r = rules.match(f).collapse(); - if (r == null) - continue; - - draw(view, f, r); - } - } catch (IOException e) { - log.error("Error querying layer " + data.getName() + e); - } - } - - Geometry clipGeometry(View view, Geometry g) { - // TODO: doing a full intersection is sub-optimal, - // look at a more efficient clipping - // algorithm, like cohen-sutherland - return g.intersection(Envelopes.toPolygon(view.getBounds())); - } - - void draw(View view, Feature f, Rule rule) { - Geometry g = f.geometry(); - if (g == null) { - return; - } - - // g = clipGeometry(view, g); - // if (g.isEmpty()) { - // return; - // } - - switch (Geom.Type.from(g)) { - case POINT: - case MULTIPOINT: - //log.debug("draw point"); - //drawPoint(f, rule); - return; - case LINESTRING: - case MULTILINESTRING: - //log.debug("draw line"); - drawLine(f, rule, g); - return; - case POLYGON: - //Polygon p = (Polygon) g; - //p.reverse(); - //log.debug("draw polygon"); - drawPolygon(f, rule, g); - return; - - case MULTIPOLYGON: - //log.debug("draw polygon"); - for (int i = 0, n = g.getNumGeometries(); i < n; i++) - drawPolygon(f, rule, g.getGeometryN(i)); - return; - default: - throw new UnsupportedOperationException(); - } - } - - private void drawLine(Feature f, Rule rule, Geometry g) { - - LineLayer ll = layers.getLineLayer(0); - - if (ll.line == null) { - RGB color = rule.color(f, CartoCSS.LINE_COLOR, RGB.black); - float width = rule.number(f, CartoCSS.LINE_WIDTH, 1.2f); - ll.line = new Line(0, color(color), width); - ll.width = width; - } - - mGeom.clear(); - mGeom.startLine(); - - CoordinatePath p = CoordinatePath.create(g); - path(mGeom, p); - - //log.debug( ll.width + " add line " + mGeom.pointPos + " " + Arrays.toString(mGeom.points)); - - ll.addLine(mGeom); - } - - TileClipper mClipper = new TileClipper(0, 0, 0, 0); - - private void drawPolygon(Feature f, Rule rule, Geometry g) { - - LineLayer ll = layers.getLineLayer(3); - - if (ll.line == null) { - RGB color = rule.color(f, CartoCSS.POLYGON_FILL, RGB.red); - float width = rule.number(f, CartoCSS.LINE_WIDTH, 1.2f); - ll.line = new Line(2, color(color), width); - ll.width = width; - } - - //PolygonLayer pl = layers.getPolygonLayer(1); - // - //if (pl.area == null) { - // RGB color = rule.color(f, CartoCSS.POLYGON_FILL, RGB.red); - // pl.area = new Area(1, color(color)); - //} - - MeshLayer mesh = layers.getMeshLayer(2); - - mGeom.clear(); - mGeom.startPolygon(); - //mGeom.startLine(); - - CoordinatePath p = CoordinatePath.create(g).generalize(mMinX, mMinY); - if (path(mGeom, p) < 3) - return; - - if (!mClipper.clip(mGeom)) - return; - - //log.debug(ll.width + " add poly " + mGeom.pointPos + " " + Arrays.toString(mGeom.points)); - mesh.addMesh(mGeom); - - ll.addLine(mGeom); - //pl.addPolygon(mGeom.points, mGeom.index); - } - - public static int color(RGB rgb) { - return rgb.getAlpha() << 24 - | rgb.getRed() << 16 - | rgb.getGreen() << 8 - | rgb.getBlue(); - } - - private int path(GeometryBuffer g, CoordinatePath path) { - - MapPosition pos = mCurrentTask; - double scale = pos.scale * Tile.SIZE; - int cnt = 0; - O: while (path.hasNext()) { - Coordinate c = path.next(); - float x = (float) ((MercatorProjection.longitudeToX(c.x) - pos.x) * scale); - float y = (float) ((MercatorProjection.latitudeToY(c.y) - pos.y) * scale); - - switch (path.getStep()) { - case MOVE_TO: - if (g.isPoly()) - g.startPolygon(); - else if (g.isLine()) - g.startLine(); - - cnt++; - g.addPoint(x, y); - break; - - case LINE_TO: - cnt++; - g.addPoint(x, y); - break; - - case CLOSE: - //g.addPoint(x, y); - - //if (g.type == GeometryType.POLY) - break; - case STOP: - break O; - } - } - return cnt; - } - - @Override - protected String getThreadName() { - return "JeoMapLayer"; - } - - @Override - protected boolean hasWork() { - return mWork; - } - - boolean mWork; - - public void go() { - if (hasWork()) - return; - - mWork = true; - - synchronized (this) { - notifyAll(); - } - } - - static class Task extends MapPosition { - View view; - RenderElement layers; - } -} diff --git a/vtm-jeo/src/org/oscim/layers/JeoTileLayer.java b/vtm-jeo/src/org/oscim/layers/JeoTileLayer.java new file mode 100644 index 00000000..f9162dc9 --- /dev/null +++ b/vtm-jeo/src/org/oscim/layers/JeoTileLayer.java @@ -0,0 +1,35 @@ +package org.oscim.layers; + +import org.oscim.layers.tile.MapTile; +import org.oscim.layers.tile.TileLoader; +import org.oscim.layers.tile.TileManager; +import org.oscim.layers.tile.bitmap.BitmapTileLayer; +import org.oscim.map.Map; +import org.oscim.tiling.source.bitmap.BitmapTileSource; + +public class JeoTileLayer extends BitmapTileLayer { + + public JeoTileLayer(Map map, BitmapTileSource tileSource) { + super(map, tileSource); + } + + @Override + protected TileLoader createLoader(TileManager tm) { + return new TileLoader(tm) { + + @Override + public void cleanup() { + // TODO Auto-generated method stub + + } + + @Override + protected boolean executeJob(MapTile tile) { + // TODO Auto-generated method stub + return false; + } + + }; + } + +} diff --git a/vtm-jeo/src/org/oscim/layers/JeoTileSource.java b/vtm-jeo/src/org/oscim/layers/JeoTileSource.java new file mode 100644 index 00000000..0648e10c --- /dev/null +++ b/vtm-jeo/src/org/oscim/layers/JeoTileSource.java @@ -0,0 +1,80 @@ +package org.oscim.layers; + +import java.io.ByteArrayInputStream; +import java.io.IOException; + +import org.jeo.data.Tile; +import org.jeo.data.TileDataset; +import org.oscim.backend.CanvasAdapter; +import org.oscim.backend.canvas.Bitmap; +import org.oscim.layers.tile.MapTile; +import org.oscim.tiling.ITileDataSink; +import org.oscim.tiling.ITileDataSource; +import org.oscim.tiling.TileSource; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class JeoTileSource extends TileSource { + final static Logger log = LoggerFactory.getLogger(JeoTileSource.class); + + final TileDataset mTileDataset; + + public JeoTileSource(TileDataset tileDataset) { + log.debug("load tileset {}", tileDataset.getName()); + mTileDataset = tileDataset; + //mTileDataset.pyramid(). + mZoomMax = 1; + mZoomMin = 0; + } + + @Override + public ITileDataSource getDataSource() { + return new ITileDataSource() { + + @Override + public QueryResult executeQuery(MapTile tile, ITileDataSink sink) { + log.debug("query {}", tile); + try { + Tile t = mTileDataset.read(tile.zoomLevel, tile.tileX, + // flip Y axis + (1 << tile.zoomLevel) - 1 - tile.tileY); + if (t == null) { + log.debug("not found {}", tile); + return QueryResult.TILE_NOT_FOUND; + } + Bitmap b = CanvasAdapter.g.decodeBitmap(new ByteArrayInputStream(t.getData())); + sink.setTileImage(b); + log.debug("success {}", tile); + + return QueryResult.SUCCESS; + + } catch (IOException e) { + e.printStackTrace(); + } + log.debug("fail {}", tile); + + return QueryResult.FAILED; + } + + @Override + public void destroy() { + + } + }; + } + + int mRefs; + + @Override + public OpenResult open() { + mRefs++; + return OpenResult.SUCCESS; + } + + @Override + public void close() { + if (--mRefs == 0) + mTileDataset.close(); + } + +} diff --git a/vtm-jeo/src/org/oscim/layers/JeoVectorLayer.java b/vtm-jeo/src/org/oscim/layers/JeoVectorLayer.java new file mode 100644 index 00000000..8f47e9ec --- /dev/null +++ b/vtm-jeo/src/org/oscim/layers/JeoVectorLayer.java @@ -0,0 +1,150 @@ +package org.oscim.layers; + +import java.io.IOException; + +import org.jeo.data.Query; +import org.jeo.data.VectorDataset; +import org.jeo.feature.Feature; +import org.jeo.geom.Geom; +import org.jeo.map.CartoCSS; +import org.jeo.map.RGB; +import org.jeo.map.Rule; +import org.jeo.map.RuleList; +import org.jeo.map.Style; +import org.oscim.jeo.JeoUtils; +import org.oscim.map.Map; +import org.oscim.renderer.elements.LineLayer; +import org.oscim.renderer.elements.MeshLayer; +import org.oscim.theme.styles.Area; +import org.oscim.theme.styles.Line; +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; + +public class JeoVectorLayer extends JtsLayer { + + public static final Logger log = LoggerFactory.getLogger(JeoVectorLayer.class); + static final boolean dbg = false; + + private final VectorDataset mDataset; + private final RuleList mRules; + + protected double mDropPointDistance = 0.01; + + public JeoVectorLayer(Map map, VectorDataset data, Style style) { + super(map); + mDataset = data; + + mRules = style.getRules().selectById(data.getName(), true).flatten(); + //mRules = style.getRules().selectById("way", true).flatten(); + log.debug(mRules.toString()); + + mRenderer = new Renderer(); + } + + @Override + protected void processFeatures(Task t, Envelope b) { + if (mDropPointDistance > 0) { + /* reduce lines points min distance */ + mMinX = ((b.getMaxX() - b.getMinX()) / mMap.getWidth()); + mMinY = ((b.getMaxY() - b.getMinY()) / mMap.getHeight()); + mMinX *= mDropPointDistance; + mMinY *= mDropPointDistance; + } + + try { + Query q = new Query().bounds(b); + if (dbg) + log.debug("query {}", b); + for (Feature f : mDataset.cursor(q)) { + if (dbg) + log.debug("feature {}", f); + + RuleList rs = mRules.match(f); + if (rs.isEmpty()) + continue; + + Rule r = rs.collapse(); + if (r == null) + continue; + + Geometry g = f.geometry(); + if (g == null) + continue; + + switch (Geom.Type.from(g)) { + case POINT: + addPoint(t, f, r, g); + break; + case MULTIPOINT: + for (int i = 0, n = g.getNumGeometries(); i < n; i++) + addPoint(t, f, r, g.getGeometryN(i)); + break; + case LINESTRING: + addLine(t, f, r, g); + break; + case MULTILINESTRING: + for (int i = 0, n = g.getNumGeometries(); i < n; i++) + addLine(t, f, r, g.getGeometryN(i)); + break; + case POLYGON: + addPolygon(t, f, r, g); + break; + case MULTIPOLYGON: + for (int i = 0, n = g.getNumGeometries(); i < n; i++) + addPolygon(t, f, r, g.getGeometryN(i)); + break; + default: + break; + } + } + } catch (IOException e) { + log.error("Error querying layer " + mDataset.getName() + e); + } + } + + protected void addLine(Task t, Feature f, Rule rule, Geometry g) { + + if (((LineString) g).isClosed()) { + addPolygon(t, f, rule, g); + return; + } + + LineLayer ll = t.layers.getLineLayer(2); + if (ll.line == null) { + RGB color = rule.color(f, CartoCSS.LINE_COLOR, RGB.black); + float width = rule.number(f, CartoCSS.LINE_WIDTH, 1.2f); + ll.line = new Line(0, JeoUtils.color(color), width); + ll.setDropDistance(0.5f); + } + + addLine(t, g, ll); + } + + protected void addPolygon(Task t, Feature f, Rule rule, Geometry g) { + + LineLayer ll = t.layers.getLineLayer(1); + + if (ll.line == null) { + float width = rule.number(f, CartoCSS.LINE_WIDTH, 1.2f); + RGB color = rule.color(f, CartoCSS.LINE_COLOR, RGB.black); + ll.line = new Line(0, JeoUtils.color(color), width); + ll.setDropDistance(0.5f); + } + + MeshLayer mesh = t.layers.getMeshLayer(0); + if (mesh.area == null) { + int color = JeoUtils.color(rule.color(f, CartoCSS.POLYGON_FILL, RGB.red)); + mesh.area = new Area(color); + } + + addPolygon(t, g, mesh, ll); + } + + protected void addPoint(Task t, Feature f, Rule rule, Geometry g) { + + } +} diff --git a/vtm-jeo/src/org/oscim/layers/JtsLayer.java b/vtm-jeo/src/org/oscim/layers/JtsLayer.java new file mode 100644 index 00000000..6a1cf5e3 --- /dev/null +++ b/vtm-jeo/src/org/oscim/layers/JtsLayer.java @@ -0,0 +1,102 @@ +package org.oscim.layers; + +import org.jeo.geom.CoordinatePath; +import org.oscim.core.BoundingBox; +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.AbstractVectorLayer; +import org.oscim.map.Map; +import org.oscim.renderer.elements.LineLayer; +import org.oscim.renderer.elements.MeshLayer; +import org.oscim.utils.geom.SimplifyDP; +import org.oscim.utils.geom.SimplifyVW; + +import com.vividsolutions.jts.geom.Coordinate; +import com.vividsolutions.jts.geom.Envelope; +import com.vividsolutions.jts.geom.Geometry; + +public abstract class JtsLayer extends AbstractVectorLayer { + + 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 abstract void processFeatures(Task t, Envelope e); + + protected int transformPath(MapPosition pos, GeometryBuffer g, CoordinatePath path) { + + double scale = pos.scale * Tile.SIZE / UNSCALE_COORD; + int cnt = 0; + O: while (path.hasNext()) { + Coordinate c = path.next(); + float x = (float) ((MercatorProjection.longitudeToX(c.x) - pos.x) * scale); + float y = (float) ((MercatorProjection.latitudeToY(c.y) - pos.y) * scale); + + switch (path.getStep()) { + case MOVE_TO: + if (g.isPoly()) + g.startPolygon(); + else if (g.isLine()) + g.startLine(); + + cnt++; + g.addPoint(x, y); + break; + case LINE_TO: + cnt++; + g.addPoint(x, y); + break; + case CLOSE: + //g.addPoint(x, y); + //if (g.type == GeometryType.POLY) + break; + case STOP: + break O; + } + } + return cnt; + } + + SimplifyDP mSimpDP = new SimplifyDP(); + SimplifyVW mSimpVW = new SimplifyVW(); + + protected void addPolygon(Task t, Geometry g, MeshLayer ml, LineLayer ll) { + mGeom.clear(); + mGeom.startPolygon(); + + CoordinatePath p = CoordinatePath.create(g); + if (mMinX > 0 || mMinY > 0) + p.generalize(mMinX, mMinY); + + if (transformPath(t.position, mGeom, p) < 3) + return; + + if (!mClipper.clip(mGeom)) + return; + + mSimpVW.simplify(mGeom, 0.1f); + mSimpDP.simplify(mGeom, 0.5f); + + ll.addLine(mGeom); + ml.addMesh(mGeom); + } + + protected void addLine(Task t, Geometry g, LineLayer ll) { + mGeom.clear(); + mGeom.startLine(); + + CoordinatePath p = CoordinatePath.create(g); + transformPath(t.position, mGeom, p); + + ll.addLine(mGeom); + } +} diff --git a/vtm-jeo/src/org/oscim/layers/OSMIndoorLayer.java b/vtm-jeo/src/org/oscim/layers/OSMIndoorLayer.java new file mode 100644 index 00000000..e1f8d4c0 --- /dev/null +++ b/vtm-jeo/src/org/oscim/layers/OSMIndoorLayer.java @@ -0,0 +1,141 @@ +package org.oscim.layers; + +import java.util.HashMap; + +import org.jeo.data.VectorDataset; +import org.jeo.feature.Feature; +import org.jeo.map.CartoCSS; +import org.jeo.map.RGB; +import org.jeo.map.Rule; +import org.jeo.map.Style; +import org.oscim.backend.canvas.Color; +import org.oscim.jeo.JeoUtils; +import org.oscim.map.Map; +import org.oscim.renderer.elements.LineLayer; +import org.oscim.renderer.elements.MeshLayer; +import org.oscim.renderer.elements.TextItem; +import org.oscim.renderer.elements.TextLayer; +import org.oscim.theme.styles.Area; +import org.oscim.theme.styles.Line; +import org.oscim.theme.styles.Text; + +import com.vividsolutions.jts.geom.Envelope; +import com.vividsolutions.jts.geom.Geometry; +import com.vividsolutions.jts.geom.LineString; + +public class OSMIndoorLayer extends JeoVectorLayer { + + protected TextLayer mTextLayer; + protected Text mText = Text.createText(16, 2.2f, Color.BLACK, Color.WHITE, true); + + public OSMIndoorLayer(Map map, VectorDataset data, Style style) { + super(map, data, style); + } + + public boolean[] activeLevels = new boolean[10]; + + @Override + protected void processFeatures(Task t, Envelope b) { + mTextLayer = t.layers.addTextLayer(new TextLayer()); + + super.processFeatures(t, b); + + //render TextItems to a bitmap and prepare vertex buffer data. + mTextLayer.prepare(); + mTextLayer.clearLabels(); + } + + protected void addLine(Task t, Feature f, Rule rule, Geometry g) { + + if (((LineString) g).isClosed()) { + addPolygon(t, f, rule, g); + return; + } + + int level = getLevel(f); + + LineLayer ll = t.layers.getLineLayer(level * 3 + 2); + if (ll.line == null) { + RGB color = rule.color(f, CartoCSS.LINE_COLOR, RGB.black); + float width = rule.number(f, CartoCSS.LINE_WIDTH, 1.2f); + ll.line = new Line(0, JeoUtils.color(color), width); + ll.heightOffset = level * 4; + ll.setDropDistance(0); + } + + addLine(t, g, ll); + } + + protected void addPolygon(Task t, Feature f, Rule rule, Geometry g) { + int level = getLevel(f); + + LineLayer ll = t.layers.getLineLayer(level * 3 + 1); + + if (ll.line == null) { + float width = rule.number(f, CartoCSS.LINE_WIDTH, 1.2f); + int color = Color.rainbow((level + 1) / 10f); + + if (level > -2 && !activeLevels[level + 1]) + color = Color.fade(color, 0.1f); + + ll.line = new Line(0, color, width); + ll.heightOffset = level * 4; + ll.setDropDistance(0); + } + + MeshLayer mesh = t.layers.getMeshLayer(level * 3); + if (mesh.area == null) { + int color = JeoUtils.color(rule.color(f, CartoCSS.POLYGON_FILL, RGB.red)); + if (level > -2 && !activeLevels[level + 1]) + color = Color.fade(color, 0.1f); + + mesh.area = new Area(color); + //mesh.area = new Area(Color.fade(Color.DKGRAY, 0.1f)); + mesh.heightOffset = level * 4f; + } + + addPolygon(t, g, mesh, ll); + + Object o = f.get("name"); + if (o instanceof String) { + float x = 0; + float y = 0; + int n = mGeom.index[0]; + for (int i = 0; i < n;) { + x += mGeom.points[i++]; + y += mGeom.points[i++]; + } + + TextItem ti = TextItem.pool.get(); + ti.set(x / (n / 2) / 8, y / (n / 2) / 8, (String) o, mText); + + mTextLayer.addText(ti); + } + } + + @Override + protected void addPoint(Task t, Feature f, Rule rule, Geometry g) { + + } + + private int getLevel(Feature f) { + /* not sure if one could match these geojson properties with cartocss */ + Object o = f.get("@relations"); + if (o instanceof HashMap) { + @SuppressWarnings("unchecked") + HashMap tags = (HashMap) o; + @SuppressWarnings("unchecked") + HashMap reltags = (HashMap) tags.get("reltags"); + + if (reltags != null) { + o = reltags.get("level"); + if (o instanceof String) { + //log.debug("got level {}", o); + return Integer.parseInt((String) o); + } + } + } + return 0; + } + +} diff --git a/vtm-jeo/src/org/oscim/layers/JeoTestData.java b/vtm-jeo/src/org/oscim/test/JeoTest.java similarity index 60% rename from vtm-jeo/src/org/oscim/layers/JeoTestData.java rename to vtm-jeo/src/org/oscim/test/JeoTest.java index d2be9c73..d29955a3 100644 --- a/vtm-jeo/src/org/oscim/layers/JeoTestData.java +++ b/vtm-jeo/src/org/oscim/test/JeoTest.java @@ -1,11 +1,15 @@ -package org.oscim.layers; +package org.oscim.test; import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; import java.io.IOException; +import java.io.InputStream; import org.jeo.carto.Carto; import org.jeo.data.Dataset; import org.jeo.data.Query; +import org.jeo.data.VectorDataset; import org.jeo.data.mem.MemVector; import org.jeo.data.mem.MemWorkspace; import org.jeo.feature.Feature; @@ -13,24 +17,52 @@ import org.jeo.feature.Features; import org.jeo.feature.Schema; import org.jeo.feature.SchemaBuilder; import org.jeo.geojson.GeoJSONDataset; +import org.jeo.geojson.GeoJSONReader; import org.jeo.geom.GeomBuilder; import org.jeo.map.Style; +import org.oscim.layers.OSMIndoorLayer; +import org.oscim.layers.tile.vector.BuildingLayer; +import org.oscim.layers.tile.vector.VectorTileLayer; +import org.oscim.map.Map; +import org.oscim.renderer.MapRenderer; +import org.oscim.tiling.source.oscimap4.OSciMap4TileSource; import com.vividsolutions.jts.geom.Geometry; -public class JeoTestData { +public class JeoTest { + + public static void indoorSketch(Map map, String file) { + MapRenderer.setBackgroundColor(0xff909090); + VectorTileLayer baseLayer = map.setBaseMap(new OSciMap4TileSource()); + map.layers().add(new BuildingLayer(map, baseLayer)); + + VectorDataset data = null; + try { + data = JeoTest.readGeoJson(new FileInputStream(new File(file))); + } catch (FileNotFoundException e) { + e.printStackTrace(); + } + + Style style = JeoTest.getStyle(); + map.layers().add(new OSMIndoorLayer(map, data, style)); + } public static Style getStyle() { Style style = null; try { style = Carto.parse("" + - "#things {" + + "#way {" + + " line-width: 2;" + " line-color: #c80;" + - " polygon-fill: #00a;" + + " polygon-fill: #44111111;" + + " " + "}" + "#states {" + - " polygon-fill: #0dc;" + + " line-width: 2.2;" + + " line-color: #c80;" + + " polygon-fill: #44111111;" + + " " + "}" ); @@ -41,6 +73,29 @@ public class JeoTestData { return null; } + public static VectorDataset readGeoJson(InputStream is) { + GeoJSONReader r = new GeoJSONReader(); + + @SuppressWarnings("resource") + MemWorkspace mem = new MemWorkspace(); + + //mem.put("layer", data); + try { + Schema s = new SchemaBuilder("way").schema(); + + MemVector memData = mem.create(s); + + for (Feature f : r.features(is)) { + //System.out.println("loaded: " + f); + memData.add(f); + } + return memData; + } catch (IOException e) { + e.printStackTrace(); + } + return null; + } + public static Dataset getJsonData(String file, boolean memory) { GeoJSONDataset data = null; @@ -53,6 +108,7 @@ public class JeoTestData { } if (memory) { + @SuppressWarnings("resource") MemWorkspace mem = new MemWorkspace(); //mem.put("layer", data); @@ -79,6 +135,7 @@ public class JeoTestData { public static Dataset getMemWorkspace(String layer) { GeomBuilder gb = new GeomBuilder(4326); + @SuppressWarnings("resource") MemWorkspace mem = new MemWorkspace(); Schema schema = new SchemaBuilder(layer) .field("geometry", Geometry.class) @@ -90,11 +147,9 @@ public class JeoTestData { try { data = mem.create(schema); } catch (UnsupportedOperationException e) { - // TODO Auto-generated catch block e.printStackTrace(); return null; } catch (IOException e) { - // TODO Auto-generated catch block e.printStackTrace(); return null; } diff --git a/vtm-jeo/src/org/oscim/theme/carto/RenderTheme.java b/vtm-jeo/src/org/oscim/theme/carto/RenderTheme.java index 042a8794..92c7f398 100644 --- a/vtm-jeo/src/org/oscim/theme/carto/RenderTheme.java +++ b/vtm-jeo/src/org/oscim/theme/carto/RenderTheme.java @@ -13,16 +13,15 @@ import org.jeo.map.CartoCSS; import org.jeo.map.RGB; import org.jeo.map.Rule; import org.jeo.map.RuleList; -import org.jeo.map.Selector; import org.jeo.map.Style; import org.oscim.core.GeometryBuffer.GeometryType; import org.oscim.core.MapElement; import org.oscim.core.Tag; import org.oscim.core.TagSet; import org.oscim.theme.IRenderTheme; -import org.oscim.theme.renderinstruction.Area; -import org.oscim.theme.renderinstruction.Line; -import org.oscim.theme.renderinstruction.RenderInstruction; +import org.oscim.theme.styles.Area; +import org.oscim.theme.styles.Line; +import org.oscim.theme.styles.RenderStyle; public class RenderTheme implements IRenderTheme { @@ -117,7 +116,7 @@ public class RenderTheme implements IRenderTheme { class StyleSet { int level; - RenderInstruction[] ri = new RenderInstruction[2]; + RenderStyle[] ri = new RenderStyle[2]; } Map mStyleSets = new HashMap(); @@ -132,11 +131,6 @@ public class RenderTheme implements IRenderTheme { sb.append(pad); - for (Selector s : r.getSelectors()) { - sb.append(RuleDebug.formatSelector(s)); - sb.append(","); - } - if (sb.length() > 0) sb.setLength(sb.length() - 1); @@ -183,7 +177,7 @@ public class RenderTheme implements IRenderTheme { } @Override - public synchronized RenderInstruction[] matchElement(GeometryType type, TagSet tags, + public synchronized RenderStyle[] matchElement(GeometryType type, TagSet tags, int zoomLevel) { MatcherFeature f = mMatchFeature; @@ -203,7 +197,7 @@ public class RenderTheme implements IRenderTheme { if (type == GeometryType.POLY) { RGB c = r.color(f, CartoCSS.POLYGON_FILL, RGB.black); out.println(z + " " + c); - return new RenderInstruction[] { + return new RenderStyle[] { new Area(z, color(c)) }; @@ -212,7 +206,7 @@ public class RenderTheme implements IRenderTheme { float width = r.number(f, CartoCSS.LINE_WIDTH, 2f); //out.println(z + " " + c); - return new RenderInstruction[] { + return new RenderStyle[] { new Line(100 + z, color(c), width) }; @@ -263,4 +257,10 @@ public class RenderTheme implements IRenderTheme { t.matchElement(GeometryType.POLY, e.tags, 15); } + @Override + public void updateInstructions() { + // TODO Auto-generated method stub + + } + } diff --git a/vtm-jeo/src/org/oscim/theme/carto/RuleDebug.java b/vtm-jeo/src/org/oscim/theme/carto/RuleDebug.java deleted file mode 100644 index ebc92865..00000000 --- a/vtm-jeo/src/org/oscim/theme/carto/RuleDebug.java +++ /dev/null @@ -1,74 +0,0 @@ -package org.oscim.theme.carto; - -import static java.lang.System.out; - -import java.util.Map; - -import org.jeo.filter.Filter; -import org.jeo.map.Rule; -import org.jeo.map.Selector; - -public class RuleDebug { - - static void printRule(Rule r, int level) { - - out.println("> " + level + " >"); - out.println(formatRule(r, level)); - } - - public static String formatRule(Rule r, int indent) { - StringBuilder sb = new StringBuilder(); - String pad = ""; - for (int i = 0; i < indent; i++) { - pad += " "; - }; - - sb.append(pad); - for (Selector s : r.getSelectors()) { - sb.append(formatSelector(s)); - sb.append(","); - } - if (sb.length() > 0) { - sb.setLength(sb.length() - 1); - } - sb.append(pad).append(" {").append("\n"); - - for (Map.Entry e : r.properties().entrySet()) { - sb.append(pad).append(" ").append(e.getKey()).append(": ").append(e.getValue()) - .append(";\n"); - } - - for (Rule nested : r.nested()) { - sb.append(nested.toString(indent + 2)).append("\n"); - } - - sb.append(pad).append("}"); - return sb.toString(); - } - - public static String formatSelector(Selector s) { - StringBuffer sb = new StringBuffer(); - - if (s.getName() != null) { - sb.append(s.getName()); - } - if (s.getId() != null) { - sb.append("#").append(s.getId()); - } - for (String c : s.getClasses()) { - sb.append(".").append(c); - } - if (s.getFilter() != null && s.getFilter() != Filter.TRUE) { - sb.append("[").append(s.getFilter()).append("]"); - } - if (s.getAttachment() != null) { - sb.append("::").append(s.getAttachment()); - } - - if (s.isWildcard()) { - sb.append("*"); - } - - return sb.toString(); - } -}