add examples

This commit is contained in:
Hannes Janetzek 2014-01-21 18:21:15 +01:00
parent 9109da9784
commit 3fd92982c4
18 changed files with 956 additions and 520 deletions

View File

@ -0,0 +1,30 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="org.oscim.jeo.android"
android:versionCode="1"
android:versionName="1.0" >
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-sdk
android:minSdkVersion="10"
android:targetSdkVersion="18" />
<application
android:label="JeoMap"
android:icon="@drawable/ic_launcher"
android:allowBackup="true"
android:theme="@android:style/Theme.NoTitleBar.Fullscreen" >
<activity
android:name=".TestActivity"
android:label="JeoMap" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>

View File

@ -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

Binary file not shown.

After

Width:  |  Height:  |  Size: 41 KiB

View File

@ -0,0 +1,93 @@
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<org.oscim.android.MapView
android:id="@+id/mapView"
android:layout_width="fill_parent"
android:layout_height="fill_parent" >
</org.oscim.android.MapView>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:alpha="0.7"
android:gravity="center"
android:orientation="vertical" >
<ToggleButton
android:id="@+id/level7"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="onClick"
android:textOff="7"
android:textOn="7" />
<ToggleButton
android:id="@+id/level6"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="onClick"
android:textOff="6"
android:textOn="6" />
<ToggleButton
android:id="@+id/level5"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="onClick"
android:textOff="5"
android:textOn="5" />
<ToggleButton
android:id="@+id/level4"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="onClick"
android:textOff="4"
android:textOn="4" />
<ToggleButton
android:id="@+id/level3"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="onClick"
android:textOff="3"
android:textOn="3" />
<ToggleButton
android:id="@+id/level2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="onClick"
android:textOff="2"
android:textOn="2" />
<ToggleButton
android:id="@+id/level1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="onClick"
android:textOff="1"
android:textOn="1" />
<ToggleButton
android:id="@+id/level0"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="onClick"
android:textOff="0"
android:textOn="0" />
<ToggleButton
android:id="@+id/level_u1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="onClick"
android:textOff="-1"
android:textOn="-1" />
</LinearLayout>
</RelativeLayout>

View File

@ -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();
}
}

View File

@ -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);
}
}

View File

@ -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));
}
}

View File

@ -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();
}
}

View File

@ -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();
}
}

View File

@ -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;
}
}

View File

@ -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;
}
};
}
}

View File

@ -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();
}
}

View File

@ -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) {
}
}

View File

@ -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<Geometry> {
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);
}
}

View File

@ -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<String, Object> tags = (HashMap<String, Object>) o;
@SuppressWarnings("unchecked")
HashMap<String, Object> reltags = (HashMap<String, Object>) 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;
}
}

View File

@ -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;
}

View File

@ -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<Rule, StyleSet> mStyleSets = new HashMap<Rule, StyleSet>();
@ -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
}
}

View File

@ -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<String, Object> 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();
}
}