/* * Geotoolkit - An Open Source Java GIS Toolkit * http://www.geotoolkit.org * * (C) 2013, Geomatys * * 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; * 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 Public License for more details. */ package org.geotoolkit.db.postgres; import com.vividsolutions.jts.geom.Coordinate; import com.vividsolutions.jts.geom.CoordinateSequence; import com.vividsolutions.jts.geom.Geometry; import com.vividsolutions.jts.geom.GeometryCollection; import com.vividsolutions.jts.geom.GeometryFactory; import com.vividsolutions.jts.geom.LineString; import com.vividsolutions.jts.geom.LinearRing; import com.vividsolutions.jts.geom.MultiLineString; import com.vividsolutions.jts.geom.MultiPoint; import com.vividsolutions.jts.geom.MultiPolygon; import com.vividsolutions.jts.geom.Point; import com.vividsolutions.jts.geom.Polygon; import com.vividsolutions.jts.geom.impl.PackedCoordinateSequence; import java.sql.SQLException; import java.util.logging.Level; import org.postgis.binary.ByteGetter; import org.postgis.binary.ValueGetter; import static org.postgis.Geometry.*; /** * PostGIS Hexa-EWKB Geometry reader/write classes. * http://postgis.net/docs/using_postgis_dbmanagement.html#EWKB_EWKT * * This format is the natural form returned by a query selection a geometry field * whithout using any ST_X method. * * @author Johann Sorel (Geomatys) */ final class PostgisHexEWKB { private static final int MASK_Z = 0x80000000; private static final int MASK_M = 0x40000000; private static final int MASK_SRID = 0x20000000; private static final int MASK_GEOMTYPE = 0x1FFFFFFF; private final GeometryFactory gf; private final PostgresDialect dialect; PostgisHexEWKB(final GeometryFactory gf, final PostgresDialect dialect) { this.dialect = dialect; this.gf = gf; } public Geometry read(final String value) { if(value == null) return null; final ByteGetter.StringByteGetter bytes = new ByteGetter.StringByteGetter(value); final ValueGetter vg; final int endianess = bytes.get(0); if(endianess == ValueGetter.XDR.NUMBER){ vg = new ValueGetter.XDR(bytes); }else if(endianess == ValueGetter.NDR.NUMBER){ vg = new ValueGetter.NDR(bytes); }else{ throw new IllegalArgumentException("Illegal endianess value : " + endianess); } return readGeometry(vg,0); } private Geometry readGeometry(final ValueGetter data, int srid) { byte endian = data.getByte(); // skip and test endian flag if (endian != data.endian) { throw new IllegalArgumentException("Endian inconsistency!"); } //parse flags final int flags = data.getInt(); final boolean flagZ = (flags & MASK_Z) != 0; final boolean flagM = (flags & MASK_M) != 0; final boolean flagSRID = (flags & MASK_SRID) != 0; final int geomType = (flags & MASK_GEOMTYPE); final int nbDim = 2 + ((flagZ)?1:0) + ((flagM)?1:0); if(flagSRID){ srid = data.getInt(); } final Geometry geom; switch (geomType) { case POINT: geom = readPoint(data, nbDim); break; case LINESTRING: geom = readLineString(data, nbDim); break; case POLYGON: geom = readPolygon(data, nbDim, srid); break; case MULTIPOINT: geom = readMultiPoint(data, srid); break; case MULTILINESTRING: geom = readMultiLineString(data, srid); break; case MULTIPOLYGON: geom = readMultiPolygon(data, srid); break; case GEOMETRYCOLLECTION:geom = readCollection(data, srid); break; default: throw new IllegalArgumentException("Unknown geometry type : "+geomType); } geom.setSRID(srid); if(srid >= 0){ try { //set the real crs geom.setUserData(dialect.decodeCRS(srid, null)); } catch (SQLException ex) { dialect.getFeaturestore().getLogger().log(Level.WARNING, ex.getLocalizedMessage(),ex); } } return geom; } private Point readPoint(final ValueGetter data, final int nbDim) { switch(nbDim){ case 2: return gf.createPoint(new Coordinate(data.getDouble(),data.getDouble())); case 3: return gf.createPoint(new Coordinate(data.getDouble(),data.getDouble(),data.getDouble())); case 4: final CoordinateSequence cs = new PackedCoordinateSequence.Double(1, nbDim); cs.setOrdinate(0, 0, data.getDouble()); cs.setOrdinate(0, 1, data.getDouble()); cs.setOrdinate(0, 2, data.getDouble()); cs.setOrdinate(0, 3, data.getDouble()); return gf.createPoint(cs); default : throw new IllegalArgumentException("Invalid dimension number : "+nbDim); } } private CoordinateSequence readCS(final ValueGetter data, final int nbDim) { final int nb = data.getInt(); final CoordinateSequence cs = new PackedCoordinateSequence.Double(nb, nbDim); for(int index=0; index<nb; index++){ for(int ordinal=0; ordinal<nbDim; ordinal++){ cs.setOrdinate(index, ordinal, data.getDouble()); } } return cs; } private MultiPoint readMultiPoint(final ValueGetter data, final int srid) { final Point[] geoms = new Point[data.getInt()]; for(int i=0; i<geoms.length; i++){ geoms[i]=(Point)readGeometry(data, srid); } return gf.createMultiPoint(geoms); } private LineString readLineString(final ValueGetter data, final int nbDim) { return gf.createLineString(readCS(data, nbDim)); } private LinearRing readLinearRing(final ValueGetter data, final int nbDim) { return gf.createLinearRing(readCS(data, nbDim)); } private Polygon readPolygon(final ValueGetter data, final int nbDim, final int srid) { final LinearRing[] inners = new LinearRing[data.getInt()-1]; final LinearRing outter = readLinearRing(data, nbDim); outter.setSRID(srid); for(int i=0; i<inners.length; i++){ inners[i] = readLinearRing(data, nbDim); inners[i].setSRID(srid); } return gf.createPolygon(outter, inners); } private MultiLineString readMultiLineString(final ValueGetter data, final int srid) { final LineString[] geoms = new LineString[data.getInt()]; for(int i=0; i<geoms.length; i++){ geoms[i]=(LineString)readGeometry(data, srid); } return gf.createMultiLineString(geoms); } private MultiPolygon readMultiPolygon(final ValueGetter data, final int srid) { final Polygon[] geoms = new Polygon[data.getInt()]; for(int i=0; i<geoms.length; i++){ geoms[i]=(Polygon)readGeometry(data, srid); } return gf.createMultiPolygon(geoms); } private GeometryCollection readCollection(final ValueGetter data, final int srid) { final Geometry[] geoms = new Geometry[data.getInt()]; for(int i=0; i<geoms.length; i++){ geoms[i]=(Point)readGeometry(data, srid); } return gf.createGeometryCollection(geoms); } }