vtm/src/org/oscim/utils/wkb/WKBReader.java
2013-10-09 01:56:01 +02:00

209 lines
4.9 KiB
Java

/*
* 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]);
}
}
}