
com.vividsolutions.jts.geom.GeometryFactory Maven / Gradle / Ivy
Show all versions of jts Show documentation
/*
* The JTS Topology Suite is a collection of Java classes that
* implement the fundamental operations required to validate a given
* geo-spatial data set to a known topological specification.
*
* Copyright (C) 2001 Vivid Solutions
*
* 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, contact:
*
* Vivid Solutions
* Suite #1A
* 2328 Government Street
* Victoria BC V8T 5G5
* Canada
*
* (250)385-6040
* www.vividsolutions.com
*/
package com.vividsolutions.jts.geom;
import java.util.*;
import java.io.Serializable;
import com.vividsolutions.jts.geom.impl.*;
import com.vividsolutions.jts.geom.util.*;
import com.vividsolutions.jts.util.Assert;
/**
* Supplies a set of utility methods for building Geometry objects from lists
* of Coordinates.
*
* Note that the factory constructor methods do not change the input coordinates in any way.
* In particular, they are not rounded to the supplied PrecisionModel.
* It is assumed that input Coordinates meet the given precision.
*
*
* @version 1.7
*/
public class GeometryFactory
implements Serializable
{
private static final long serialVersionUID = -6820524753094095635L;
private PrecisionModel precisionModel;
private CoordinateSequenceFactory coordinateSequenceFactory;
public static Point createPointFromInternalCoord(Coordinate coord, Geometry exemplar)
{
exemplar.getPrecisionModel().makePrecise(coord);
return exemplar.getFactory().createPoint(coord);
}
/**
* Constructs a GeometryFactory that generates Geometries having the given
* PrecisionModel, spatial-reference ID, and CoordinateSequence implementation.
*/
public GeometryFactory(PrecisionModel precisionModel, int SRID,
CoordinateSequenceFactory coordinateSequenceFactory) {
this.precisionModel = precisionModel;
this.coordinateSequenceFactory = coordinateSequenceFactory;
this.SRID = SRID;
}
/**
* Constructs a GeometryFactory that generates Geometries having the given
* CoordinateSequence implementation, a double-precision floating PrecisionModel and a
* spatial-reference ID of 0.
*/
public GeometryFactory(CoordinateSequenceFactory coordinateSequenceFactory) {
this(new PrecisionModel(), 0, coordinateSequenceFactory);
}
/**
* Constructs a GeometryFactory that generates Geometries having the given
* {@link PrecisionModel} and the default CoordinateSequence
* implementation.
*
* @param precisionModel the PrecisionModel to use
*/
public GeometryFactory(PrecisionModel precisionModel) {
this(precisionModel, 0, getDefaultCoordinateSequenceFactory());
}
/**
* Constructs a GeometryFactory that generates Geometries having the given
* {@link PrecisionModel} and spatial-reference ID, and the default CoordinateSequence
* implementation.
*
* @param precisionModel the PrecisionModel to use
* @param SRID the SRID to use
*/
public GeometryFactory(PrecisionModel precisionModel, int SRID) {
this(precisionModel, SRID, getDefaultCoordinateSequenceFactory());
}
/**
* Constructs a GeometryFactory that generates Geometries having a floating
* PrecisionModel and a spatial-reference ID of 0.
*/
public GeometryFactory() {
this(new PrecisionModel(), 0);
}
private static CoordinateSequenceFactory getDefaultCoordinateSequenceFactory()
{
return CoordinateArraySequenceFactory.instance();
}
/**
* Converts the List
to an array.
*
*@param points the List
of Points to convert
*@return the List
in array format
*/
public static Point[] toPointArray(Collection points) {
Point[] pointArray = new Point[points.size()];
return (Point[]) points.toArray(pointArray);
}
/**
* Converts the List
to an array.
*
*@param geometries the list of Geometry's
to convert
*@return the List
in array format
*/
public static Geometry[] toGeometryArray(Collection geometries) {
if (geometries == null) return null;
Geometry[] geometryArray = new Geometry[geometries.size()];
return (Geometry[]) geometries.toArray(geometryArray);
}
/**
* Converts the List
to an array.
*
*@param linearRings the List
of LinearRings to convert
*@return the List
in array format
*/
public static LinearRing[] toLinearRingArray(Collection linearRings) {
LinearRing[] linearRingArray = new LinearRing[linearRings.size()];
return (LinearRing[]) linearRings.toArray(linearRingArray);
}
/**
* Converts the List
to an array.
*
*@param lineStrings the List
of LineStrings to convert
*@return the List
in array format
*/
public static LineString[] toLineStringArray(Collection lineStrings) {
LineString[] lineStringArray = new LineString[lineStrings.size()];
return (LineString[]) lineStrings.toArray(lineStringArray);
}
/**
* Converts the List
to an array.
*
*@param polygons the List
of Polygons to convert
*@return the List
in array format
*/
public static Polygon[] toPolygonArray(Collection polygons) {
Polygon[] polygonArray = new Polygon[polygons.size()];
return (Polygon[]) polygons.toArray(polygonArray);
}
/**
* Converts the List
to an array.
*
*@param multiPolygons the List
of MultiPolygons to convert
*@return the List
in array format
*/
public static MultiPolygon[] toMultiPolygonArray(Collection multiPolygons) {
MultiPolygon[] multiPolygonArray = new MultiPolygon[multiPolygons.size()];
return (MultiPolygon[]) multiPolygons.toArray(multiPolygonArray);
}
/**
* Converts the List
to an array.
*
*@param multiLineStrings the List
of MultiLineStrings to convert
*@return the List
in array format
*/
public static MultiLineString[] toMultiLineStringArray(Collection multiLineStrings) {
MultiLineString[] multiLineStringArray = new MultiLineString[multiLineStrings.size()];
return (MultiLineString[]) multiLineStrings.toArray(multiLineStringArray);
}
/**
* Converts the List
to an array.
*
*@param multiPoints the List
of MultiPoints to convert
*@return the List
in array format
*/
public static MultiPoint[] toMultiPointArray(Collection multiPoints) {
MultiPoint[] multiPointArray = new MultiPoint[multiPoints.size()];
return (MultiPoint[]) multiPoints.toArray(multiPointArray);
}
/**
* Creates a {@link Geometry} with the same extent as the given envelope.
* The Geometry returned is guaranteed to be valid.
* To provide this behaviour, the following cases occur:
*
* If the Envelope
is:
*
* - null : returns an empty {@link Point}
*
- a point : returns a non-empty {@link Point}
*
- a line : returns a two-point {@link LineString}
*
- a rectangle : returns a {@link Polygon}> whose points are (minx, miny),
* (minx, maxy), (maxx, maxy), (maxx, miny), (minx, miny).
*
*
*@param envelope the Envelope
to convert
*@return an empty Point
(for null Envelope
s),
* a Point
(when min x = max x and min y = max y) or a
* Polygon
(in all other cases)
*/
public Geometry toGeometry(Envelope envelope)
{
// null envelope - return empty point geometry
if (envelope.isNull()) {
return createPoint((CoordinateSequence)null);
}
// point?
if (envelope.getMinX() == envelope.getMaxX() && envelope.getMinY() == envelope.getMaxY()) {
return createPoint(new Coordinate(envelope.getMinX(), envelope.getMinY()));
}
// vertical or horizontal line?
if (envelope.getMinX() == envelope.getMaxX()
|| envelope.getMinY() == envelope.getMaxY()) {
return createLineString(new Coordinate[]{
new Coordinate(envelope.getMinX(), envelope.getMinY()),
new Coordinate(envelope.getMaxX(), envelope.getMaxY())
});
}
// create a CW ring for the polygon
return createPolygon(createLinearRing(new Coordinate[]{
new Coordinate(envelope.getMinX(), envelope.getMinY()),
new Coordinate(envelope.getMinX(), envelope.getMaxY()),
new Coordinate(envelope.getMaxX(), envelope.getMaxY()),
new Coordinate(envelope.getMaxX(), envelope.getMinY()),
new Coordinate(envelope.getMinX(), envelope.getMinY())
}), null);
}
/**
* Returns the PrecisionModel that Geometries created by this factory
* will be associated with.
*/
public PrecisionModel getPrecisionModel() {
return precisionModel;
}
/**
* Creates a Point using the given Coordinate; a null Coordinate will create
* an empty Geometry.
*/
public Point createPoint(Coordinate coordinate) {
return createPoint(coordinate != null ? getCoordinateSequenceFactory().create(new Coordinate[]{coordinate}) : null);
}
/**
* Creates a Point using the given CoordinateSequence; a null or empty
* CoordinateSequence will create an empty Point.
*/
public Point createPoint(CoordinateSequence coordinates) {
return new Point(coordinates, this);
}
/**
* Creates a MultiLineString using the given LineStrings; a null or empty
* array will create an empty MultiLineString.
* @param lineStrings LineStrings, each of which may be empty but not null
*/
public MultiLineString createMultiLineString(LineString[] lineStrings) {
return new MultiLineString(lineStrings, this);
}
/**
* Creates a GeometryCollection using the given Geometries; a null or empty
* array will create an empty GeometryCollection.
* @param geometries Geometries, each of which may be empty but not null
*/
public GeometryCollection createGeometryCollection(Geometry[] geometries) {
return new GeometryCollection(geometries, this);
}
/**
* Creates a MultiPolygon using the given Polygons; a null or empty array
* will create an empty Polygon. The polygons must conform to the
* assertions specified in the OpenGIS Simple Features
* Specification for SQL.
*
* @param polygons
* Polygons, each of which may be empty but not null
*/
public MultiPolygon createMultiPolygon(Polygon[] polygons) {
return new MultiPolygon(polygons, this);
}
/**
* Creates a LinearRing using the given Coordinates; a null or empty array will
* create an empty LinearRing. The points must form a closed and simple
* linestring. Consecutive points must not be equal.
* @param coordinates an array without null elements, or an empty array, or null
*/
public LinearRing createLinearRing(Coordinate[] coordinates) {
return createLinearRing(coordinates != null ? getCoordinateSequenceFactory().create(coordinates) : null);
}
/**
* Creates a LinearRing using the given CoordinateSequence; a null or empty CoordinateSequence will
* create an empty LinearRing. The points must form a closed and simple
* linestring. Consecutive points must not be equal.
* @param coordinates a CoordinateSequence possibly empty, or null
*/
public LinearRing createLinearRing(CoordinateSequence coordinates) {
return new LinearRing(coordinates, this);
}
/**
* Creates a MultiPoint using the given Points.
* A null or empty array will create an empty MultiPoint.
*
* @param coordinates an array (without null elements), or an empty array, or null
* @return a MultiPoint object
*/
public MultiPoint createMultiPoint(Point[] point) {
return new MultiPoint(point, this);
}
/**
* Creates a {@link MultiPoint} using the given {@link Coordinate}s.
* A null or empty array will create an empty MultiPoint.
*
* @param coordinates an array (without null elements), or an empty array, or null
* @return a MultiPoint object
*/
public MultiPoint createMultiPoint(Coordinate[] coordinates) {
return createMultiPoint(coordinates != null
? getCoordinateSequenceFactory().create(coordinates)
: null);
}
/**
* Creates a MultiPoint using the given CoordinateSequence.
* A a null or empty CoordinateSequence will create an empty MultiPoint.
*
* @param coordinates a CoordinateSequence (possibly empty), or null
* @return a MultiPoint object
*/
public MultiPoint createMultiPoint(CoordinateSequence coordinates) {
if (coordinates == null) {
return createMultiPoint(new Point[0]);
}
Point[] points = new Point[coordinates.size()];
for (int i = 0; i < coordinates.size(); i++) {
points[i] = createPoint(coordinates.getCoordinate(i));
}
return createMultiPoint(points);
}
/**
* Constructs a Polygon
with the given exterior boundary and
* interior boundaries.
*
* @param shell
* the outer boundary of the new Polygon
, or
* null
or an empty LinearRing
if
* the empty geometry is to be created.
* @param holes
* the inner boundaries of the new Polygon
, or
* null
or empty LinearRing
s if
* the empty geometry is to be created.
*/
public Polygon createPolygon(LinearRing shell, LinearRing[] holes) {
return new Polygon(shell, holes, this);
}
/**
* Build an appropriate Geometry
, MultiGeometry
, or
* GeometryCollection
to contain the Geometry
s in
* it.
* For example:
*
*
* - If
geomList
contains a single Polygon
,
* the Polygon
is returned.
* - If
geomList
contains several Polygon
s, a
* MultiPolygon
is returned.
* - If
geomList
contains some Polygon
s and
* some LineString
s, a GeometryCollection
is
* returned.
* - If
geomList
is empty, an empty GeometryCollection
* is returned
*
*
* Note that this method does not "flatten" Geometries in the input, and hence if
* any MultiGeometries are contained in the input a GeometryCollection containing
* them will be returned.
*
*@param geomList the Geometry
s to combine
*@return a Geometry
of the "smallest", "most
* type-specific" class that can contain the elements of geomList
* .
*/
public Geometry buildGeometry(Collection geomList) {
/**
* Determine some facts about the geometries in the list
*/
Class geomClass = null;
boolean isHeterogeneous = false;
boolean hasGeometryCollection = false;
for (Iterator i = geomList.iterator(); i.hasNext(); ) {
Geometry geom = (Geometry) i.next();
Class partClass = geom.getClass();
if (geomClass == null) {
geomClass = partClass;
}
if (partClass != geomClass) {
isHeterogeneous = true;
}
if (geom instanceof GeometryCollection)
hasGeometryCollection = true;
}
/**
* Now construct an appropriate geometry to return
*/
// for the empty geometry, return an empty GeometryCollection
if (geomClass == null) {
return createGeometryCollection(null);
}
if (isHeterogeneous || hasGeometryCollection) {
return createGeometryCollection(toGeometryArray(geomList));
}
// at this point we know the collection is hetereogenous.
// Determine the type of the result from the first Geometry in the list
// this should always return a geometry, since otherwise an empty collection would have already been returned
Geometry geom0 = (Geometry) geomList.iterator().next();
boolean isCollection = geomList.size() > 1;
if (isCollection) {
if (geom0 instanceof Polygon) {
return createMultiPolygon(toPolygonArray(geomList));
}
else if (geom0 instanceof LineString) {
return createMultiLineString(toLineStringArray(geomList));
}
else if (geom0 instanceof Point) {
return createMultiPoint(toPointArray(geomList));
}
Assert.shouldNeverReachHere("Unhandled class: " + geom0.getClass().getName());
}
return geom0;
}
/**
* Creates a LineString using the given Coordinates; a null or empty array will
* create an empty LineString. Consecutive points must not be equal.
* @param coordinates an array without null elements, or an empty array, or null
*/
public LineString createLineString(Coordinate[] coordinates) {
return createLineString(coordinates != null ? getCoordinateSequenceFactory().create(coordinates) : null);
}
/**
* Creates a LineString using the given CoordinateSequence; a null or empty CoordinateSequence will
* create an empty LineString. Consecutive points must not be equal.
* @param coordinates a CoordinateSequence possibly empty, or null
*/
public LineString createLineString(CoordinateSequence coordinates) {
return new LineString(coordinates, this);
}
/**
* @return a clone of g based on a CoordinateSequence created by this
* GeometryFactory's CoordinateSequenceFactory
*/
public Geometry createGeometry(Geometry g)
{
// could this be cached to make this more efficient? Or maybe it isn't enough overhead to bother
GeometryEditor editor = new GeometryEditor(this);
return editor.edit(g, new GeometryEditor.CoordinateOperation() {
public Coordinate[] edit(Coordinate[] coordinates, Geometry geometry) {
return coordinates;
}
});
}
public int getSRID() {
return SRID;
}
private int SRID;
public CoordinateSequenceFactory getCoordinateSequenceFactory() {
return coordinateSequenceFactory;
}
}