This commit is contained in:
Hannes Janetzek
2013-06-24 01:50:37 +02:00
parent 36de337e25
commit 83cd73156a
454 changed files with 30032 additions and 348 deletions

10
vtm-extras/.classpath Normal file
View File

@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="src" path="src"/>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.6"/>
<classpathentry kind="lib" path="libs/jackson-core-2.1.4.jar"/>
<classpathentry kind="lib" path="libs/osmosis-osm-binary-0.43.jar"/>
<classpathentry kind="lib" path="libs/protobuf-java-2.4.1.jar"/>
<classpathentry combineaccessrules="false" kind="src" path="/vtm"/>
<classpathentry kind="output" path="bin"/>
</classpath>

17
vtm-extras/.project Normal file
View File

@@ -0,0 +1,17 @@
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>vtm-extras</name>
<comment></comment>
<projects>
</projects>
<buildSpec>
<buildCommand>
<name>org.eclipse.jdt.core.javabuilder</name>
<arguments>
</arguments>
</buildCommand>
</buildSpec>
<natures>
<nature>org.eclipse.jdt.core.javanature</nature>
</natures>
</projectDescription>

View File

@@ -0,0 +1,11 @@
eclipse.preferences.version=1
org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6
org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
org.eclipse.jdt.core.compiler.compliance=1.6
org.eclipse.jdt.core.compiler.debug.lineNumber=generate
org.eclipse.jdt.core.compiler.debug.localVariable=generate
org.eclipse.jdt.core.compiler.debug.sourceFile=generate
org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
org.eclipse.jdt.core.compiler.source=1.6

View File

@@ -0,0 +1,366 @@
package org.oscim.utils;
import java.util.ArrayList;
/**
* Triangulates a polygon into triangles - duh. Doesn't handle
* holes in polys
*
* @author Public Source from FlipCode
*/
public class Triangulator {
/** The accepted error value */
private static final float EPSILON = 0.0000000001f;
/** The list of points to be triangulated */
private final PointList poly = new PointList();
/** The list of points describing the triangles */
private final PointList tris = new PointList();
/** True if we've tried to triangulate */
private boolean tried;
/**
* Create a new triangulator
*/
public Triangulator() {
}
/**
* Add a point describing the polygon to be triangulated
*
* @param x The x coordinate of the point
* @param y the y coordinate of the point
*/
public void addPolyPoint(float x, float y) {
poly.add(new Point(x, y));
}
/**
* Cause the triangulator to split the polygon
*
* @return True if we managed the task
*/
public boolean triangulate() {
tried = true;
boolean worked = process(poly, tris);
return worked;
}
/**
* Get a count of the number of triangles produced
*
* @return The number of triangles produced
*/
public int getTriangleCount() {
if (!tried) {
throw new RuntimeException("Call triangulate() before accessing triangles");
}
return tris.size() / 3;
}
/**
* Get a point on a specified generated triangle
*
* @param tri The index of the triangle to interegate
* @param i The index of the point within the triangle to retrieve
* (0 - 2)
* @return The x,y coordinate pair for the point
*/
public float[] getTrianglePoint(int tri, int i) {
if (!tried) {
throw new RuntimeException("Call triangulate() before accessing triangles");
}
return tris.get((tri * 3) + i).toArray();
}
/**
* Find the area of a polygon defined by the series of points
* in the list
*
* @param contour The list of points defined the contour of the polygon
* (Vector2f)
* @return The area of the polygon defined
*/
private static float area(PointList contour) {
int n = contour.size();
float A = 0.0f;
for (int p = n - 1, q = 0; q < n; p = q++) {
Point contourP = contour.get(p);
Point contourQ = contour.get(q);
A += contourP.getX() * contourQ.getY() - contourQ.getX()
* contourP.getY();
}
return A * 0.5f;
}
/**
* Check if the point P is inside the triangle defined by
* the points A,B,C
*
* @param Ax Point A x-coordinate
* @param Ay Point A y-coordinate
* @param Bx Point B x-coordinate
* @param By Point B y-coordinate
* @param Cx Point C x-coordinate
* @param Cy Point C y-coordinate
* @param Px Point P x-coordinate
* @param Py Point P y-coordinate
* @return True if the point specified is within the triangle
*/
private static boolean insideTriangle(float Ax, float Ay, float Bx,
float By, float Cx, float Cy, float Px, float Py) {
float ax, ay, bx, by, cx, cy, apx, apy, bpx, bpy, cpx, cpy;
float cCROSSap, bCROSScp, aCROSSbp;
ax = Cx - Bx;
ay = Cy - By;
bx = Ax - Cx;
by = Ay - Cy;
cx = Bx - Ax;
cy = By - Ay;
apx = Px - Ax;
apy = Py - Ay;
bpx = Px - Bx;
bpy = Py - By;
cpx = Px - Cx;
cpy = Py - Cy;
aCROSSbp = ax * bpy - ay * bpx;
cCROSSap = cx * apy - cy * apx;
bCROSScp = bx * cpy - by * cpx;
return ((aCROSSbp >= 0.0f) && (bCROSScp >= 0.0f) && (cCROSSap >= 0.0f));
}
/**
* Cut a the contour and add a triangle into V to describe the
* location of the cut
*
* @param contour The list of points defining the polygon
* @param u The index of the first point
* @param v The index of the second point
* @param w The index of the third point
* @param n ?
* @param V The array to populate with indicies of triangles
* @return True if a triangle was found
*/
private static boolean snip(PointList contour, int u, int v, int w, int n,
int[] V) {
int p;
float Ax, Ay, Bx, By, Cx, Cy, Px, Py;
Ax = contour.get(V[u]).getX();
Ay = contour.get(V[u]).getY();
Bx = contour.get(V[v]).getX();
By = contour.get(V[v]).getY();
Cx = contour.get(V[w]).getX();
Cy = contour.get(V[w]).getY();
if (EPSILON > (((Bx - Ax) * (Cy - Ay)) - ((By - Ay) * (Cx - Ax)))) {
return false;
}
for (p = 0; p < n; p++) {
if ((p == u) || (p == v) || (p == w)) {
continue;
}
Px = contour.get(V[p]).getX();
Py = contour.get(V[p]).getY();
if (insideTriangle(Ax, Ay, Bx, By, Cx, Cy, Px, Py)) {
return false;
}
}
return true;
}
/**
* Process a list of points defining a polygon
*
* @param contour The list of points describing the polygon
* @param result The list of points describing the triangles. Groups
* of 3 describe each triangle
* @return True if we succeeded in completing triangulation
*/
private static boolean process(PointList contour, PointList result) {
/* allocate and initialize list of Vertices in polygon */
int n = contour.size();
if (n < 3)
return false;
int[] V = new int[n];
/* we want a counter-clockwise polygon in V */
if (0.0f < area(contour)) {
for (int v = 0; v < n; v++)
V[v] = v;
} else {
for (int v = 0; v < n; v++)
V[v] = (n - 1) - v;
}
int nv = n;
/* remove nv-2 Vertices, creating 1 triangle every time */
int count = 2 * nv; /* error detection */
//for (int m = 0, v = nv - 1; nv > 2;) {
for (int v = nv - 1; nv > 2;) {
/* if we loop, it is probably a non-simple polygon */
if (0 >= (count--)) {
//** Triangulate: ERROR - probable bad polygon!
return false;
}
/* three consecutive vertices in current polygon, <u,v,w> */
int u = v;
if (nv <= u)
u = 0; /* previous */
v = u + 1;
if (nv <= v)
v = 0; /* new v */
int w = v + 1;
if (nv <= w)
w = 0; /* next */
if (snip(contour, u, v, w, nv, V)) {
int a, b, c, s, t;
/* true names of the vertices */
a = V[u];
b = V[v];
c = V[w];
/* output Triangle */
result.add(contour.get(a));
result.add(contour.get(b));
result.add(contour.get(c));
//m++;
/* remove v from remaining polygon */
for (s = v, t = v + 1; t < nv; s++, t++) {
V[s] = V[t];
}
nv--;
/* resest error detection counter */
count = 2 * nv;
}
}
return true;
}
/**
* A single point handled by the triangulator
*
* @author Kevin Glass
*/
private class Point {
/** The x coorindate of this point */
private final float x;
/** The y coorindate of this point */
private final float y;
/**
* Create a new point
*
* @param x The x coordindate of the point
* @param y The y coordindate of the point
*/
public Point(float x, float y) {
this.x = x;
this.y = y;
}
/**
* Get the x coordinate of the point
*
* @return The x coordinate of the point
*/
public float getX() {
return x;
}
/**
* Get the y coordinate of the point
*
* @return The y coordinate of the point
*/
public float getY() {
return y;
}
/**
* Convert this point into a float array
*
* @return The contents of this point as a float array
*/
public float[] toArray() {
return new float[] { x, y };
}
}
/**
* A list of type <code>Point</code>
*
* @author Kevin Glass
*/
private class PointList {
/** The list of points */
private final ArrayList<Point> points = new ArrayList<Point>();
/**
* Create a new empty list
*/
public PointList() {
}
/**
* Add a point to the list
*
* @param point The point to add
*/
public void add(Point point) {
points.add(point);
}
///**
// * Remove a point from the list
// *
// * @param point The point to remove
// */
//public void remove(Point point) {
// points.remove(point);
//}
/**
* Get the size of the list
*
* @return The size of the list
*/
public int size() {
return points.size();
}
/**
* Get a point a specific index in the list
*
* @param i The index of the point to retrieve
* @return The point
*/
public Point get(int i) {
return points.get(i);
}
}
}

View File

@@ -0,0 +1,19 @@
/*
* Copyright 2013 Hannes Janetzek
*
* This program is free software: you can redistribute it and/or modify it under the
* terms of the GNU Lesser General Public License as published by the Free Software
* Foundation, either version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
* PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License along with
* this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.oscim.utils.osm;
public class Bound {
}

View File

@@ -0,0 +1,55 @@
/*
* Copyright 2013 Tobias Knerr
*
* This program is free software: you can redistribute it and/or modify it under the
* terms of the GNU Lesser General Public License as published by the Free Software
* Foundation, either version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
* PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License along with
* this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.oscim.utils.osm;
import java.util.Collection;
/**
* OSM dataset containing nodes, areas and relations
*/
public class OSMData {
private final Collection<Bound> bounds;
private final Collection<OSMNode> nodes;
private final Collection<OSMWay> ways;
private final Collection<OSMRelation> relations;
public OSMData(Collection<Bound> bounds, Collection<OSMNode> nodes,
Collection<OSMWay> ways, Collection<OSMRelation> relations) {
this.bounds = bounds;
this.nodes = nodes;
this.ways = ways;
this.relations = relations;
}
public Collection<OSMNode> getNodes() {
return nodes;
}
public Collection<OSMWay> getWays() {
return ways;
}
public Collection<OSMRelation> getRelations() {
return relations;
}
public Collection<Bound> getBounds() {
return bounds;
}
}

View File

@@ -0,0 +1,60 @@
/*
* Copyright 2013 Tobias Knerr
*
* This program is free software: you can redistribute it and/or modify it under the
* terms of the GNU Lesser General Public License as published by the Free Software
* Foundation, either version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
* PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License along with
* this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.oscim.utils.osm;
import org.oscim.core.TagSet;
public abstract class OSMElement {
public final TagSet tags;
public final long id;
public OSMElement(TagSet tags, long id) {
assert tags != null;
this.tags = tags;
this.id = id;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + (int) (id ^ (id >>> 32));
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
OSMElement other = (OSMElement) obj;
if (id != other.id)
return false;
return true;
}
/**
* returns the id, plus an one-letter prefix for the element type
*/
@Override
public String toString() {
return "?" + id;
}
}

View File

@@ -0,0 +1,39 @@
/*
* Copyright 2013 Tobias Knerr
*
* This program is free software: you can redistribute it and/or modify it under the
* terms of the GNU Lesser General Public License as published by the Free Software
* Foundation, either version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
* PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License along with
* this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.oscim.utils.osm;
public class OSMMember {
public enum MemberType{
NODE,
WAY,
RELATIOM
}
static final boolean useDebugLabels = true;
public final String role;
public final OSMElement member;
public OSMMember(String role, OSMElement member) {
assert role != null && member != null;
this.role = role;
this.member = member;
}
@Override
public String toString() {
return role + ":" + member;
}
}

View File

@@ -0,0 +1,36 @@
/*
* Copyright 2013 Tobias Knerr
*
* This program is free software: you can redistribute it and/or modify it under the
* terms of the GNU Lesser General Public License as published by the Free Software
* Foundation, either version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
* PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License along with
* this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.oscim.utils.osm;
import org.oscim.core.TagSet;
public class OSMNode extends OSMElement {
//public static EMPTY_NODE = new OSMNode()
public final double lat;
public final double lon;
public OSMNode(double lat, double lon, TagSet tags, long id) {
super(tags, id);
this.lat = lat;
this.lon = lon;
}
@Override
public String toString() {
return "n" + id;
}
}

View File

@@ -0,0 +1,39 @@
/*
* Copyright 2013 Tobias Knerr
*
* This program is free software: you can redistribute it and/or modify it under the
* terms of the GNU Lesser General Public License as published by the Free Software
* Foundation, either version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
* PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License along with
* this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.oscim.utils.osm;
import java.util.ArrayList;
import java.util.List;
import org.oscim.core.TagSet;
public class OSMRelation extends OSMElement {
public final List<OSMMember> relationMembers;
// content added after constructor call
public OSMRelation(TagSet tags, long id, int initialMemberSize) {
super(tags, id);
this.relationMembers =
new ArrayList<OSMMember>(initialMemberSize);
}
@Override
public String toString() {
return "r" + id;
}
}

View File

@@ -0,0 +1,40 @@
/*
* Copyright 2013 Tobias Knerr
*
* This program is free software: you can redistribute it and/or modify it under the
* terms of the GNU Lesser General Public License as published by the Free Software
* Foundation, either version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
* PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License along with
* this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.oscim.utils.osm;
import java.util.List;
import org.oscim.core.TagSet;
public class OSMWay extends OSMElement {
public final List<OSMNode> nodes;
public OSMWay(TagSet tags, long id, List<OSMNode> nodes) {
super(tags, id);
this.nodes = nodes;
}
public boolean isClosed() {
return nodes.size() > 0 &&
nodes.get(0).equals(nodes.get(nodes.size() - 1));
}
@Override
public String toString() {
return "w" + id;
}
}

View File

@@ -0,0 +1,323 @@
// This software is released into the Public Domain. See copying.txt for details.
package org.oscim.utils.osmpbf;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import org.openstreetmap.osmosis.osmbinary.BinaryParser;
import org.openstreetmap.osmosis.osmbinary.Osmformat;
import org.oscim.backend.Log;
import org.oscim.core.Tag;
import org.oscim.core.TagSet;
import org.oscim.utils.osm.OSMData;
import org.oscim.utils.osm.OSMMember;
import org.oscim.utils.osm.OSMNode;
import org.oscim.utils.osm.OSMRelation;
import org.oscim.utils.osm.OSMWay;
/**
* Class that reads and parses binary files and sends the contained entities to
* the sink.
*/
public class OsmPbfParser extends BinaryParser {
@Override
public void complete() {
//sink.complete();
}
// /** Get the osmosis object representing a the user in a given Info protobuf.
// * @param info The info protobuf.
// * @return The OsmUser object */
// OsmUser getUser(Osmformat.Info info) {
// // System.out.println(info);
// if (info.hasUid() && info.hasUserSid()) {
// if (info.getUid() < 0) {
// return OsmUser.NONE;
// }
// return new OsmUser(info.getUid(), getStringById(info.getUserSid()));
// } else {
// return OsmUser.NONE;
// }
// }
/**
* The magic number used to indicate no version number metadata for this
* entity.
*/
static final int NOVERSION = -1;
/** The magic number used to indicate no changeset metadata for this entity. */
static final int NOCHANGESET = -1;
HashMap<Long, OSMNode> mNodeMap = new HashMap<Long, OSMNode>();
HashMap<Long, OSMWay> mWayMap = new HashMap<Long, OSMWay>();
@Override
protected void parseNodes(List<Osmformat.Node> nodes) {
for (Osmformat.Node i : nodes) {
int tagCnt = i.getKeysCount();
TagSet tags = new TagSet(tagCnt);
// List<Tag> tags = new ArrayList<Tag>();
for (int j = 0; j < tagCnt; j++) {
tags.add(new Tag(getStringById(i.getKeys(j)), getStringById(i.getVals(j))));
}
// long id, int version, Date timestamp, OsmUser user,
// long changesetId, Collection<Tag> tags,
// double latitude, double longitude
OSMNode tmp;
long id = i.getId();
double latf = parseLat(i.getLat()), lonf = parseLon(i.getLon());
// if (i.hasInfo()) {
// Osmformat.Info info = i.getInfo();
// tmp = new OSMNode(new CommonEntityData(id, info.getVersion(), getDate(info),
// getUser(info), info.getChangeset(), tags), latf, lonf);
// } else {
tmp = new OSMNode(latf, lonf, tags, id);
// tmp = new Node(new CommonEntityData(id, NOVERSION, NODATE, OsmUser.NONE,
// NOCHANGESET, tags), latf, lonf);
// }
//sink.process(new NodeContainer(tmp));
mNodeMap.put(Long.valueOf(id), tmp);
}
}
@Override
protected void parseDense(Osmformat.DenseNodes nodes) {
long lastId = 0, lastLat = 0, lastLon = 0;
int j = 0; // Index into the keysvals array.
// Stuff for dense info
// long lasttimestamp = 0, lastchangeset = 0;
// int lastuserSid = 0, lastuid = 0;
// DenseInfo di = null;
// if (nodes.hasDenseinfo()) {
// di = nodes.getDenseinfo();
// }
for (int i = 0; i < nodes.getIdCount(); i++) {
OSMNode tmp;
TagSet tags = new TagSet(4);
long lat = nodes.getLat(i) + lastLat;
lastLat = lat;
long lon = nodes.getLon(i) + lastLon;
lastLon = lon;
long id = nodes.getId(i) + lastId;
lastId = id;
double latf = parseLat(lat), lonf = parseLon(lon);
// If empty, assume that nothing here has keys or vals.
if (nodes.getKeysValsCount() > 0) {
while (nodes.getKeysVals(j) != 0) {
int keyid = nodes.getKeysVals(j++);
int valid = nodes.getKeysVals(j++);
tags.add(new Tag(getStringById(keyid), getStringById(valid)));
}
j++; // Skip over the '0' delimiter.
}
// Handle dense info.
// if (di != null) {
// int uid = di.getUid(i) + lastuid; lastuid = uid;
// int userSid = di.getUserSid(i) + lastuserSid; lastuserSid = userSid;
// long timestamp = di.getTimestamp(i) + lasttimestamp; lasttimestamp = timestamp;
// int version = di.getVersion(i);
// long changeset = di.getChangeset(i) + lastchangeset; lastchangeset = changeset;
//
// Date date = new Date(date_granularity * timestamp);
//OsmUser user;
// if (uid < 0) {
// user = OsmUser.NONE;
// } else {
// user = new OsmUser(uid, getStringById(userSid));
// }
//
// tmp = new OSMNode(id, tags, latf, lonf);
// } else {
tmp = new OSMNode(latf, lonf, tags, id);
mNodeMap.put(Long.valueOf(id), tmp);
// }
//sink.process(new NodeContainer(tmp));
}
}
@Override
protected void parseWays(List<Osmformat.Way> ways) {
for (Osmformat.Way i : ways) {
int tagCnt = i.getKeysCount();
TagSet tags = new TagSet(tagCnt);
// List<Tag> tags = new ArrayList<Tag>();
for (int j = 0; j < tagCnt; j++) {
tags.add(new Tag(getStringById(i.getKeys(j)), getStringById(i.getVals(j))));
}
// List<Tag> tags = new ArrayList<Tag>();
// for (int j = 0; j < ; j++) {
// tags.add(new Tag(getStringById(i.getKeys(j)), getStringById(i.getVals(j))));
// }
long lastId = 0;
List<OSMNode> nodes = new ArrayList<OSMNode>();
for (long j : i.getRefsList()) {
OSMNode n = mNodeMap.get(Long.valueOf(j + lastId));
if (n == null)
n = new OSMNode(Double.NaN, Double.NaN, null, j + lastId);
nodes.add(n);
lastId = j + lastId;
}
long id = i.getId();
// long id, int version, Date timestamp, OsmUser user,
// long changesetId, Collection<Tag> tags,
// List<WayNode> wayNodes
OSMWay tmp;
// if (i.hasInfo()) {
// Osmformat.Info info = i.getInfo();
// tmp = new Way(new CommonEntityData(id, info.getVersion(), getDate(info),
// getUser(info), info.getChangeset(), tags), nodes);
// } else {
tmp = new OSMWay(tags, id, nodes);
// }
mWayMap.put(Long.valueOf(id), tmp);
//sink.process(new WayContainer(tmp));
}
}
@Override
protected void parseRelations(List<Osmformat.Relation> rels) {
for (Osmformat.Relation i : rels) {
int tagCnt = i.getKeysCount();
TagSet tags = new TagSet(tagCnt);
for (int j = 0; j < tagCnt; j++)
tags.add(new Tag(getStringById(i.getKeys(j)), getStringById(i.getVals(j))));
long id = i.getId();
long lastMid = 0;
List<OSMMember> nodes = new ArrayList<OSMMember>();
int memberCnt = i.getMemidsCount();
// for (int j = 0; j < memberCnt; j++) {
// long mid = lastMid + i.getMemids(j);
// lastMid = mid;
// String role = getStringById(i.getRolesSid(j));
//
// Osmformat.Relation.MemberType t = i.getTypes(j);
//
// if (t == Osmformat.Relation.MemberType.NODE) {
// etype = EntityType.Node;
// } else if (t == Osmformat.Relation.MemberType.WAY) {
// etype = EntityType.Way;
// } else if (t == Osmformat.Relation.MemberType.RELATION) {
// etype = EntityType.Relation;
// } else {
// assert false; // TODO; Illegal file?
// }
//
// nodes.add(new OSMMember(mid, etype, role));
// }
// long id, int version, TimestampContainer timestampContainer,
// OsmUser user,
// long changesetId, Collection<Tag> tags,
// List<RelationMember> members
OSMRelation tmp = new OSMRelation(tags, id, memberCnt);
// if (i.hasInfo()) {
// Osmformat.Info info = i.getInfo();
// tmp = new Relation(new CommonEntityData(id, info.getVersion(), getDate(info),
// getUser(info), info.getChangeset(), tags), nodes);
// } else {
// tmp = new Relation(new CommonEntityData(id, NOVERSION, NODATE, OsmUser.NONE,
// NOCHANGESET, tags), nodes);
// }
// sink.process(new RelationContainer(tmp));
}
}
@Override
public void parse(Osmformat.HeaderBlock block) {
for (String s : block.getRequiredFeaturesList()) {
if (s.equals("OsmSchema-V0.6")) {
continue; // We can parse this.
}
if (s.equals("DenseNodes")) {
continue; // We can parse this.
}
throw new RuntimeException("File requires unknown feature: " + s);
}
// if (block.hasBbox()) {
// String source = OsmosisConstants.VERSION;
// if (block.hasSource()) {
// source = block.getSource();
// }
//
// double multiplier = .000000001;
// double rightf = block.getBbox().getRight() * multiplier;
// double leftf = block.getBbox().getLeft() * multiplier;
// double topf = block.getBbox().getTop() * multiplier;
// double bottomf = block.getBbox().getBottom() * multiplier;
//
// Bound bounds = new Bound(rightf, leftf, topf, bottomf, source);
// sink.process(new BoundContainer(bounds));
// }
}
public OSMData getData() {
// for (Entry<OSMRelation, List<TmpRelation>> entry : relationMembersForRelation
// .entrySet()) {
//
// OSMRelation relation = entry.getKey();
//
// for (TmpRelation member : entry.getValue()) {
//
// OSMElement memberObject = null;
//
// if ("node".equals(member)) {
// memberObject = nodesById.get(member.id);
// } else if ("way".equals(member)) {
// memberObject = waysById.get(member.id);
// } else if ("relation".equals(member)) {
// memberObject = relationsById.get(member.id);
// } else {
// // log("missing relation " + member.id);
// continue;
// }
//
// if (memberObject != null) {
// OSMMember ownMember = new OSMMember(member.role,
// memberObject);
//
// relation.relationMembers.add(ownMember);
// }
// }
// }
// give up references to original collections
ArrayList<OSMWay> ways = new ArrayList<OSMWay> (mWayMap.values());
ArrayList<OSMNode> nodes= new ArrayList<OSMNode> (mNodeMap.values());
Log.d("..", "nodes: " + nodes.size() + " ways: " + ways.size());
return new OSMData(null, nodes, ways, null);
}
}

View File

@@ -0,0 +1,38 @@
/*
* Copyright 2013
*
* This program is free software: you can redistribute it and/or modify it under the
* terms of the GNU Lesser General Public License as published by the Free Software
* Foundation, either version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
* PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License along with
* this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.oscim.utils.osmpbf;
import java.io.IOException;
import java.io.InputStream;
import org.openstreetmap.osmosis.osmbinary.file.BlockInputStream;
import org.oscim.utils.osm.OSMData;
public class OsmPbfReader {
public static OSMData process(InputStream is){
OsmPbfParser parser = new OsmPbfParser();
try {
(new BlockInputStream(is, parser)).process();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
return null;
}
return parser.getData();
}
}

View File

@@ -0,0 +1,415 @@
/*
* Copyright 2013 Hannes Janetzek
*
* This program is free software: you can redistribute it and/or modify it under the
* terms of the GNU Lesser General Public License as published by the Free Software
* Foundation, either version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
* PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License along with
* this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.oscim.utils.overpass;
import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.zip.GZIPInputStream;
import java.util.zip.Inflater;
import java.util.zip.InflaterInputStream;
import org.oscim.core.Tag;
import org.oscim.core.TagSet;
import org.oscim.utils.osm.Bound;
import org.oscim.utils.osm.OSMData;
import org.oscim.utils.osm.OSMElement;
import org.oscim.utils.osm.OSMMember;
import org.oscim.utils.osm.OSMNode;
import org.oscim.utils.osm.OSMRelation;
import org.oscim.utils.osm.OSMWay;
import com.fasterxml.jackson.core.JsonFactory;
import com.fasterxml.jackson.core.JsonParseException;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonToken;
public class OverpassAPIReader {
private static final String OVERPASS_API = "http://city.informatik.uni-bremen.de/oapi/interpreter";
private static final int RESPONSECODE_OK = 200;
/**
* The timeout we use for the HttpURLConnection.
*/
private static final int TIMEOUT = 15000;
/**
* The base url of the server. Defaults to.
* "http://www.openstreetmap.org/api/0.5".
*/
private final String myBaseUrl = OVERPASS_API;
/**
* The http connection used to retrieve data.
*/
private HttpURLConnection myActiveConnection;
/**
* The stream providing response data.
*/
private InputStream responseStream;
private final String query;
/**
* Creates a new instance with the specified geographical coordinates.
*
* @param left
* The longitude marking the left edge of the bounding box.
* @param right
* The longitude marking the right edge of the bounding box.
* @param top
* The latitude marking the top edge of the bounding box.
* @param bottom
* The latitude marking the bottom edge of the bounding box.
* @param baseUrl
* (optional) The base url of the server (eg.
* http://www.openstreetmap.org/api/0.5).
*/
public OverpassAPIReader(final double left, final double right,
final double top, final double bottom, final String baseUrl,
final String query) {
String bbox = "(" + Math.min(top, bottom) + "," + Math.min(left, right)
+ "," + Math.max(top, bottom) + "," + Math.max(left, right)
+ ")";
this.query = query.replaceAll("\\{\\{bbox\\}\\}", bbox);
}
/**
* Open a connection to the given url and return a reader on the input
* stream from that connection.
*
* @param pUrlStr
* The exact url to connect to.
* @return An reader reading the input stream (servers answer) or
* <code>null</code>.
* @throws IOException
* on io-errors
*/
private InputStream getInputStream(final String pUrlStr) throws IOException {
URL url;
int responseCode;
String encoding;
url = new URL(pUrlStr);
myActiveConnection = (HttpURLConnection) url.openConnection();
myActiveConnection.setRequestProperty("Accept-Encoding",
"gzip, deflate");
responseCode = myActiveConnection.getResponseCode();
if (responseCode != RESPONSECODE_OK) {
String message;
String apiErrorMessage;
apiErrorMessage = myActiveConnection.getHeaderField("Error");
if (apiErrorMessage != null) {
message = "Received API HTTP response code " + responseCode
+ " with message \"" + apiErrorMessage
+ "\" for URL \"" + pUrlStr + "\".";
} else {
message = "Received API HTTP response code " + responseCode
+ " for URL \"" + pUrlStr + "\".";
}
throw new IOException(message);
}
myActiveConnection.setConnectTimeout(TIMEOUT);
encoding = myActiveConnection.getContentEncoding();
responseStream = myActiveConnection.getInputStream();
if (encoding != null && encoding.equalsIgnoreCase("gzip")) {
responseStream = new GZIPInputStream(responseStream);
} else if (encoding != null && encoding.equalsIgnoreCase("deflate")) {
responseStream = new InflaterInputStream(responseStream,
new Inflater(true));
}
return responseStream;
}
class TmpRelation {
Long id;
String type;
String role;
}
private final List<Bound> bounds = new ArrayList<Bound>();
private Map<Long, OSMNode> nodesById = new HashMap<Long, OSMNode>();
private Map<Long, OSMWay> waysById = new HashMap<Long, OSMWay>();
private Map<Long, OSMRelation> relationsById = new HashMap<Long, OSMRelation>();
private Map<OSMRelation, List<TmpRelation>> relationMembersForRelation =
new HashMap<OSMRelation, List<TmpRelation>>();
private final Collection<OSMNode> ownNodes = new ArrayList<OSMNode>(10000);
private final Collection<OSMWay> ownWays = new ArrayList<OSMWay>(1000);
private final Collection<OSMRelation> ownRelations = new ArrayList<OSMRelation>(
100);
public void parse(InputStream in) throws IOException {
JsonFactory jsonFactory = new JsonFactory();
try {
JsonParser jp = jsonFactory.createJsonParser(in);
JsonToken t;
while ((t = jp.nextToken()) != null) {
if (t == JsonToken.START_OBJECT) {
jp.nextToken();
String name = jp.getCurrentName();
jp.nextToken();
if ("type".equals(name)) {
String type = jp.getText();
if ("node".equals(type))
parseNode(jp);
else if ("way".equals(type))
parseWay(jp);
else if ("relation".equals(type))
parseRelation(jp);
}
}
}
} catch (JsonParseException e) {
e.printStackTrace();
}
}
private void parseNode(JsonParser jp) throws JsonParseException,
IOException {
long id = 0;
double lat = 0, lon = 0;
TagSet tags = TagSet.EMPTY_TAG_SET;
while (jp.nextToken() != JsonToken.END_OBJECT) {
String name = jp.getCurrentName();
jp.nextToken();
if ("id".equals(name))
id = jp.getLongValue();
else if ("lat".equals(name))
lat = jp.getDoubleValue();
else if ("lon".equals(name))
lon = jp.getDoubleValue();
else if ("tags".equals(name))
tags = parseTags(jp);
}
// log("node: "+id + " "+ lat + " " + lon);
OSMNode node = new OSMNode(lat, lon, tags, id);
ownNodes.add(node);
nodesById.put(Long.valueOf(id), node);
}
private void parseWay(JsonParser jp) throws JsonParseException, IOException {
long id = 0;
TagSet tags = TagSet.EMPTY_TAG_SET;
ArrayList<OSMNode> wayNodes = new ArrayList<OSMNode>();
while (jp.nextToken() != JsonToken.END_OBJECT) {
String name = jp.getCurrentName();
jp.nextToken();
if ("id".equals(name))
id = jp.getLongValue();
else if ("nodes".equals(name)) {
while (jp.nextToken() != JsonToken.END_ARRAY) {
Long nodeId = Long.valueOf(jp.getLongValue());
OSMNode node = nodesById.get(nodeId);
if (node != null)
// log("missing node " + nodeId);
// else
wayNodes.add(node);
}
} else if ("tags".equals(name))
tags = parseTags(jp);
}
// log("way: "+ id + " " + wayNodes.size());
OSMWay way = new OSMWay(tags, id, wayNodes);
ownWays.add(way);
waysById.put(Long.valueOf(id), way);
}
private void parseRelation(JsonParser jp) throws JsonParseException,
IOException {
long id = 0;
TagSet tags = TagSet.EMPTY_TAG_SET;
ArrayList<TmpRelation> members = new ArrayList<TmpRelation>();
while (jp.nextToken() != JsonToken.END_OBJECT) {
String name = jp.getCurrentName();
jp.nextToken();
if ("id".equals(name))
id = jp.getLongValue();
else if ("members".equals(name)) {
while (jp.nextToken() != JsonToken.END_ARRAY) {
TmpRelation member = new TmpRelation();
while (jp.nextToken() != JsonToken.END_OBJECT) {
name = jp.getCurrentName();
jp.nextToken();
if ("type".equals(name))
member.type = jp.getText();
else if ("ref".equals(name))
member.id = Long.valueOf(jp.getLongValue());
else if ("role".equals(name))
member.role = jp.getText();
}
members.add(member);
}
} else if ("tags".equals(name))
tags = parseTags(jp);
}
OSMRelation relation = new OSMRelation(tags, id, members.size());
ownRelations.add(relation);
relationsById.put(Long.valueOf(id), relation);
relationMembersForRelation.put(relation, members);
}
private static TagSet parseTags(JsonParser jp) throws JsonParseException,
IOException {
TagSet tags = null;
while (jp.nextToken() != JsonToken.END_OBJECT) {
String key = jp.getCurrentName();
jp.nextToken();
String val = jp.getText();
if (tags== null)
tags= new TagSet(4);
tags.add(new Tag(key, val, false));
}
if (tags== null)
return TagSet.EMPTY_TAG_SET;
return tags;
}
private static void log(String msg) {
System.out.println(msg);
}
public OSMData getData() {
String encoded;
try {
encoded = URLEncoder.encode(this.query, "utf-8");
} catch (UnsupportedEncodingException e1) {
e1.printStackTrace();
return null;
}
System.out.println(myBaseUrl + "?data=" + encoded);
InputStream inputStream = null;
try {
inputStream = getInputStream(myBaseUrl + "?data=[out:json];" + encoded);
parse(inputStream);
} catch (IOException e) {
e.printStackTrace();
} finally {
if (inputStream != null)
try {
inputStream.close();
} catch (IOException e) {
//...
}
inputStream = null;
}
for (Entry<OSMRelation, List<TmpRelation>> entry : relationMembersForRelation
.entrySet()) {
OSMRelation relation = entry.getKey();
for (TmpRelation member : entry.getValue()) {
OSMElement memberObject = null;
if ("node".equals(member)) {
memberObject = nodesById.get(member.id);
} else if ("way".equals(member)) {
memberObject = waysById.get(member.id);
} else if ("relation".equals(member)) {
memberObject = relationsById.get(member.id);
} else {
// log("missing relation " + member.id);
continue;
}
if (memberObject != null) {
OSMMember ownMember = new OSMMember(member.role,
memberObject);
relation.relationMembers.add(ownMember);
}
}
}
log("nodes: " + ownNodes.size() + " ways: " + ownWays.size()
+ " relations: " + ownRelations.size());
// give up references to original collections
nodesById = null;
waysById = null;
relationsById = null;
relationMembersForRelation = null;
return new OSMData(bounds, ownNodes, ownWays, ownRelations);
}
}

View File

@@ -0,0 +1,384 @@
/*
* Geometry.java
*
* PostGIS extension for PostgreSQL JDBC driver - geometry model
*
* (C) 2004 Paul Ramsey, pramsey@refractions.net
*
* (C) 2005 Markus Schaber, markus.schaber@logix-tt.com
*
* This library is free software; you can redistribute it and/or modify it under
* the terms of the GNU Lesser General License as published by the Free
* Software Foundation, either version 2.1 of the License.
*
* This library is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU Lesser General License for more
* details.
*
* You should have received a copy of the GNU Lesser General License
* along with this library; if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA or visit the web at
* http://www.gnu.org.
*
* $Id: Geometry.java 9324 2012-02-27 22:08:12Z pramsey $
*/
package org.oscim.utils.wkb;
import java.io.Serializable;
/** The base class of all geometries */
abstract class Geometry implements Serializable {
/* JDK 1.5 Serialization */
private static final long serialVersionUID = 0x100;
// OpenGIS Geometry types as defined in the OGC WKB Spec
// (May we replace this with an ENUM as soon as JDK 1.5
// has gained widespread usage?)
/** Fake type for linear ring */
static final int LINEARRING = 0;
/**
* The OGIS geometry type number for points.
*/
static final int POINT = 1;
/**
* The OGIS geometry type number for lines.
*/
static final int LINESTRING = 2;
/**
* The OGIS geometry type number for polygons.
*/
static final int POLYGON = 3;
/**
* The OGIS geometry type number for aggregate points.
*/
static final int MULTIPOINT = 4;
/**
* The OGIS geometry type number for aggregate lines.
*/
static final int MULTILINESTRING = 5;
/**
* The OGIS geometry type number for aggregate polygons.
*/
static final int MULTIPOLYGON = 6;
/**
* The OGIS geometry type number for feature collections.
*/
static final int GEOMETRYCOLLECTION = 7;
static final String[] ALLTYPES = new String[] {
"", // internally used LinearRing does not have any text in front of
// it
"POINT", "LINESTRING", "POLYGON", "MULTIPOINT", "MULTILINESTRING",
"MULTIPOLYGON", "GEOMETRYCOLLECTION" };
/**
* The Text representations of the geometry types
*
* @param type
* ...
* @return ...
*/
static String getTypeString(int type) {
if (type >= 0 && type <= 7)
return ALLTYPES[type];
throw new IllegalArgumentException("Unknown Geometry type" + type);
}
// Properties common to all geometries
/**
* The dimensionality of this feature (2,3)
*/
int dimension;
/**
* Do we have a measure (4th dimension)
*/
boolean haveMeasure = false;
/**
* The OGIS geometry type of this feature. this is final as it never
* changes, it is bound to the subclass of the
* instance.
*/
final int type;
/**
* Official UNKNOWN srid value
*/
final static int UNKNOWN_SRID = 0;
/**
* The spacial reference system id of this geometry, default is no srid
*/
int srid = UNKNOWN_SRID;
/**
* Parse a SRID value, anything <= 0 is unknown
*
* @param srid
* ...
* @return ...
*/
static int parseSRID(int srid) {
if (srid < 0) {
/* TODO: raise a warning ? */
return 0;
}
return srid;
}
/**
* Constructor for subclasses
*
* @param type
* has to be given by all subclasses.
*/
protected Geometry(int type) {
this.type = type;
}
/**
* java.lang.Object hashCode implementation
*/
@Override
public int hashCode() {
return dimension | (type * 4) | (srid * 32);
}
/**
* java.lang.Object equals implementation
*/
@Override
public boolean equals(Object other) {
return (other != null) && (other instanceof Geometry)
&& equals((Geometry) other);
}
/**
* geometry specific equals implementation - only defined for non-null
* values
*
* @param other
* ...
* @return ...
*/
public boolean equals(Geometry other) {
return (other != null) && (this.dimension == other.dimension)
&& (this.type == other.type) && (this.srid == other.srid)
&& (this.haveMeasure == other.haveMeasure)
&& other.getClass().equals(this.getClass())
&& this.equalsintern(other);
}
/**
* Whether test coordinates for geometry - subclass specific code
* Implementors can assume that dimensin, type, srid
* and haveMeasure are equal, other != null and other is the same subclass.
*
* @param other
* ...
* @return ...
*/
protected abstract boolean equalsintern(Geometry other);
/**
* Return the number of Points of the geometry
*
* @return ...
*/
abstract int numPoints();
/**
* Get the nth Point of the geometry
*
* @param n
* the index of the point, from 0 to numPoints()-1;
* @throws ArrayIndexOutOfBoundsException
* in case of an emtpy geometry or bad index.
*/
// abstract Point getPoint(int n);
//
// /**
// * Same as getPoint(0);
// */
// abstract Point getFirstPoint();
//
// /**
// * Same as getPoint(numPoints()-1);
// */
// abstract Point getLastPoint();
/**
* The OGIS geometry type number of this geometry.
*
* @return ...
*/
int getType() {
return this.type;
}
/**
* Return the Type as String
*
* @return ...
*/
String getTypeString() {
return getTypeString(this.type);
}
/**
* Returns whether we have a measure
*
* @return ....
*/
boolean isMeasured() {
return haveMeasure;
}
/**
* Queries the number of geometric dimensions of this geometry. This does
* not include measures, as opposed to the
* server.
*
* @return The dimensionality (eg, 2D or 3D) of this geometry.
*/
int getDimension() {
return this.dimension;
}
/**
* The OGIS geometry type number of this geometry.
*
* @return ...
*/
int getSrid() {
return this.srid;
}
/**
* Recursively sets the srid on this geometry and all contained
* subgeometries
*
* @param srid
* ...
*/
void setSrid(int srid) {
this.srid = srid;
}
@Override
public String toString() {
StringBuffer sb = new StringBuffer();
if (srid != UNKNOWN_SRID) {
sb.append("SRID=");
sb.append(srid);
sb.append(';');
}
outerWKT(sb, true);
return sb.toString();
}
/**
* Render the WKT version of this Geometry (without SRID) into the given
* StringBuffer.
*
* @param sb
* ...
* @param putM
* ...
*/
void outerWKT(StringBuffer sb, boolean putM) {
sb.append(getTypeString());
if (putM && haveMeasure && dimension == 2) {
sb.append('M');
}
mediumWKT(sb);
}
final void outerWKT(StringBuffer sb) {
outerWKT(sb, true);
}
/**
* Render the WKT without the type name, but including the brackets into the
* StringBuffer
*
* @param sb
* ...
*/
protected void mediumWKT(StringBuffer sb) {
sb.append('(');
innerWKT(sb);
sb.append(')');
}
/**
* Render the "inner" part of the WKT (inside the brackets) into the
* StringBuffer.
*
* @param SB
* ...
*/
protected abstract void innerWKT(StringBuffer SB);
/**
* backwards compatibility method
*
* @return ...
*/
String getValue() {
StringBuffer sb = new StringBuffer();
mediumWKT(sb);
return sb.toString();
}
/**
* Do some internal consistency checks on the geometry. Currently, all
* Geometries must have a valid dimension (2 or
* 3) and a valid type. 2-dimensional Points must have Z=0.0, as well as
* non-measured Points must have m=0.0.
* Composed geometries must have all equal SRID, dimensionality and
* measures, as well as that they do not contain
* NULL or inconsistent subgeometries. BinaryParser and WKTParser should
* only generate consistent geometries.
* BinaryWriter may produce invalid results on inconsistent geometries.
*
* @return true if all checks are passed.
*/
boolean checkConsistency() {
return (dimension >= 2 && dimension <= 3) && (type >= 0 && type <= 7);
}
/**
* Splits the SRID=4711; part of a EWKT rep if present and sets the srid.
*
* @param value
* ...
* @return value without the SRID=4711; part
*/
protected String initSRID(String value) {
String v = value.trim();
if (v.startsWith("SRID=")) {
int index = v.indexOf(';', 5); // sridprefix length is 5
if (index == -1) {
throw new IllegalArgumentException(
"Error parsing Geometry - SRID not delimited with ';' ");
}
this.srid = Integer.parseInt(v.substring(5, index));
return v.substring(index + 1).trim();
}
return v;
}
}

View File

@@ -0,0 +1,139 @@
/*
* ValueGetter.java
*
* PostGIS extension for PostgreSQL JDBC driver - Binary Parser
*
* (C) 2005 Markus Schaber, markus.schaber@logix-tt.com
*
* This library is free software; you can redistribute it and/or modify it under
* the terms of the GNU Lesser General License as published by the Free
* Software Foundation, either version 2.1 of the License.
*
* This library is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU Lesser General License for more
* details.
*
* You should have received a copy of the GNU Lesser General License
* along with this library; if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA or visit the web at
* http://www.gnu.org.
*
* $Id: ValueGetter.java 9324 2012-02-27 22:08:12Z pramsey $
*/
package org.oscim.utils.wkb;
abstract class ValueGetter {
byte[] data;
int position;
final byte endian;
ValueGetter(byte[] data, byte endian) {
this.data = data;
this.endian = endian;
}
/**
* Get a byte, should be equal for all endians
*
* @return ...
*/
byte getByte() {
return data[position++];
}
int getInt() {
int res = getInt(position);
position += 4;
return res;
}
long getLong() {
long res = getLong(position);
position += 8;
return res;
}
/**
* Get a 32-Bit integer
*
* @param index
* ...
* @return ...
*/
protected abstract int getInt(int index);
/**
* Get a long value. This is not needed directly, but as a nice side-effect
* from GetDouble.
*
* @param index
* ...
* @return ...
*/
protected abstract long getLong(int index);
/**
* Get a double.
*
* @return ...
*/
double getDouble() {
long bitrep = getLong();
return Double.longBitsToDouble(bitrep);
}
static class XDR extends ValueGetter {
static final byte NUMBER = 0;
XDR(byte[] data) {
super(data, NUMBER);
}
@Override
protected int getInt(int index) {
return ((data[index] & 0xFF) << 24) + ((data[index + 1] & 0xFF) << 16)
+ ((data[index + 2] & 0xFF) << 8) + (data[index + 3] & 0xFF);
}
@Override
protected long getLong(int index) {
return ((long) (data[index] & 0xFF) << 56) | ((long) (data[index + 1] & 0xFF) << 48)
| ((long) (data[index + 2] & 0xFF) << 40)
| ((long) (data[index + 3] & 0xFF) << 32)
| ((long) (data[index + 4] & 0xFF) << 24)
| ((long) (data[index + 5] & 0xFF) << 16)
| ((long) (data[index + 6] & 0xFF) << 8)
| ((long) (data[index + 7] & 0xFF) << 0);
}
}
static class NDR extends ValueGetter {
static final byte NUMBER = 1;
NDR(byte[] data) {
super(data, NUMBER);
}
@Override
protected int getInt(int index) {
return ((data[index + 3] & 0xFF) << 24) + ((data[index + 2] & 0xFF) << 16)
+ ((data[index + 1] & 0xFF) << 8) + (data[index] & 0xFF);
}
@Override
protected long getLong(int index) {
return ((long) (data[index + 7] & 0xFF) << 56)
| ((long) (data[index + 6] & 0xFF) << 48)
| ((long) (data[index + 5] & 0xFF) << 40)
| ((long) (data[index + 4] & 0xFF) << 32)
| ((long) (data[index + 3] & 0xFF) << 24)
| ((long) (data[index + 2] & 0xFF) << 16)
| ((long) (data[index + 1] & 0xFF) << 8) | ((long) (data[index] & 0xFF) << 0);
}
}
}

View File

@@ -0,0 +1,208 @@
/*
* Copyright 2013 Hannes Janetzek
*
* This program is free software: you can redistribute it and/or modify it under the
* terms of the GNU Lesser General Public License as published by the Free Software
* Foundation, either version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
* PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License along with
* this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.oscim.utils.wkb;
import org.oscim.core.GeometryBuffer;
public class WKBReader {
interface Callback {
public void process(GeometryBuffer geom);
}
// taken from postgis-java
private GeometryBuffer mGeom;
private final double mScale = 1;
private final double mOffsetX = 0;
private final double mOffsetY = 0;
private WKBReader.Callback mCallback;
/**
* Parse a binary encoded geometry.
*
* @param value
* ...
* @return ...
*/
boolean parse(byte[] value) {
return parseGeometry(valueGetterForEndian(value), 0);
}
private boolean parseGeometry(ValueGetter data, int count) {
byte endian = data.getByte(); // skip and test endian flag
if (endian != data.endian) {
throw new IllegalArgumentException("Endian inconsistency!");
}
int typeword = data.getInt();
int realtype = typeword & 0x1FFFFFFF; // cut off high flag bits
boolean haveZ = (typeword & 0x80000000) != 0;
boolean haveM = (typeword & 0x40000000) != 0;
boolean haveS = (typeword & 0x20000000) != 0;
// int srid = Geometry.UNKNOWN_SRID;
boolean polygon = false;
if (haveS) {
// srid = Geometry.parseSRID(data.getInt());
data.getInt();
}
switch (realtype) {
case Geometry.POINT:
mGeom.startPoints();
parsePoint(data, haveZ, haveM);
break;
case Geometry.LINESTRING:
mGeom.startLine();
parseLineString(data, haveZ, haveM);
break;
case Geometry.POLYGON:
mGeom.startPolygon();
parsePolygon(data, haveZ, haveM);
polygon = true;
break;
case Geometry.MULTIPOINT:
mGeom.startPoints();
parseMultiPoint(data);
break;
case Geometry.MULTILINESTRING:
mGeom.startLine();
parseMultiLineString(data);
break;
case Geometry.MULTIPOLYGON:
mGeom.startPolygon();
parseMultiPolygon(data);
polygon = true;
break;
case Geometry.GEOMETRYCOLLECTION:
parseCollection(data);
break;
default:
throw new IllegalArgumentException("Unknown Geometry Type: " + realtype);
}
if (count == 0) {
mCallback.process(mGeom);
mGeom.clear();
}
// if (srid != Geometry.UNKNOWN_SRID) {
// result.setSrid(srid);
// }
return polygon;
}
private void parsePoint(ValueGetter data, boolean haveZ, boolean haveM) {
float x = (float) ((data.getDouble() + mOffsetX) * mScale);
float y = (float) ((data.getDouble() + mOffsetY) * mScale);
mGeom.addPoint(x, y);
if (haveZ)
data.getDouble();
if (haveM)
data.getDouble();
}
/**
* Parse an Array of "full" Geometries
*
* @param data
* ...
* @param count
* ...
*/
private void parseGeometryArray(ValueGetter data, int count) {
mGeom.clear();
for (int i = 0; i < count; i++) {
parseGeometry(data, count);
mGeom.index[mGeom.indexPos++] = 0;
}
mCallback.process(mGeom);
mGeom.clear();
}
private void parseMultiPoint(ValueGetter data) {
parseGeometryArray(data, data.getInt());
}
private void parseLineString(ValueGetter data, boolean haveZ, boolean haveM) {
int count = data.getInt();
for (int i = 0; i < count; i++) {
float x = (float) ((data.getDouble() + mOffsetX) * mScale);
float y = (float) ((data.getDouble() + mOffsetY) * mScale);
mGeom.addPoint(x, y);
// ignore
if (haveZ)
data.getDouble();
if (haveM)
data.getDouble();
}
}
private void parsePolygon(ValueGetter data, boolean haveZ, boolean haveM) {
int count = data.getInt();
for (int i = 0; i < count; i++) {
if (i > 0)
mGeom.startHole();
parseLineString(data, haveZ, haveM);
}
}
private void parseMultiLineString(ValueGetter data) {
int count = data.getInt();
if (count <= 0)
return;
parseGeometryArray(data, count);
}
private void parseMultiPolygon(ValueGetter data) {
int count = data.getInt();
if (count <= 0)
return;
parseGeometryArray(data, count);
}
private void parseCollection(ValueGetter data) {
int count = data.getInt();
parseGeometryArray(data, count);
mCallback.process(mGeom);
mGeom.clear();
}
private static ValueGetter valueGetterForEndian(byte[] bytes) {
if (bytes[0] == ValueGetter.XDR.NUMBER) { // XDR
return new ValueGetter.XDR(bytes);
} else if (bytes[0] == ValueGetter.NDR.NUMBER) {
return new ValueGetter.NDR(bytes);
} else {
throw new IllegalArgumentException("Unknown Endian type:" + bytes[0]);
}
}
}