/* * GeoTools - The Open Source Java GIS Toolkit * http://geotools.org * * (C) 2002-2010, Open Source Geospatial Foundation (OSGeo) * * 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.geotools.geopkg.geom; import java.io.IOException; import java.io.InputStream; import com.vividsolutions.jts.geom.Envelope; import com.vividsolutions.jts.geom.Geometry; import com.vividsolutions.jts.geom.GeometryFactory; import com.vividsolutions.jts.io.ByteArrayInStream; import com.vividsolutions.jts.io.ByteOrderDataInStream; import com.vividsolutions.jts.io.InStream; import com.vividsolutions.jts.io.InputStreamInStream; import com.vividsolutions.jts.io.ParseException; import com.vividsolutions.jts.io.WKBReader; /** * Translates a GeoPackage geometry BLOB to a vividsolutions Geometry. * * @author Justin Deoliveira * @author Niels Charlier */ public class GeoPkgGeomReader { protected InStream input; protected GeometryHeader header = null; protected Geometry geometry = null; private GeometryFactory factory = new GeometryFactory(); public GeoPkgGeomReader(InStream input) { this.input = input; } public GeoPkgGeomReader(InputStream input) throws IOException { this.input = new InputStreamInStream(input); } public GeoPkgGeomReader(byte[] bytes) { this.input = new ByteArrayInStream(bytes); } public GeometryHeader getHeader() throws IOException { if (header == null) { header = readHeader(); } return header; } public Geometry get() throws IOException { if (header == null) { header = readHeader(); } if (geometry == null) { geometry = read(); } return geometry; } public Envelope getEnvelope() throws IOException { if (getHeader().getFlags().getEnvelopeIndicator() == EnvelopeType.NONE) { return get().getEnvelopeInternal(); } else { return getHeader().getEnvelope(); } } protected Geometry read() throws IOException { //header must be read! // read the geometry try { WKBReader wkbReader = new WKBReader(factory); Geometry g = wkbReader.read(input); g.setSRID(header.getSrid()); return g; } catch (ParseException e) { throw new IOException(e); } } /* * OptimizedGeoPackageBinary { * byte[3] magic = 0x47504230; // 'GPB' * byte flags; // see flags layout below * unit32 srid; * double[] envelope; // see flags envelope contents indicator code below * WKBGeometry geometry; // per OGC 06-103r4 clause 8 * * * flags layout: * bit 7 6 5 4 3 2 1 0 * use - - X Y E E E B * use: * X: GeoPackageBinary type (0: StandardGeoPackageBinary, 1: ExtendedGeoPackageBinary) * Y: 0: non-empty geometry, 1: empty geometry * * E: envelope contents indicator code (3-bit unsigned integer) * value | description | envelope length (bytes) * 0 | no envelope (space saving slower indexing option) | 0 * 1 | envelope is [minx, maxx, miny, maxy] | 32 * 2 | envelope is [minx, maxx, miny, maxy, minz, maxz] | 48 * 3 | envelope is [minx, maxx, miny, maxy, minm, maxm] | 48 * 4 | envelope is [minx, maxx, miny, maxy, minz, maxz, minm, maxm] | 64 * B: byte order for header values (1-bit Boolean) * 0 = Big Endian (most significant bit first) * 1 = Little Endian (least significant bit first) */ protected GeometryHeader readHeader() throws IOException { GeometryHeader h = new GeometryHeader(); // read first 4 bytes // TODO: something with the magic number byte[] buf = new byte[4]; input.read(buf); // next byte flags h.setFlags(new GeometryHeaderFlags((byte)buf[3])); // set endianess ByteOrderDataInStream din = new ByteOrderDataInStream(input); din.setOrder(h.getFlags().getEndianess()); // read the srid h.setSrid(din.readInt()); // read the envelope if (h.getFlags().getEnvelopeIndicator() != EnvelopeType.NONE) { double x1 = din.readDouble(); double x2 = din.readDouble(); double y1 = din.readDouble(); double y2 = din.readDouble(); if (h.getFlags().getEnvelopeIndicator().getValue() > 1) { // 2 = minz,maxz; 3 = minm,maxm - we ignore these for now din.readDouble(); din.readDouble(); } if (h.getFlags().getEnvelopeIndicator().getValue() > 3) { // 4 = minz,maxz,minm,maxm - we ignore these for now din.readDouble(); din.readDouble(); } h.setEnvelope (new Envelope(x1, x2, y1, y2)); } return h; } /** * @return the factory */ public GeometryFactory getFactory() { return factory; } /** * @param factory the factory to set */ public void setFactory(GeometryFactory factory) { if(factory!=null) { this.factory = factory; } } }