/* * $Id: WKBReader.java,v 1.1 2007-02-27 12:45:29 eugen Exp $ * * Copyright (C) 2002 by Brockmann Consult (info@brockmann-consult.de) * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation. This program is distributed in the hope it will * be useful, but WITHOUT ANY WARRANTY; without even the implied warranty * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ package com.bc.util.geom; import java.awt.geom.GeneralPath; import java.awt.geom.Point2D; import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.InputStream; import java.io.InvalidClassException; import java.nio.ByteBuffer; import java.nio.ByteOrder; import com.bc.util.NotImplementedException; /** * Reads a {@link Geometry}from a byte stream in Well-Known Binary format. * <p> * This class is designed to support reuse of a single instance to read multiple * geometries. This class is not thread-safe; each thread should create its own * instance. * * @see WKBWriter */ public class WKBReader { private static final String INVALID_GEOM_TYPE_MSG = "Invalid geometry type encountered in "; private InputStream inputStream; private ByteBuffer bBuffer; public WKBReader() { bBuffer = ByteBuffer.allocate(2*8); } /** * Reads a single {@link Geometry} from a byte array. * * @param bytes * the byte array to read from * @return the geometry read * @throws IOException * if an input exception occurs */ public Geometry read(byte[] bytes) throws IOException { inputStream = new ByteArrayInputStream(bytes); return read(inputStream); } /** * Reads a {@link Geometry} from an {@link InputStream). * * @param is * the stream to read from * @return the Geometry read * @throws IOException */ public Geometry read(InputStream is) throws IOException { this.inputStream = is; return readGeometry(); } private Geometry readGeometry() throws IOException { // determine byte order int byteOrder = inputStream.read(); // default is big endian if (byteOrder == WKBConstants.NDR) { bBuffer.order(ByteOrder.LITTLE_ENDIAN); } int typeInt = readInt(); int geometryType = typeInt & 0xff; switch (geometryType) { case WKBConstants.POINT: return readPoint(); case WKBConstants.LINESTRING: return readLineString(); case WKBConstants.POLYGON: return readPolygon(); case WKBConstants.MULTIPOINT: return readMultiPoint(); case WKBConstants.MULTILINESTRING: return readMultiLineString(); case WKBConstants.MULTIPOLYGON: return readMultiPolygon(); case WKBConstants.GEOMETRYCOLLECTION: return readGeometryCollection(); } throw new InvalidClassException("Unknown WKB type " + geometryType); } private PointGeometry readPoint() throws IOException { Point2D point = readPoint2D(); return new PointGeometry(point); } private LineStringGeometry readLineString() throws IOException { return new LineStringGeometry(readLinearRing()); } private GeneralPath readLinearRing() throws IOException { final int size = readInt(); GeneralPath linearRing = new GeneralPath(); for (int i = 0; i < size; i++) { Point2D point = readPoint2D(); if (i == 0) { linearRing.moveTo((float) point.getX(), (float) point.getY()); } else { linearRing.lineTo((float) point.getX(), (float) point.getY()); } } return linearRing; } private PolygonGeometry readPolygon() throws IOException { int numRings = readInt(); GeneralPath polygon = new GeneralPath(); for (int i = 0; i < numRings; i++) { GeneralPath ring = readLinearRing(); polygon.append(ring, false); } return new PolygonGeometry(polygon); } private MultiPointGeometry readMultiPoint() throws IOException { final int numGeom = readInt(); MultiPointGeometry multiPoint = new MultiPointGeometry(); for (int i = 0; i < numGeom; i++) { Geometry geometry = readGeometry(); if (geometry instanceof PointGeometry) { multiPoint.addPoint((PointGeometry) geometry); } else { throw new InvalidClassException(INVALID_GEOM_TYPE_MSG + "MultiPoint"); } } return multiPoint; } private MultiLineStringGeometry readMultiLineString() throws IOException { final int numGeom = readInt(); MultiLineStringGeometry multiLineString = new MultiLineStringGeometry(); for (int i = 0; i < numGeom; i++) { Geometry geometry = readGeometry(); if (geometry instanceof LineStringGeometry) { multiLineString.addLineString((LineStringGeometry) geometry); } else { throw new InvalidClassException(INVALID_GEOM_TYPE_MSG + "MultiLineString"); } } return multiLineString; } private MultiPolygonGeometry readMultiPolygon() throws IOException { final int numGeom = readInt(); MultiPolygonGeometry multiPolygon = new MultiPolygonGeometry(); for (int i = 0; i < numGeom; i++) { Geometry geometry = readGeometry(); if (geometry instanceof PolygonGeometry) { multiPolygon.addPolygon((PolygonGeometry) geometry); } else { throw new InvalidClassException(INVALID_GEOM_TYPE_MSG + "MultiPolygon"); } } return multiPolygon; } private GeometryCollection readGeometryCollection() throws IOException { throw new NotImplementedException(); } private Point2D readPoint2D() throws IOException { bBuffer.rewind(); inputStream.read(bBuffer.array(), 0, 2 * 8); double x = bBuffer.getDouble(); double y = bBuffer.getDouble(); return new Point2D.Double(x, y); } private int readInt() throws IOException { bBuffer.rewind(); inputStream.read(bBuffer.array(), 0, 4); return bBuffer.getInt(); } }