io.github.sebasbaumh.postgis.binary.BinaryParser Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of postgis-java-ng Show documentation
Show all versions of postgis-java-ng Show documentation
This project contains Java bindings for using PostGIS geometries coming from a PostgreSQL database.
The newest version!
/*
* PostGIS extension for PostgreSQL JDBC driver
*
* (C) 2004 Paul Ramsey, [email protected]
* (C) 2005 Markus Schaber, [email protected]
* (C) 2015 Phillip Ross, [email protected]
* (C) 2018-2023 Sebastian Baumhekel, [email protected]
*
* This library 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 2.1 of the License, or (at your option) any later version.
*
* 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 Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see .
*/
package io.github.sebasbaumh.postgis.binary;
import java.util.ArrayList;
import java.util.Collection;
import io.github.sebasbaumh.postgis.CircularString;
import io.github.sebasbaumh.postgis.CompoundCurve;
import io.github.sebasbaumh.postgis.Curve;
import io.github.sebasbaumh.postgis.CurvePolygon;
import io.github.sebasbaumh.postgis.Geometry;
import io.github.sebasbaumh.postgis.GeometryCollection;
import io.github.sebasbaumh.postgis.LineString;
import io.github.sebasbaumh.postgis.LinearRing;
import io.github.sebasbaumh.postgis.MultiCurve;
import io.github.sebasbaumh.postgis.MultiLineString;
import io.github.sebasbaumh.postgis.MultiPoint;
import io.github.sebasbaumh.postgis.MultiPolygon;
import io.github.sebasbaumh.postgis.MultiSurface;
import io.github.sebasbaumh.postgis.Point;
import io.github.sebasbaumh.postgis.Polygon;
import io.github.sebasbaumh.postgis.PolygonBase;
/**
* A parser for reading geometries from a binary or hex string representation.
* @author Sebastian Baumhekel
*/
public final class BinaryParser
{
// prevent instantiating this class
@Deprecated
private BinaryParser()
{
}
/**
* Parse a hex encoded geometry
* @param value byte array containing the data to be parsed
* @param offset offset
* @return resulting geometry for the parsed data
* @throws IllegalArgumentException if a contained geometry is of the wrong type or the encoding type is unknown
*/
public static Geometry parse(byte[] value, int offset)
{
return parseGeometry(new BinaryValueGetter(value, offset));
}
/**
* Parse a hex encoded geometry
* @param value String containing the data to be parsed
* @return resulting geometry for the parsed data
* @throws IllegalArgumentException if a contained geometry is of the wrong type or the encoding type is unknown
*/
public static Geometry parse(String value)
{
return parseGeometry(new StringValueGetter(value));
}
/**
* Parse multiple geometries into a {@link Collection}. The number of geometries is read upfront from the
* {@link ValueGetter}.
* @param clazz {@link Class} of the geometries
* @param data {@link ValueGetter}
* @return {@link Collection} of geometries
* @throws IllegalArgumentException if a contained geometry is of the wrong type
*/
@SuppressWarnings("unchecked")
private static Collection parseGeometries(Class clazz, ValueGetter data)
{
// get number of geometries to parse
int count = data.getInt();
ArrayList l = new ArrayList(count);
// parse geometries
for (int i = 0; i < count; i++)
{
Geometry geom = parseGeometry(data);
// check if the geometry is of the correct type
if (clazz.isInstance(geom))
{
l.add((T) geom);
}
else
{
throw new IllegalArgumentException(
"expected: " + clazz.getCanonicalName() + " got: " + geom.getClass().getCanonicalName());
}
}
return l;
}
/**
* Parse a geometry starting at offset.
* @param data ValueGetter with the data to be parsed
* @return the parsed geometry
* @throws IllegalArgumentException for unknown geometry types
*/
private static Geometry parseGeometry(ValueGetter data)
{
// read endian flag
data.readEncoding();
// and get the type
int typeword = data.getInt();
int geometryType = 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;
if (haveS)
{
// ensure valid SRID
srid = data.getInt();
if (srid < 0)
{
srid = Geometry.UNKNOWN_SRID;
}
}
// parse geometry according to type
Geometry result;
switch (geometryType)
{
case Point.TYPE:
result = parsePoint(data, haveZ, haveM);
break;
case LineString.TYPE:
result = new LineString(parsePoints(data, haveZ, haveM));
break;
case CircularString.TYPE:
result = new CircularString(parsePoints(data, haveZ, haveM));
break;
case CompoundCurve.TYPE:
result = new CompoundCurve(parseGeometries(LineString.class, data));
break;
case Polygon.TYPE:
result = parsePolygon(data, haveZ, haveM);
break;
case CurvePolygon.TYPE:
result = new CurvePolygon(parseGeometries(Curve.class, data));
break;
case MultiPoint.TYPE:
result = new MultiPoint(parseGeometries(Point.class, data));
break;
case MultiLineString.TYPE:
result = new MultiLineString(parseGeometries(LineString.class, data));
break;
case MultiCurve.TYPE:
result = new MultiCurve(parseGeometries(Curve.class, data));
break;
case MultiPolygon.TYPE:
result = new MultiPolygon(parseGeometries(Polygon.class, data));
break;
case MultiSurface.TYPE:
result = new MultiSurface(parseGeometries(PolygonBase.class, data));
break;
case GeometryCollection.TYPE:
result = new GeometryCollection(parseGeometries(Geometry.class, data));
break;
default:
throw new IllegalArgumentException("Unknown Geometry Type: " + geometryType);
}
// set SRID and return the geometry
result.setSrid(srid);
return result;
}
/**
* Parse a single point.
* @param data {@link ValueGetter}
* @param haveZ parse z value?
* @param haveM parse measure value?
* @return {@link Point}
*/
private static Point parsePoint(ValueGetter data, boolean haveZ, boolean haveM)
{
double x = data.getDouble();
double y = data.getDouble();
Point result;
// parse z?
if (haveZ)
{
result = new Point(x, y, data.getDouble());
}
else
{
result = new Point(x, y);
}
// parse measure?
if (haveM)
{
result.setM(data.getDouble());
}
return result;
}
/**
* Parse an Array of "slim" {@link Point}s (without endianness and type, part of {@link LinearRing} and
* {@link LineString}, but not {@link MultiPoint}!
* @param data {@link ValueGetter}
* @param haveZ parse z value?
* @param haveM parse measure value?
* @return {@link Collection} of {@link Point}s
*/
private static Collection parsePoints(ValueGetter data, boolean haveZ, boolean haveM)
{
int count = data.getInt();
ArrayList l = new ArrayList(count);
for (int i = 0; i < count; i++)
{
l.add(parsePoint(data, haveZ, haveM));
}
return l;
}
/**
* Parse a {@link Polygon}.
* @param data {@link ValueGetter}
* @param haveZ parse z value?
* @param haveM parse measure value?
* @return {@link Polygon}
*/
private static Polygon parsePolygon(ValueGetter data, boolean haveZ, boolean haveM)
{
int count = data.getInt();
ArrayList rings = new ArrayList(count);
for (int i = 0; i < count; i++)
{
rings.add(new LinearRing(parsePoints(data, haveZ, haveM)));
}
return new Polygon(rings);
}
}