fix WKBReader

This commit is contained in:
Hannes Janetzek 2013-07-24 05:06:07 +02:00
parent 1481f4b508
commit a6994913be

View File

@ -15,33 +15,46 @@
package org.oscim.utils.wkb; package org.oscim.utils.wkb;
import org.oscim.core.GeometryBuffer; import org.oscim.core.GeometryBuffer;
import org.oscim.core.Tile;
public class WKBReader { public class WKBReader {
interface Callback { public interface Callback {
public void process(GeometryBuffer geom); public void process(GeometryBuffer geom);
} }
// taken from postgis-java private final GeometryBuffer mGeom;
private final boolean mFlipY;
private GeometryBuffer mGeom;
private final double mScale = 1;
private final double mOffsetX = 0;
private final double mOffsetY = 0;
private WKBReader.Callback mCallback; private WKBReader.Callback mCallback;
/** public WKBReader(GeometryBuffer geom, boolean flipY) {
* Parse a binary encoded geometry. mGeom = geom;
* mFlipY = flipY;
* @param value
* ...
* @return ...
*/
boolean parse(byte[] value) {
return parseGeometry(valueGetterForEndian(value), 0);
} }
private boolean parseGeometry(ValueGetter data, int count) { public void setCallback(WKBReader.Callback cb) {
mCallback = cb;
}
/**
* Parse a binary encoded geometry.
*/
public void parse(byte[] value) {
parseGeometry(valueGetterForEndian(value), 0);
}
/**
* Parse a hex encoded geometry.
*/
public void parse(String value) {
byte[] b = hexStringToByteArray(value);
if (b == null)
return;
parse(b);
}
private void parseGeometry(ValueGetter data, int count) {
byte endian = data.getByte(); // skip and test endian flag byte endian = data.getByte(); // skip and test endian flag
if (endian != data.endian) { if (endian != data.endian) {
throw new IllegalArgumentException("Endian inconsistency!"); throw new IllegalArgumentException("Endian inconsistency!");
@ -55,59 +68,59 @@ public class WKBReader {
boolean haveS = (typeword & 0x20000000) != 0; boolean haveS = (typeword & 0x20000000) != 0;
// int srid = Geometry.UNKNOWN_SRID; // int srid = Geometry.UNKNOWN_SRID;
boolean polygon = false;
if (haveS) { if (haveS) {
// srid = Geometry.parseSRID(data.getInt()); // srid = Geometry.parseSRID(data.getInt());
data.getInt(); data.getInt();
} }
switch (realtype) { switch (realtype) {
case Geometry.POINT: case Geometry.POINT:
mGeom.startPoints(); mGeom.startPoints();
parsePoint(data, haveZ, haveM); parsePoint(data, haveZ, haveM);
break; break;
case Geometry.LINESTRING: case Geometry.LINESTRING:
mGeom.startLine(); mGeom.startLine();
parseLineString(data, haveZ, haveM); parseLineString(data, haveZ, haveM);
break; break;
case Geometry.POLYGON: case Geometry.POLYGON:
mGeom.startPolygon(); mGeom.startPolygon();
parsePolygon(data, haveZ, haveM); parsePolygon(data, haveZ, haveM);
polygon = true; break;
break; case Geometry.MULTIPOINT:
case Geometry.MULTIPOINT: mGeom.startPoints();
mGeom.startPoints(); parseMultiPoint(data);
parseMultiPoint(data); break;
break; case Geometry.MULTILINESTRING:
case Geometry.MULTILINESTRING: mGeom.startLine();
mGeom.startLine(); parseMultiLineString(data);
parseMultiLineString(data); break;
break; case Geometry.MULTIPOLYGON:
case Geometry.MULTIPOLYGON: mGeom.startPolygon();
mGeom.startPolygon(); parseMultiPolygon(data);
parseMultiPolygon(data); break;
polygon = true; case Geometry.GEOMETRYCOLLECTION:
break; parseCollection(data);
case Geometry.GEOMETRYCOLLECTION: break;
parseCollection(data); default:
break; throw new IllegalArgumentException("Unknown Geometry Type: " + realtype);
default:
throw new IllegalArgumentException("Unknown Geometry Type: " + realtype);
} }
if (count == 0) { if (count == 0) {
mCallback.process(mGeom); mCallback.process(mGeom);
mGeom.clear(); mGeom.clear();
} }
// if (srid != Geometry.UNKNOWN_SRID) { // if (srid != Geometry.UNKNOWN_SRID) {
// result.setSrid(srid); // result.setSrid(srid);
// } // }
return polygon;
} }
private void parsePoint(ValueGetter data, boolean haveZ, boolean haveM) { private void parsePoint(ValueGetter data, boolean haveZ, boolean haveM) {
float x = (float) ((data.getDouble() + mOffsetX) * mScale); float x = (float) data.getDouble();
float y = (float) ((data.getDouble() + mOffsetY) * mScale); float y = (float) data.getDouble();
if (mFlipY)
y = Tile.SIZE - y;
mGeom.addPoint(x, y); mGeom.addPoint(x, y);
if (haveZ) if (haveZ)
@ -125,12 +138,22 @@ public class WKBReader {
* @param count * @param count
* ... * ...
*/ */
private void parseGeometryArray(ValueGetter data, int count) { private void parseGeometryArray(ValueGetter data, int count, int type) {
mGeom.clear(); mGeom.clear();
for (int i = 0; i < count; i++) { for (int i = 0; i < count; i++) {
if (i > 0) {
if (type == Geometry.LINESTRING)
mGeom.startLine();
else if (type == Geometry.POLYGON)
mGeom.startPolygon();
else {
mCallback.process(mGeom);
mGeom.clear();
}
}
parseGeometry(data, count); parseGeometry(data, count);
mGeom.index[mGeom.indexPos++] = 0; // mGeom.index[++mGeom.indexPos] = -1;
} }
mCallback.process(mGeom); mCallback.process(mGeom);
@ -138,7 +161,7 @@ public class WKBReader {
} }
private void parseMultiPoint(ValueGetter data) { private void parseMultiPoint(ValueGetter data) {
parseGeometryArray(data, data.getInt()); parseGeometryArray(data, data.getInt(), Geometry.POINT);
} }
private void parseLineString(ValueGetter data, boolean haveZ, boolean haveM) { private void parseLineString(ValueGetter data, boolean haveZ, boolean haveM) {
@ -146,8 +169,12 @@ public class WKBReader {
int count = data.getInt(); int count = data.getInt();
for (int i = 0; i < count; i++) { for (int i = 0; i < count; i++) {
float x = (float) ((data.getDouble() + mOffsetX) * mScale); float x = (float) data.getDouble();
float y = (float) ((data.getDouble() + mOffsetY) * mScale); float y = (float) data.getDouble();
if (mFlipY)
y = Tile.SIZE - y;
mGeom.addPoint(x, y); mGeom.addPoint(x, y);
// ignore // ignore
@ -166,7 +193,26 @@ public class WKBReader {
if (i > 0) if (i > 0)
mGeom.startHole(); mGeom.startHole();
parseLineString(data, haveZ, haveM);
int points = data.getInt();
for (int j = 0; j < points; j++) {
float x = (float) data.getDouble();
float y = (float) data.getDouble();
if (mFlipY)
y = Tile.SIZE - y;
// drop redundant closing point
if (j < points - 1)
mGeom.addPoint(x, y);
// ignore
if (haveZ)
data.getDouble();
if (haveM)
data.getDouble();
}
} }
} }
@ -176,7 +222,7 @@ public class WKBReader {
if (count <= 0) if (count <= 0)
return; return;
parseGeometryArray(data, count); parseGeometryArray(data, count, Geometry.LINESTRING);
} }
private void parseMultiPolygon(ValueGetter data) { private void parseMultiPolygon(ValueGetter data) {
@ -184,12 +230,13 @@ public class WKBReader {
if (count <= 0) if (count <= 0)
return; return;
parseGeometryArray(data, count); parseGeometryArray(data, count, Geometry.POLYGON);
} }
private void parseCollection(ValueGetter data) { private void parseCollection(ValueGetter data) {
int count = data.getInt(); int count = data.getInt();
parseGeometryArray(data, count);
parseGeometryArray(data, count, Geometry.GEOMETRYCOLLECTION);
mCallback.process(mGeom); mCallback.process(mGeom);
mGeom.clear(); mGeom.clear();
@ -205,4 +252,24 @@ public class WKBReader {
} }
} }
/**
* Converting a string of hex character to bytes
*
* from http://stackoverflow.com/questions/140131/convert-a-string-
* representation-of-a-hex-dump-to-a-byte-array-using-java
*/
public static byte[] hexStringToByteArray(String s) {
int len = s.length();
if (len < 2)
return null;
byte[] data = new byte[len / 2];
for (int i = 0; i < len; i += 2) {
data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4)
+ Character.digit(s.charAt(i + 1), 16));
}
return data;
}
} }