/* XXL: The eXtensible and fleXible Library for data processing Copyright (C) 2000-2011 Prof. Dr. Bernhard Seeger Head of the Database Research Group Department of Mathematics and Computer Science University of Marburg Germany 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 3 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 <http://www.gnu.org/licenses/>. http://code.google.com/p/xxl/ */ package xxl.connectivity.jts; import java.util.Collection; import xxl.core.spatial.geometries.Geometry2DException; import xxl.core.spatial.points.DoublePoint; import xxl.core.spatial.points.FloatPoint; import xxl.core.spatial.points.Point; import xxl.core.spatial.rectangles.DoublePointRectangle; import xxl.core.spatial.rectangles.FloatPointRectangle; import xxl.core.spatial.rectangles.Rectangle; import xxl.core.util.WrappingRuntimeException; import com.vividsolutions.jts.geom.Coordinate; import com.vividsolutions.jts.geom.Envelope; 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.Polygon; import com.vividsolutions.jts.geom.PrecisionModel; import com.vividsolutions.jts.io.WKBReader; import com.vividsolutions.jts.io.WKTReader; import com.vividsolutions.jts.util.GeometricShapeFactory; /** This class contains some static-methods for the creation of new <code>Geometry2D</code>-objects * and the conversion between different types of geometrical representations available in XXL. * * @see xxl.core.spatial.rectangles * @see xxl.core.spatial.points * @see xxl.core.spatial.geometries * @see xxl.connectivity.jts */ public class Geometry2DFactory { /** There's no need to instantiate this class */ private Geometry2DFactory(){} /** A static reference to the JTS-Double-Precision-Model */ public static PrecisionModel DOUBLE_PRECISIONMODEL = new PrecisionModel(PrecisionModel.FLOATING); /** A static reference to the JTS-Float-Precision-Model */ public static PrecisionModel FLOAT_PRECISIONMODEL = new PrecisionModel(PrecisionModel.FLOATING_SINGLE); /* some private static references used inside this class */ private static GeometryFactory DOUBLE_GEOMETRYFACTORY = new GeometryFactory(DOUBLE_PRECISIONMODEL); private static GeometryFactory FLOAT_GEOMETRYFACTORY = new GeometryFactory(FLOAT_PRECISIONMODEL); private static WKBReader DOUBLE_WKB_READER = new WKBReader(DOUBLE_GEOMETRYFACTORY); private static WKBReader FLOAT_WKB_READER = new WKBReader(FLOAT_GEOMETRYFACTORY); private static WKTReader DOUBLE_WKT_READER = new WKTReader(DOUBLE_GEOMETRYFACTORY); private static WKTReader FLOAT_WKT_READER = new WKTReader(FLOAT_GEOMETRYFACTORY); /* some private help-methods used inside this class */ private static Coordinate pointToCoordinate(xxl.core.spatial.points.Point point){ if(point.dimensions()<2 || point.dimensions() > 3) throw new Geometry2DException("Cannot converert point:"+point); return new Coordinate(point.getValue(0), point.getValue(1), point.dimensions()>2 ? point.getValue(2) : Double.NaN); } private static boolean isFloat(PrecisionModel p){ return p.isFloating() && p.getMaximumSignificantDigits()==6; } private static boolean isDouble(PrecisionModel p){ return p.isFloating() && p.getMaximumSignificantDigits()==16; } private static GeometryFactory getGeometryFactory(PrecisionModel p){ return isDouble(p) ? DOUBLE_GEOMETRYFACTORY : isFloat(p) ? FLOAT_GEOMETRYFACTORY : new GeometryFactory(p); } /** This method wraps the given JTS-<code>Geometry</code> in the appropriate * <code>Geometry2DAdapter</code> subclass. * @param geometry the <code>Geometry</code> to wrap or <code>null</code> * @return an object of the appropriate <code>Geometry2DAdapter</code> subclass * or the empty Geometry if <code>geometry == null</code> */ public static Geometry2DAdapter wrap(Geometry geometry){ if(geometry == null) throw new Geometry2DException("Null value not allowed!"); final String geometryType = geometry.getGeometryType(); if(geometryType.equals("Point")) return new Point2DAdapter((com.vividsolutions.jts.geom.Point)geometry); if(geometryType.equals("MultiPoint")) return new MultiPoint2DAdapter((MultiPoint)geometry); if(geometryType.equals("LineString")) return (geometry.getNumPoints()>2 ? new LineString2DAdapter((LineString)geometry) : new Line2DAdapter((LineString) geometry)); if(geometryType.equals("LinearRing")) return new LineString2DAdapter((LinearRing)geometry); if(geometryType.equals("MultiLineString")) return new MultiLineString2DAdapter((MultiLineString)geometry); if(geometryType.equals("Polygon")) return new Polygon2DAdapter((Polygon)geometry); if(geometryType.equals("MultiPolygon")) return new MultiPolygon2DAdapter((MultiPolygon)geometry); if(geometryType.equals("GeometryCollection")) return new GeometryCollection2DAdapter<Geometry2DAdapter>((GeometryCollection)geometry); throw new IllegalArgumentException(); // should never reach here } /** Reads a JTS-<code>Geometry</code> from its Well- Known Binary- Representation and wraps * it in the appropriate <code>Geometry2DAdapter</code> subclass. * @param wkb the Well Known Binary Representation of the <code>Geometry</code> * @return an object of the appropriate <code>Geometry2DAdapter</code> subclass */ public static Geometry2DAdapter createFromWKB(byte[] wkb) { return createFromWKB(wkb, DOUBLE_PRECISIONMODEL); } /** Reads a JTS-<code>Geometry</code> from its Well- Known Binary- Representation and wraps * it in the appropriate <code>Geometry2DAdapter</code> subclass. * @param wkb the Well Known Binary Representation of the <code>Geometry</code> * @param p the <code>PrecisionModel</code> of the returned <code>Geometry2DAdapter</code> * @return an object of the appropriate <code>Geometry2DAdapter</code> subclass */ public static Geometry2DAdapter createFromWKB(byte[] wkb, PrecisionModel p) { try {WKBReader reader = isDouble(p) ? DOUBLE_WKB_READER : isFloat(p) ? FLOAT_WKB_READER : new WKBReader( new GeometryFactory(p) ); return Geometry2DFactory.wrap( reader.read(wkb) ); } catch ( Exception e) { throw new WrappingRuntimeException(e); } } /** Reads a JTS-<code>Geometry</code> from its Well- Known Text- Representation and wraps * it in the appropriate <code>Geometry2DAdapter</code> subclass. * @param wkt the Well Known Binary Representation of the <code>Geometry</code> * @return an object of the appropriate <code>Geometry2DAdapter</code> subclass */ public static Geometry2DAdapter createFromWKT(String wkt) { return createFromWKT(wkt, DOUBLE_PRECISIONMODEL); } /** Reads a JTS-<code>Geometry</code> from its Well- Known Text- Representation and wraps * it in the appropriate <code>Geometry2DAdapter</code> subclass. * @param wkt the Well Known Binary Representation of the <code>Geometry</code> * @param p the <code>PrecisionModel</code> of the returned <code>Geometry2DAdapter</code> * @return an object of the appropriate <code>Geometry2DAdapter</code> subclass */ public static Geometry2DAdapter createFromWKT(String wkt, PrecisionModel p) { try { WKTReader reader = isDouble(p) ? DOUBLE_WKT_READER : isFloat(p) ? FLOAT_WKT_READER : new WKTReader( getGeometryFactory(p)); return Geometry2DFactory.wrap ( reader.read(wkt) ); } catch ( Exception e) { throw new WrappingRuntimeException(e); } } /** Converts the given JTS- Envelope- object to the corresponding {@link DoublePointRectangle} * @param e the <code>Envelope</code>-object to convert * @return the corresponding XXL-<code>DoublePointRectangle</code> */ public static Rectangle envelopeToXXLRectangle(Envelope e){ return envelopeToXXLRectangle(e, true); } /** Converts the given JTS- Envelope- object to the corresponding XXl-<code>Rectangle</code> * The precise result-type can be specified (either {@link DoublePointRectangle} or {@link FloatPointRectangle}) * @param e the <code>Envelope</code>-object to convert * @param returnDoublePointRectangle determines whether a {@link DoublePointRectangle} or a {@link FloatPointRectangle} is returned * @return the corresponding XXL-<code>Rectangle</code> */ public static Rectangle envelopeToXXLRectangle(Envelope e, boolean returnDoublePointRectangle){ if( returnDoublePointRectangle ) return new DoublePointRectangle( new double[]{e.getMinX(), e.getMinY()}, new double[]{e.getMaxX(), e.getMaxY()} ); return new FloatPointRectangle( new float[]{(float) e.getMinX(), (float) e.getMinY()}, new float[]{(float) e.getMaxX(), (float) e.getMaxY()} ); } /** Converts the given JTS- Envelope- object to the corresponding Geometry2D-class ({@link Polygon2DAdapter}). * @param e the <code>Envelope</code>-object to convert * @return the corresponding {@link Polygon2DAdapter}-object */ public static Polygon2DAdapter envelopeToPolygon(Envelope e){ return createRectangle(e.centre(),e.getWidth(),e.getHeight(), DOUBLE_PRECISIONMODEL); } /** Converts the given JTS- Envelope- object to the corresponding Geometry2D-class ({@link Polygon2DAdapter}). * @param e the <code>Envelope</code>-object to convert * @param precision the <code>PrecisionModel</code> of the returned <code>Polygon2DAdapter</code> * @return the corresponding {@link Polygon2DAdapter}-object */ public static Polygon2DAdapter envelopeToPolygon(Envelope e, PrecisionModel precision){ return createRectangle(e.centre(),e.getWidth(),e.getHeight(), precision); } /** Converts the given XXL-Rectangle to the corresponding <tt>Polygon2DAdapter</tt>-object * @param rectangle the rectangle to convert * @return the <tt>Polygon2DAdapter</tt>-object corresponding to the input-rectangle */ public static Polygon2DAdapter xxlRectangleToPolygon2D(Rectangle rectangle){ return createRectangle( xxlPointToPoint2D(rectangle.getCorner(false)), xxlPointToPoint2D( rectangle.getCorner(true)) ); } /** Converts the given XXL-Rectangle to the corresponding <tt>Polygon2DAdapter</tt>-object * @param rectangle the rectangle to convert * @param precision the <code>PrecisionModel</code> of the returned <code>Polygon2DAdapter</code> * @return the <tt>Polygon2DAdapter</tt>-object corresponding to the input-rectangle */ public static Polygon2DAdapter xxlRectangleToPolygon2D(Rectangle rectangle, PrecisionModel precision){ return createRectangle( xxlPointToPoint2D(rectangle.getCorner(false)), xxlPointToPoint2D(rectangle.getCorner(true)), precision); } /** Converts the given XXL-Point to the corresponding <tt>Point2DAdapter</tt>-object * @param point the XXL-Point to convert * @return the <tt>Point2DAdapter</tt>-object corresponding to the input-point */ public static Point2DAdapter xxlPointToPoint2D(Point point){ return xxlPointToPoint2D(point, DOUBLE_PRECISIONMODEL); } /** Converts the given XXL-Point to the corresponding <tt>Point2DAdapter</tt>-object * @param point the XXL-Point to convert * @param precision the <code>PrecisionModel</code> of the returned <code>Point2DAdapter</code> * @return the <tt>Point2DAdapter</tt>-object corresponding to the input-point */ public static Point2DAdapter xxlPointToPoint2D(Point point, PrecisionModel precision){ return createPoint( pointToCoordinate(point), precision); } /** Converts the given <code>Point2DAdapter</code>-object to the corresponding {@link FloatPoint} * @param point the <code>Point2DAdapter</code> to convert * @return the <tt>FloatPoint</tt>-object corresponding to the input-<code>Point2DAdapter</code> */ public static Point point2DToXXLPoint(Point2DAdapter point){ return point2DToXXLPoint(point, true); } /** Converts the given <code>Point2DAdapter</code>-object to the corresponding XXL-{@link Point} * The precise result-type can be specified (either {@link DoublePoint} or {@link FloatPoint}) * @param point the <code>Point2DAdapter</code> to convert * @param returnDoublePoint determines whether a {@link DoublePoint} or a {@link FloatPoint} is returned * @return the <tt>FloatPoint</tt>-object corresponding to the input-<code>Point2DAdapter</code> */ public static Point point2DToXXLPoint(Point2DAdapter point, boolean returnDoublePoint){ Coordinate c = point.geometry.getCoordinate(); return returnDoublePoint ? new DoublePoint( c.z== Double.NaN ? new double[]{c.x, c.y} : new double[]{c.x, c.y, c.z} ) : new FloatPoint( c.z== Double.NaN ? new float[]{(float) c.x, (float) c.y} : new float[]{(float) c.x, (float) c.y, (float) c.z}); } /** A method to create a Point in 2D. * @param x the x-coordinate of the point created * @param y the y-coordinate of the point created * @return the new JTS-point wrapped in a <code>Point2DAdapter</code> */ public static Point2DAdapter createPoint(double x, double y){ return createPoint(new Coordinate(x,y),DOUBLE_PRECISIONMODEL ); } /** A method to create a Point in 3D. * @param x the x-coordinate of the point created * @param y the y-coordinate of the point created * @param z the z-coordinate of the point created * @return the new JTS-point wrapped in a <code>Point2DAdapter</code> */ public static Point2DAdapter createPoint(double x, double y, double z){ return createPoint(new Coordinate(x,y,z),DOUBLE_PRECISIONMODEL ); } /** A method to create a Point in 2D. The PrecisionModel of the new Point can be specified. * @param x the x-coordinate of the point created * @param y the y-coordinate of the point created * @param precision determines the PrecisionModel to use * @return the new JTS-point wrapped in a <code>Point2DAdapter</code> */ public static Point2DAdapter createPoint(double x, double y, PrecisionModel precision){ return createPoint(new Coordinate(x,y), precision); } /** A method to create a Point in 3D. The PrecisionModel of the new Point can be specified. * @param x the x-coordinate of the point created * @param y the y-coordinate of the point created * @param z the z-coordinate of the point created * @param precision the PrecisionModel to use * @return the new JTS-point wrapped in a <code>Point2DAdapter</code> */ public static Point2DAdapter createPoint(double x, double y, double z, PrecisionModel precision){ return createPoint(new Coordinate(x,y,z), precision); } /** Creates a Point from a JTS-{@link Coordinate}. * @param c the Coordinate to create the <code>Point2DAdapter</code>-object from * @param precision the <code>PrecisionModel</code> of the new <code>Point2DAdapter</code> * @return the new JTS-point wrapped in a <code>Point2DAdapter</code> */ public static Point2DAdapter createPoint(Coordinate c, PrecisionModel precision){ GeometryFactory gf = getGeometryFactory(precision); return new Point2DAdapter(gf.createPoint(c)); } /** Creates a rectangle using the given lower left und upper right corners. * By default the PrecisionModel used is set to Double-Precision. * * @param left the lower left corner of the rectangle * @param right the upper right corner of the rectangle * @return a double-precision rectangle specified by the given corners */ public static Polygon2DAdapter createRectangle(Point2DAdapter left, Point2DAdapter right){ GeometricShapeFactory gsf = new GeometricShapeFactory( DOUBLE_GEOMETRYFACTORY ); gsf.setBase(left.geometry.getCoordinate()); gsf.setWidth( right.getX() - left.getX()); gsf.setHeight( right.getY() - left.getY()); gsf.setNumPoints(4); return new Polygon2DAdapter(gsf.createRectangle()); } /** Creates a rectangle using the given lower left und upper right corners. * The PrecisionModel can be specified. * * @param left the lower left corner of the rectangle * @param right the upper right corner of the rectangle * @param precision the <code>PrecisionModel</code> of the returned <code>Polygon2DAdapter</code> * @return a double-precision rectangle specified by the given corners */ public static Polygon2DAdapter createRectangle(Point2DAdapter left, Point2DAdapter right, PrecisionModel precision){ GeometricShapeFactory gsf = new GeometricShapeFactory( getGeometryFactory(precision) ); gsf.setBase(left.geometry.getCoordinate()); gsf.setWidth( right.getX() - left.getX()); gsf.setHeight( right.getY() - left.getY()); gsf.setNumPoints(4); return new Polygon2DAdapter(gsf.createRectangle()); } /** Creates a rectangle using the given centre-point and the extensions in both dimensions. * By default the PrecisionModel is set to double-precision. * * @param centre the centre-point of the new rectangle * @param width the rectangle's extension on the x-axis * @param height the rectangle's extension on the y-axis * @return a double-precision rectangle specified by the given corners */ public static Polygon2DAdapter createRectangle(Point2DAdapter centre, double width, double height){ return createRectangle(centre.geometry.getCoordinate(), height, height, DOUBLE_PRECISIONMODEL); } /** Creates a rectangle using the given centre-point and the extensions in both dimensions. * By default the PrecisionModel is set to double-precision. * * @param centre the centre-point of the new rectangle * @param width the rectangle's extension on the x-axis * @param height the rectangle's extension on the y-axis * @param precision the <code>PrecisionModel</code> of the returned <code>Polygon2DAdapter</code> * @return a double-precision rectangle specified by the given corners */ public static Polygon2DAdapter createRectangle(Point2DAdapter centre, double width, double height, PrecisionModel precision){ return createRectangle(centre.geometry.getCoordinate(), height, height, precision); } private static Polygon2DAdapter createRectangle(Coordinate centre, double width, double height, PrecisionModel precision){ GeometricShapeFactory gsf = new GeometricShapeFactory( getGeometryFactory(precision) ); gsf.setCentre(centre); gsf.setWidth( width ); gsf.setHeight( height ); gsf.setNumPoints(4); return new Polygon2DAdapter(gsf.createRectangle()); } /** Creates an arc around the given centre-point using the specified radii. The arc is * linearly interpolated from the starting-angle <it>fromAngle</it> to the ending-angle * <it>toAngle</it> with the given number of base-points. * The <code>PrecisionModel</code> is set to double-precision. * @param centre the centre of the arc * @param radiusX the radius in x-direction * @param radiusY the radius in y-direction * @param fromAngle the starting-angle of the arc * @param toAngle the ending-angle * @param numPoints the number of interpolation points * @return a <code>LineString2DAdapter</code> representing the arc */ public static LineString2DAdapter createArc(Point2DAdapter centre, double radiusX, double radiusY, double fromAngle, double toAngle, int numPoints){ return createArc(centre, radiusX, radiusY, fromAngle, toAngle, numPoints, DOUBLE_PRECISIONMODEL); } /** Creates an arc around the given centre-point using the specified radii. The arc is * linearly interpolated from the starting-angle <it>fromAngle</it> to the ending-angle * <it>toAngle</it> with the given number of base-points. * The <code>PrecisionModel</code> can be specified. * @param centre the centre of the arc * @param radiusX the radius in x-direction * @param radiusY the radius in y-direction * @param fromAngle the starting-angle of the arc * @param toAngle the ending-angle * @param numPoints the number of interpolation points * @param precision the <code>PrecisionModel</code> to use * @return a <code>LineString2DAdapter</code> representing the arc */ public static LineString2DAdapter createArc(Point2DAdapter centre, double radiusX, double radiusY, double fromAngle, double toAngle, int numPoints, PrecisionModel precision){ GeometricShapeFactory gsf = new GeometricShapeFactory( getGeometryFactory(precision) ); gsf.setCentre( centre.geometry.getCoordinate() ); gsf.setWidth( radiusX * 2); gsf.setHeight( radiusY *2 ); gsf.setNumPoints(numPoints); return new LineString2DAdapter(gsf.createArc(fromAngle, toAngle)); } /** Creates an ellipse around the given centre-point using the specified radii. The ellipse is * linearly interpolated using the given number of base-points. * The <code>PrecisionModel</code> can be specified. * @param centre the centre of the ellipse * @param radiusX the radius in x-direction * @param radiusY the radius in y-direction * @param numPoints the number of interpolation points * @return a <code>Polygon2DAdapter</code> representing the ellipse */ public static Polygon2DAdapter createEllipse(Point2DAdapter centre, double radiusX, double radiusY, int numPoints){ return createEllipse(centre, radiusX, radiusY, numPoints, DOUBLE_PRECISIONMODEL ); } /** Creates an ellipse around the given centre-point using the specified radii. The ellipse is * linearly interpolated using the given number of base-points. * The <code>PrecisionModel</code> can be specified. * @param centre the centre of the ellipse * @param radiusX the radius in x-direction * @param radiusY the radius in y-direction * @param numPoints the number of interpolation points * @param precision the <code>PrecisionModel</code> to use * @return a <code>Polygon2DAdapter</code> representing the ellipse */ public static Polygon2DAdapter createEllipse(Point2DAdapter centre, double radiusX, double radiusY, int numPoints, PrecisionModel precision){ GeometricShapeFactory gsf = new GeometricShapeFactory( getGeometryFactory( precision ) ); gsf.setBase(new Coordinate(centre.getX()-radiusX, centre.getY() - radiusY)); gsf.setWidth(radiusX*2); gsf.setHeight(radiusY*2); gsf.setNumPoints(numPoints); return new Polygon2DAdapter(gsf.createCircle()); } /** Connects the given array of points to a line-string. The <code>PrecisionModel</code> is * set to double-precision. * @param points the points to connect * @return a new <code>LineString2DAdapter</code> connecting the given points */ public static LineString2DAdapter createLineString2D(Point2DAdapter[] points){ return createLineString2D(points, DOUBLE_PRECISIONMODEL); } /** Connects the given array of points to a line-string. The <code>PrecisionModel</code> can * be specified. * @param points the points to connect * @param precision the <code>PrecisionModel</code> to use * @return a new <code>LineString2DAdapter</code> connecting the given points */ public static LineString2DAdapter createLineString2D(Point2DAdapter[] points, PrecisionModel precision){ Coordinate[] c = new Coordinate[points.length]; for(int i=0; i< points.length; c[i] = points[i].geometry.getCoordinate(), i++); GeometryFactory factory = getGeometryFactory( precision ); return new LineString2DAdapter( factory.createLineString(c) ); } /** Connects the given array of points to a linear ring. The first and last point of the array are assumed * to be identical. The <code>PrecisionModel</code> is set to double-precision. * @param points the points to connect * @return a new <code>LinearRing2DAdapter</code> connecting the given points to a ring */ public static LinearRing2DAdapter createLinearRing2D(Point2DAdapter[] points){ return createLinearRing2D(points, DOUBLE_PRECISIONMODEL); } /** Connects the given array of points to a linear ring. The first and last point of the array are assumed * to be identical. The <code>PrecisionModel</code> can be specified. * @param points the points to connect * @param precision the <code>PrecisionModel</code> to use * @return a new <code>LinearRing2DAdapter</code> connecting the given points to a ring */ public static LinearRing2DAdapter createLinearRing2D(Point2DAdapter[] points, PrecisionModel precision){ Coordinate[] c = new Coordinate[points.length]; for(int i=0; i< points.length; c[i] = points[i].geometry.getCoordinate(), i++); GeometryFactory factory = getGeometryFactory( precision ); return new LinearRing2DAdapter( factory.createLinearRing(c) ); } /** Creates a polygon with shell and holes specified by the given point-sets. * The <code>PrecisionModel</code> is set to double-precision. * @param shell the point-set defining the shell of the polygon * @param holes the point-sets defining holes in the polygon * @return a new <code>Polygon2DAdapter</code> */ public static Polygon2DAdapter createPolygon2D(Point2DAdapter[] shell, Point2DAdapter[][] holes){ return createPolygon2D(shell, holes, DOUBLE_PRECISIONMODEL); } /** Creates a polygon with shell and holes specified by the given point-sets. * The <code>PrecisionModel</code> can be specified. * @param shell the point-set defining the shell of the polygon * @param holes the point-sets defining holes in the polygon * @param precision the <code>PrecisionModel</code> to use * @return a new <code>Polygon2DAdapter</code> */ public static Polygon2DAdapter createPolygon2D(Point2DAdapter[] shell, Point2DAdapter[][] holes, PrecisionModel precision){ if(shell.length==0) throw new Geometry2DException("Cannot create polygon out of empty point- set"); Coordinate[] sh = new Coordinate[shell.length]; for(int i=0; i< shell.length; sh[i] = shell[i].geometry.getCoordinate(), i++); GeometryFactory factory = getGeometryFactory( precision ); LinearRing _shell = factory.createLinearRing(sh); LinearRing[] _holes = new LinearRing[holes.length]; for(int i=0; i<holes.length;i++){ Coordinate[] ho = new Coordinate[shell.length]; for(int j=0; j< holes[i].length; ho[j] = holes[i][j].geometry.getCoordinate(), j++); _holes[i] = factory.createLinearRing(ho); } return new Polygon2DAdapter( factory.createPolygon(_shell, _holes) ); } /** Wraps the given point-set in a <code>MultiPoint2DAdapter</code>-collection. * The <code>PrecisionModel</code> is determined from the points' models. * @param points the points to wrap in the collection * @return a new <code>MultiPoint2DAdapter</code>-object */ public static MultiPoint2DAdapter createMultiPoint2D(Point2DAdapter[] points) { MultiPoint m = null; if(points== null || points.length==0) m = DOUBLE_GEOMETRYFACTORY.createMultiPoint((com.vividsolutions.jts.geom.Point[])null); else{ Coordinate[] c = new Coordinate[points.length]; for(int i=0; i< points.length; c[i] = points[i].geometry.getCoordinate(), i++); m = points[0].geometry.getFactory().createMultiPoint(c); } return new MultiPoint2DAdapter( m ); } /** Wraps the given line-strings in a <code>MultiLineString2DAdapter</code>-collection. * The <code>PrecisionModel</code> is determined from the line-strings' models. * @param lineStrings the line-strings to wrap in the collection * @return a new <code>MultiLineString2DAdapter</code>-object */ public static MultiLineString2DAdapter createMultiLineString2D(LineString2DAdapter[] lineStrings) { MultiLineString m = null; if(lineStrings== null || lineStrings.length==0) m = DOUBLE_GEOMETRYFACTORY.createMultiLineString(null); else{ LineString[] l = new LineString[lineStrings.length]; for(int i=0; i< l.length; i++) l[i] = (LineString) lineStrings[i].geometry; m = l[0].getFactory().createMultiLineString(l); } return new MultiLineString2DAdapter( m ); } /** Wraps the given polygons in a <code>MultiPolygon2DAdapter</code>-collection. * The <code>PrecisionModel</code> is determined from the polygons' models. * @param polygons the polygons to wrap in the collection * @return a new <code>MultiPolygon2DAdapter</code>-object */ public static MultiPolygon2DAdapter createMultiPolygon2D(Polygon2DAdapter[] polygons) { MultiPolygon m = null; if(polygons== null || polygons.length==0) m = DOUBLE_GEOMETRYFACTORY.createMultiPolygon(null); else{ Polygon[] p = new Polygon[polygons.length]; for(int i=0; i< p.length; i++) p[i] = (Polygon) polygons[i].geometry; m = p[0].getFactory().createMultiPolygon(p); } return new MultiPolygon2DAdapter(m); } /** Wraps the given geometries in a <code>GeometryCollection2DAdapter</code>-object. * The <code>PrecisionModel</code> is determined from the geometries' models. * @param geometries the geometries to wrap in the collection * @return a new <code>GeometryCollection<2DAdapter</code>-object */ public static GeometryCollection2DAdapter createGeometryCollection2D(Geometry2DAdapter[] geometries) { GeometryCollection m = null; if(geometries == null || geometries.length==0) m= DOUBLE_GEOMETRYFACTORY.createGeometryCollection(null); else { Geometry[] g = new Geometry[geometries.length]; for(int i=0; i< g.length; i++) g[i] = geometries[i].geometry; m = g[0].getFactory().createGeometryCollection(g); } return new GeometryCollection2DAdapter( m ); } /** Wraps the given list of geometries in the appropriate {@link GeometryCollection}-subclass. * @param geometryList the geometries to wrap * @return the <code>GeometryCollection</code>-object appropriate for the given set of geometries. */ public static Geometry2DAdapter buildGeometry(Collection<Geometry> geometryList){ GeometryFactory factory = geometryList.size()> 0 ? geometryList.iterator().next().getFactory() : getGeometryFactory(DOUBLE_PRECISIONMODEL); return Geometry2DFactory.wrap(factory.buildGeometry(geometryList)); } }