Rev 21 | Rev 49 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | RSS feed
/*** $Id: SDOGeometryType.java 40 2007-09-20 15:33:24Z maesenka $** This file is part of Spatial Hibernate, an extension to the* hibernate ORM solution for geographic data.** Copyright © 2007 K.U. Leuven LRD, Spatial Applications Division, Belgium** This work was partially supported by the European Commission,* under the 6th Framework Programme, contract IST-2-004688-STP.** 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, write to the Free Software* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA** For more information, visit: http://www.cadrie.com/*/package org.hibernatespatial.oracle;import java.sql.Connection;import java.sql.PreparedStatement;import java.sql.SQLException;import java.sql.Types;import oracle.spatial.geometry.JGeometry;import oracle.sql.STRUCT;import org.hibernate.HibernateException;import org.hibernatespatial.AbstractDBGeometryType;import org.hibernatespatial.HibernateSpatialException;import com.vividsolutions.jts.algorithm.CGAlgorithms;import com.vividsolutions.jts.geom.Coordinate;import com.vividsolutions.jts.geom.CoordinateSequence;import com.vividsolutions.jts.geom.Geometry;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;/*** Implements Oracle 9i/10g specific geometrytype.** @author Karel Maesen*/public class SDOGeometryType extends AbstractDBGeometryType {private static final int[] geometryTypes = new int[] { Types.STRUCT };private static final GeometryFactory geomFactory = new GeometryFactory();private static String SQL_TYPE_NAME = "SDO_GEOMETRY";@Overridepublic void nullSafeSet(PreparedStatement st, Object value, int index)throws HibernateException, SQLException {if (value == null) {st.setNull(index, sqlTypes()[0], SQL_TYPE_NAME);} else {Geometry jtsGeom = (Geometry) value;Object dbGeom = conv2DBGeometry(jtsGeom, st.getConnection());st.setObject(index, dbGeom);}}@Overridepublic Object conv2DBGeometry(Geometry jtsGeom, Connection connection) {// note: we assume that there is no LRS used in jtsGeom.JGeometry geom = null;if (jtsGeom.getClass() == Point.class) {geom = convertJTSPoint((Point) jtsGeom);} else if (jtsGeom.getClass() == MultiPoint.class) {geom = convertJTSMultiPoint((MultiPoint) jtsGeom);} else if (jtsGeom.getClass() == LineString.class) {geom = convertJTSLineString((LineString) jtsGeom);} else if (jtsGeom.getClass() == LinearRing.class) {geom = convertJTSLinearRing((LinearRing) jtsGeom);} else if (jtsGeom.getClass() == MultiLineString.class) {geom = convertJTSMultiLineString((MultiLineString) jtsGeom);} else if (jtsGeom.getClass() == Polygon.class) {geom = convertJTSPolygon((Polygon) jtsGeom);} else if (jtsGeom.getClass() == MultiPolygon.class) {geom = convertJTSMultiPolygon((MultiPolygon) jtsGeom);}if (geom != null)try {return JGeometry.store(geom, connection);} catch (SQLException e) {throw new HibernateSpatialException("Problem during conversion from JTS to JGeometry", e);}elsethrow new UnsupportedOperationException("Conversion of "+ jtsGeom.getClass().getSimpleName()+ " to PGgeometry not supported");}private JGeometry convertJTSMultiPolygon(MultiPolygon polygon) {// TODO implement thisthrow new UnsupportedOperationException("Not yet implemented");}private JGeometry convertJTSPolygon(Polygon polygon) {int dim = getCoordDimension(polygon);Object[] coords = convertCoordinateArrays(convertGeometryToCoordArrays(polygon), dim);return JGeometry.createLinearPolygon(coords, dim, polygon.getSRID());}private JGeometry convertJTSMultiLineString(MultiLineString multiLineString) {int dim = getCoordDimension(multiLineString);Object[] coords = convertCoordinateArrays(convertGeometryToCoordArrays(multiLineString), dim);return JGeometry.createLinearMultiLineString(coords, dim,multiLineString.getSRID());}private JGeometry convertJTSLinearRing(LinearRing ring) {return convertJTSLineString(ring);}private JGeometry convertJTSLineString(LineString lineString) {int dim = getCoordDimension(lineString);double[] coords = convertCoordinates(lineString.getCoordinates(), dim);return JGeometry.createLinearLineString(coords, dim, lineString.getSRID());}private JGeometry convertJTSMultiPoint(MultiPoint multiPoint) {int dim = getCoordDimension(multiPoint);Object[] coords = convertCoordinateArrays(convertGeometryToCoordArrays(multiPoint), dim);return JGeometry.createMultiPoint(coords, dim, multiPoint.getSRID());}private JGeometry convertJTSPoint(Point jtsGeom) {int dim = getCoordDimension(jtsGeom);double[] coord = convertCoordinates(jtsGeom.getCoordinates(), dim);return JGeometry.createPoint(coord, dim, jtsGeom.getSRID());}private double[] convertCoordinates(Coordinate[] coordinates, int dim) {if (dim < 2 || dim > 3)throw new IllegalArgumentException("Dim parameter value must be between 2 and 3");double[] converted = new double[coordinates.length * dim];for (int i = 0; i < coordinates.length; i++) {converted[i * dim] = coordinates[i].x;converted[i * dim + 1] = coordinates[i].y;if (dim == 3)converted[i * dim + 2] = coordinates[i].z;}return converted;}/*** @param coordinateArrays* array of Coordinate arrays* @param dim* -dimension of the coordinates* @return*/private Object[] convertCoordinateArrays(Object[] coordinateArrays, int dim) {Object[] converted = new Object[coordinateArrays.length];for (int i = 0; i < coordinateArrays.length; i++) {Coordinate[] coordinates = (Coordinate[]) (coordinateArrays[i]);converted[i] = convertCoordinates(coordinates, dim);}return converted;}private Object[] convertGeometryToCoordArrays(Geometry geom) {if (geom.getClass() == MultiPoint.class|| geom.getClass() == MultiLineString.class) {Object[] arr = new Object[geom.getNumGeometries()];for (int i = 0; i < arr.length; i++) {arr[i] = geom.getGeometryN(i).getCoordinates();}return arr;} else if (geom.getClass() == Polygon.class) {Polygon poly = (Polygon) geom;Object[] arr = new Object[poly.getNumInteriorRing() + 1];Coordinate[] outer = poly.getExteriorRing().getCoordinates();// For Oracle Spatial, outer ring must be counter clockwiseif (!CGAlgorithms.isCCW(outer))arr[0] = reverseRing(outer);elsearr[0] = outer;for (int i = 0; i < poly.getNumInteriorRing(); i++) {Coordinate[] inner = poly.getInteriorRingN(i).getCoordinates();if (CGAlgorithms.isCCW(inner))arr[i + 1] = reverseRing(inner);elsearr[i + 1] = inner;}return arr;} elsethrow new IllegalArgumentException("geom must of of type MultiPoint, MultiLineString or Polygon");}@Overridepublic Geometry convert2JTS(Object geomObj) {if (geomObj == null)return null;JGeometry jgeom;try {jgeom = JGeometry.load((STRUCT) geomObj);} catch (SQLException e) {throw new HibernateSpatialException("Error loading Oracle Spatial Geometry Object", e);}if (jgeom.getDimensions() > 3 || jgeom.isLRSGeometry())throw new UnsupportedOperationException("Cannot handle LRS Geometries, or geometries with more than 3 dimensions");Geometry jtsGeom = null;if (jgeom.getType() == JGeometry.GTYPE_POINT) {double[] ordinates = jgeom.getOrdinatesArray();if (ordinates == null)ordinates = jgeom.getPoint();CoordinateSequence cs = convertOrdinateArray(jgeom.getOrdinatesArray(), jgeom.getDimensions());jtsGeom = geomFactory.createPoint(cs);jtsGeom.setSRID(jgeom.getSRID());} else if (jgeom.getType() == JGeometry.GTYPE_MULTIPOINT) {CoordinateSequence cs = convertOrdinateArray(jgeom.getOrdinatesArray(), jgeom.getDimensions());jtsGeom = geomFactory.createMultiPoint(cs);jtsGeom.setSRID(jgeom.getSRID());} else if (jgeom.getType() == JGeometry.GTYPE_CURVE) {ElemInfo elem = new ElemInfo();elem.parse(jgeom.getOrdinatesArray(), jgeom.getElemInfo(), jgeom.getDimensions());jtsGeom = createLineString(elem, jgeom.getDimensions(), jgeom.getSRID());} else if (jgeom.getType() == JGeometry.GTYPE_MULTICURVE) {ElemInfo elem = new ElemInfo();elem.parse(jgeom.getOrdinatesArray(), jgeom.getElemInfo(), jgeom.getDimensions());LineString[] linestrings = new LineString[elem.getNumElems()];for (int i = 0; elem != null; elem = elem.getNext(), i++) {linestrings[i] = createLineString(elem, jgeom.getDimensions(),jgeom.getSRID());}jtsGeom = geomFactory.createMultiLineString(linestrings);jtsGeom.setSRID(jgeom.getSRID());} else if (jgeom.getType() == JGeometry.GTYPE_POLYGON) {ElemInfo elem = new ElemInfo();elem.parse(jgeom.getOrdinatesArray(), jgeom.getElemInfo(), jgeom.getDimensions());jtsGeom = createPolygon(elem, jgeom.getDimensions(), jgeom.getSRID());} else if (jgeom.getType() == JGeometry.GTYPE_MULTIPOLYGON) {ElemInfo elem = new ElemInfo();elem.parse(jgeom.getOrdinatesArray(), jgeom.getElemInfo(), jgeom.getDimensions());ElemInfo[] polyElems = elem.toPolyElems();Polygon[] polygons = new Polygon[polyElems.length];for (int i = 0; i < polyElems.length; i++) {polygons[i] = createPolygon(polyElems[i], jgeom.getDimensions(), jgeom.getSRID());}jtsGeom = geomFactory.createMultiPolygon(polygons);jtsGeom.setSRID(jgeom.getSRID());} else {throw new IllegalArgumentException("Unsupported JGeometry type");}return jtsGeom;}private Polygon createPolygon(ElemInfo elem, int dimensions, int srid) {LinearRing shell = null;LinearRing[] holes = null;int idxInteriorRings = 0;LinearRing[] rings = new LinearRing[elem.getNumElems()];for (int i = 0; i < rings.length; i++) {if (elem.getElementType() == ElementTypes.INTERIOR_RING_ARC_SEGMENTS|| elem.getElementType() == ElementTypes.INTERIOR_RING_CIRCLE|| elem.getElementType() == ElementTypes.INTERIOR_RING_RECT|| elem.getElementType() == ElementTypes.INTERIOR_RING_STRAIGHT_SEGMENTS) {rings[idxInteriorRings] = createRing(elem, dimensions);rings[idxInteriorRings].setSRID(srid);idxInteriorRings++;} else {if (shell != null)break;shell = createRing(elem, dimensions);shell.setSRID(srid);}elem = elem.getNext();}holes = new LinearRing[idxInteriorRings];System.arraycopy(rings, 0, holes, 0, idxInteriorRings);Polygon polygon = geomFactory.createPolygon(shell, holes);polygon.setSRID(srid);return polygon;}private LinearRing createRing(ElemInfo elem, int dim) {CoordinateSequence cs = convertOrdinateArray(elem.getOrdinates(), dim);// if the element is a rectangle, than complete the ringif (elem.getElementType() == ElementTypes.EXTERIOR_RING_RECT|| elem.getElementType() == ElementTypes.INTERIOR_RING_RECT) {Coordinate ll = cs.getCoordinate(0);Coordinate ur = cs.getCoordinate(1);Coordinate lr = new Coordinate(ur.x, ll.y);Coordinate ul = new Coordinate(ll.x, ur.y);cs = geomFactory.getCoordinateSequenceFactory().create(new Coordinate[] { ll, lr, ur, ul, ll });}LinearRing ring = geomFactory.createLinearRing(cs);return ring;}private LineString createLineString(ElemInfo elem, int dim, int SRID) {CoordinateSequence cs = convertOrdinateArray(elem.getOrdinates(), dim);LineString ls = geomFactory.createLineString(cs);ls.setSRID(SRID);return ls;}private CoordinateSequence convertOrdinateArray(double[] oordinates,int dim) {Coordinate[] coordinates = new Coordinate[oordinates.length / dim];for (int i = 0; i < coordinates.length; i++) {if (dim == 2)coordinates[i] = new Coordinate(oordinates[i * dim],oordinates[i * dim + 1]);else if (dim == 3)coordinates[i] = new Coordinate(oordinates[i * dim],oordinates[i * dim + 1], oordinates[i * dim + 2]);}return geomFactory.getCoordinateSequenceFactory().create(coordinates);}private int getCoordDimension(Geometry jtsGeom) {Coordinate cd = jtsGeom.getCoordinate();if (cd != null && !Double.isNaN(cd.z))return 3;elsereturn 2;}// reverses ordinates in a coordinate array in-placeprivate Coordinate[] reverseRing(Coordinate[] ar) {for (int i = 0; i < ar.length / 2; i++) {Coordinate cs = ar[i];ar[i] = ar[ar.length - 1 - i];ar[ar.length - 1 - i] = cs;}return ar;}@Overridepublic int[] sqlTypes() {return geometryTypes;}private static class ElementTypes {public static int UNSUPPORTED = 0;public static int POINT = 1;public static int ORIENTATION = 2;public static int POINT_CLUSTER = 3;public static int LINE_STRAITH_SEGMENTS = 4;public static int LINE_ARC_SEGMENTS = 5;public static int INTERIOR_RING_STRAIGHT_SEGMENTS = 6;public static int EXTERIOR_RING_STRAIGHT_SEGMENTS = 7;public static int INTERIOR_RING_ARC_SEGMENTS = 8;public static int EXTERIOR_RING_ARC_SEGMENTS = 9;public static int INTERIOR_RING_RECT = 10;public static int EXTERIOR_RING_RECT = 11;public static int INTERIOR_RING_CIRCLE = 12;public static int EXTERIOR_RING_CIRCLE = 13;public static int COMPOUND_LINE = 14;public static int COMPOUND_EXTERIOR_RING = 15;public static int COMPOUND_INTERIOR_RING = 16;}/*** @author Karel Maesen*** represents a simplified view on the Elements in an SDO_Geometry. Circular* segments are all linearized, and compound elements combined into a single* element with all segments linearized.**/private class ElemInfo {private double[] linearOrdinates = null;private int elementType = -1;// used for compound elements;private int numCompounds = 0;// used for point clustersprivate int numPoints = 0;private ElemInfo next = null;protected int dimension = 2;protected void setDimension(int dim) {this.dimension = dim;}private boolean isExteriorRing() {if (getElementType() == ElementTypes.EXTERIOR_RING_ARC_SEGMENTS|| getElementType() == ElementTypes.EXTERIOR_RING_CIRCLE|| getElementType() == ElementTypes.EXTERIOR_RING_RECT|| getElementType() == ElementTypes.EXTERIOR_RING_STRAIGHT_SEGMENTS) {return true;} elsereturn false;}private int getNumExteriorRings() {ElemInfo elem = this;int cnt = 0;while (elem != null) {if (elem.isExteriorRing())cnt++;elem = elem.getNext();}return cnt;}/*** This splits the ElemInfo into an array of ElemInfo's, each pertaining* to exactly one polygon** @return*/public ElemInfo[] toPolyElems() {if (getNumExteriorRings() == 0) {throw new IllegalStateException("toPolyElems() should only be invoked on Polygon ElemInfo's");} else if (getNumExteriorRings() == 1) {return new ElemInfo[] { this };} else {// For multipolygons, the//ElemInfo elem = this;ElemInfo[] polyElems = new ElemInfo[getNumExteriorRings()];int pIdx = 0;while (elem != null) {if (elem.isExteriorRing()) {polyElems[pIdx++] = elem;}elem = elem.getNext();}// strip beyond next Exterior Ringfor (int i = 0; i < polyElems.length; i++) {ElemInfo pe = polyElems[i];while (pe.getNext() != null) {if (pe.getNext().isExteriorRing()) {pe.setNextElemInfo(null);break;}pe = pe.getNext();}}return polyElems;}}protected void setLinearOrdinates(double[] ordinates) {this.linearOrdinates = ordinates;}protected void setElementType(int type) {this.elementType = type;}protected void setNumCompounds(int num) {this.numCompounds = num;}protected void setNumPoints(int num) {this.numPoints = num;}protected void setNextElemInfo(ElemInfo elemInfo) {this.next = elemInfo;}public void parse(double[] ordinates, int[] elemInfo, int dim) {this.dimension = dim;if (ordinates.length == 0 || elemInfo.length == 0)return;int numOrdinates = 0;if (elemInfo[1] == 0)elementType = ElementTypes.UNSUPPORTED;else if (elemInfo[1] == 1 && elemInfo[2] == 1) {elementType = ElementTypes.POINT;linearOrdinates = getElemOrdinates(ordinates, elemInfo, 0, dim);numOrdinates = linearOrdinates.length;} else if (elemInfo[1] == 1 && elemInfo[2] == 0) {elementType = ElementTypes.ORIENTATION;linearOrdinates = getElemOrdinates(ordinates, elemInfo, 0, dim);numOrdinates = linearOrdinates.length;} else if (elemInfo[1] == 1 && elemInfo[2] > 1) {elementType = ElementTypes.POINT_CLUSTER;linearOrdinates = getElemOrdinates(ordinates, elemInfo, 0, dim);numPoints = elemInfo[2];numOrdinates = linearOrdinates.length;} else if (elemInfo[1] == 2 && elemInfo[2] == 1) {elementType = ElementTypes.LINE_STRAITH_SEGMENTS;linearOrdinates = getElemOrdinates(ordinates, elemInfo, 0, dim);numOrdinates = linearOrdinates.length;} else if (elemInfo[1] == 2 && elemInfo[2] == 2) {elementType = ElementTypes.LINE_ARC_SEGMENTS;double[] arcOrdinates = getElemOrdinates(ordinates, elemInfo,0, dim);numOrdinates = arcOrdinates.length;linearOrdinates = linearize(arcOrdinates, dim);} else if (elemInfo[1] == 1003 && elemInfo[2] == 1) {elementType = ElementTypes.EXTERIOR_RING_STRAIGHT_SEGMENTS;linearOrdinates = getElemOrdinates(ordinates, elemInfo, 0, dim);numOrdinates = linearOrdinates.length;} else if (elemInfo[1] == 2003 && elemInfo[2] == 1) {elementType = ElementTypes.INTERIOR_RING_STRAIGHT_SEGMENTS;linearOrdinates = getElemOrdinates(ordinates, elemInfo, 0, dim);numOrdinates = linearOrdinates.length;} else if (elemInfo[1] == 1003 && elemInfo[2] == 2) {elementType = ElementTypes.EXTERIOR_RING_ARC_SEGMENTS;double[] arcOrdinates = getElemOrdinates(ordinates, elemInfo,0, dim);numOrdinates = arcOrdinates.length;linearOrdinates = linearize(arcOrdinates, dim);} else if (elemInfo[1] == 2003 && elemInfo[2] == 2) {elementType = ElementTypes.INTERIOR_RING_ARC_SEGMENTS;double[] arcOrdinates = getElemOrdinates(ordinates, elemInfo,0, dim);numOrdinates = arcOrdinates.length;linearOrdinates = linearize(arcOrdinates, dim);} else if (elemInfo[1] == 1003 && elemInfo[2] == 3) {elementType = ElementTypes.EXTERIOR_RING_RECT;linearOrdinates = getElemOrdinates(ordinates, elemInfo, 0, dim);numOrdinates = linearOrdinates.length;} else if (elemInfo[1] == 2003 && elemInfo[2] == 3) {elementType = ElementTypes.INTERIOR_RING_RECT;linearOrdinates = getElemOrdinates(ordinates, elemInfo, 0, dim);numOrdinates = linearOrdinates.length;} else if (elemInfo[1] == 1003 && elemInfo[2] == 4) {elementType = ElementTypes.EXTERIOR_RING_CIRCLE;double[] arcOrdinates = getElemOrdinates(ordinates, elemInfo,0, dim);numOrdinates = arcOrdinates.length;linearOrdinates = linearize(arcOrdinates, dim);} else if (elemInfo[1] == 2003 && elemInfo[2] == 4) {elementType = ElementTypes.INTERIOR_RING_CIRCLE;double[] arcOrdinates = getElemOrdinates(ordinates, elemInfo,0, dim);numOrdinates = arcOrdinates.length;linearOrdinates = linearize(arcOrdinates, dim);} else if (elemInfo[1] == 4) {elementType = ElementTypes.COMPOUND_LINE;numCompounds = elemInfo[2];double[] cmpOrdinates = getElemOrdinates(ordinates, elemInfo,numCompounds, dim);numOrdinates = cmpOrdinates.length;int[] cmpElemInfo = getCompoundElemInfo(elemInfo, numCompounds);CElemInfo celemInfo = new CElemInfo();celemInfo.parse(cmpOrdinates, cmpElemInfo, dim);linearOrdinates = celemInfo.flattenOrdinates();} else if (elemInfo[1] == 1005) {elementType = ElementTypes.COMPOUND_EXTERIOR_RING;numCompounds = elemInfo[2];double[] cmpOrdinates = getElemOrdinates(ordinates, elemInfo,numCompounds, dim);numOrdinates = cmpOrdinates.length;int[] cmpElemInfo = getCompoundElemInfo(elemInfo, numCompounds);CElemInfo celemInfo = new CElemInfo();celemInfo.parse(cmpOrdinates, cmpElemInfo, dim);linearOrdinates = celemInfo.flattenOrdinates();} else if (elemInfo[1] == 1005) {elementType = ElementTypes.COMPOUND_INTERIOR_RING;numCompounds = elemInfo[2];double[] cmpOrdinates = getElemOrdinates(ordinates, elemInfo,numCompounds, dim);numOrdinates = cmpOrdinates.length;int[] cmpElemInfo = getCompoundElemInfo(elemInfo, numCompounds);CElemInfo celemInfo = new CElemInfo();celemInfo.parse(cmpOrdinates, cmpElemInfo, dim);linearOrdinates = celemInfo.flattenOrdinates();} elsethrow new IllegalArgumentException("Can't convert ELEM_INFO to type");if (!(ordinates.length == numOrdinates)) {int[] tailElemInfo = new int[elemInfo.length- (3 * (numCompounds + 1))];System.arraycopy(elemInfo, 3 * (numCompounds + 1),tailElemInfo, 0, tailElemInfo.length);ordinates = getTailOrdinates(ordinates, numOrdinates);elemInfo = tailElemInfo;next = createNextElemInfo();next.parse(ordinates, elemInfo, dim);}}protected double[] getTailOrdinates(double[] ordinates,int numOrdinates) {double[] tailOrdinates = new double[ordinates.length- numOrdinates];System.arraycopy(ordinates, numOrdinates, tailOrdinates, 0,tailOrdinates.length);return tailOrdinates;}protected int[] getTailElemInfo(int[] elemInfo, int compounds) {int[] tailElemInfo = new int[elemInfo.length- (3 * (numCompounds + 1))];System.arraycopy(elemInfo, 3 * (numCompounds + 1), tailElemInfo,0, tailElemInfo.length);return tailElemInfo;}protected ElemInfo createNextElemInfo() {return new ElemInfo();}protected double[] getElemOrdinates(double[] ordinates,int[] elemInfo, int numCompounds, int dim) {int numOrdinates = 0;if (elemInfo.length == (3 * (numCompounds + 1))) {numOrdinates = ordinates.length;return ordinates;} else {numOrdinates = elemInfo[3 * (numCompounds + 1)] - elemInfo[0];double[] elemOrdinates = new double[numOrdinates];System.arraycopy(ordinates, 0, elemOrdinates, 0,elemOrdinates.length);return elemOrdinates;}}protected int[] getCompoundElemInfo(int[] elemInfo, int numCompounds) {int infoArraySize = 3;int startOffset = 0;if (numCompounds > 0) {infoArraySize = 3 * numCompounds;startOffset = 3;}int[] celemInfo = new int[infoArraySize];System.arraycopy(elemInfo, startOffset, celemInfo, 0,celemInfo.length);return celemInfo;}private double[] linearize(double[] arcOrdinates, int dim) {int numOrd = 2;double[] linearizedCoords = new double[0];// this only works with 2-Dimensional geometries, since we use// JGeometry linearization;if (dim != 2)throw new IllegalArgumentException("Can only linearize 2D arc segments, but geometry is "+ dim + "D.");while (numOrd < arcOrdinates.length) {numOrd -= 2; // start point of next arc segment is end point// of previous segment, and is not repeated.double x1 = arcOrdinates[numOrd++];double y1 = arcOrdinates[numOrd++];double x2 = arcOrdinates[numOrd++];double y2 = arcOrdinates[numOrd++];double x3 = arcOrdinates[numOrd++];double y3 = arcOrdinates[numOrd++];double[] result = JGeometry.linearizeArc(x1, y1, x2, y2, x3,y3);// if this is not the first arcsegment, the first linearized// point is already in linearizedArc, so disregard this.int resultBegin = 2;if (linearizedCoords.length == 0)resultBegin = 0;int destPos = linearizedCoords.length;double[] tmpCoords = new double[linearizedCoords.length+ result.length - resultBegin];System.arraycopy(linearizedCoords, 0, tmpCoords, 0,linearizedCoords.length);System.arraycopy(result, resultBegin, tmpCoords, destPos,result.length - resultBegin);linearizedCoords = tmpCoords;}// garuantee that first and last oordinate pairs of the// linearizedOrdinates are exactly the same as in input ArcOrdinates// This is neede because JGeometry linearization "bruises"// coordinates// which causes problems in case of linear rings.linearizedCoords[0] = arcOrdinates[0];linearizedCoords[1] = arcOrdinates[1];linearizedCoords[linearizedCoords.length - 1] = arcOrdinates[arcOrdinates.length - 1];linearizedCoords[linearizedCoords.length - 2] = arcOrdinates[arcOrdinates.length - 2];return linearizedCoords;}public double[] getOrdinates() {return linearOrdinates;}public int getElementType() {return elementType;}public int getNumCompounts() {return numCompounds;}public int getNumPoints() {return numPoints;}public ElemInfo getNext() {return next;}public int getNumElems() {int cnt = 0;for (ElemInfo elem = this; elem != null; elem = elem.getNext(), cnt++);return cnt;}}private class CElemInfo extends ElemInfo {public CElemInfo() {super();}protected ElemInfo createNextElemInfo() {return new CElemInfo();}// subelements of a compound element are contiguous. Thefore// we include the first coordinate of the next subelement.protected double[] getElemOrdinates(double[] ordinates,int[] elemInfo, int numCompounds, int dim) {if (elemInfo.length == (3 * (numCompounds + 1))) {return ordinates;} else {// numOrdinates includes first ordinate of next subelement, if// there is oneint numOrdinates = elemInfo[3 * (numCompounds + 1)]- elemInfo[0] + dim;double[] elemOrdinates = new double[numOrdinates];System.arraycopy(ordinates, 0, elemOrdinates, 0,elemOrdinates.length);return elemOrdinates;}}protected double[] getTailOrdinates(double[] ordinates,int numOrdinates) {double[] tailOrdinates = new double[ordinates.length- numOrdinates + this.dimension];if (numOrdinates < ordinates.length)System.arraycopy(ordinates, numOrdinates - this.dimension,tailOrdinates, 0, tailOrdinates.length);elseSystem.arraycopy(ordinates, numOrdinates, tailOrdinates, 0,tailOrdinates.length);return tailOrdinates;}protected double[] flattenOrdinates() {ElemInfo elem = this;double[] ordinates = new double[elem.getOrdinates().length];System.arraycopy(elem.getOrdinates(), 0, ordinates, 0, this.getOrdinates().length);int nextStartPos = ordinates.length;while (elem.getNext() != null) {elem = elem.getNext();int nextOrdinateArraySize = elem.getOrdinates().length- dimension;double[] newArray = new double[ordinates.length+ nextOrdinateArraySize];System.arraycopy(ordinates, 0, newArray, 0, ordinates.length);System.arraycopy(elem.getOrdinates(), dimension, newArray,nextStartPos, nextOrdinateArraySize);ordinates = newArray;nextStartPos = ordinates.length;}return ordinates;}}}