using System;
using System.Collections;
using System.Collections.Generic;
using GeoAPI.Geometries;
using GisSharpBlog.NetTopologySuite.Geometries.Utilities;
using GisSharpBlog.NetTopologySuite.Utilities;
namespace GisSharpBlog.NetTopologySuite.Geometries
{
///
/// Supplies a set of utility methods for building Geometry objects
/// from lists of Coordinates.
///
[Serializable]
public class GeometryFactory : IGeometryFactory
{
///
/// A predefined with
/// == .
///
public static readonly IGeometryFactory Default = new GeometryFactory();
///
/// A predefined with
/// == .
///
/// A shortcut for .
public static readonly IGeometryFactory Floating = Default;
///
/// A predefined with
/// == .
///
public static readonly IGeometryFactory FloatingSingle = new GeometryFactory(new PrecisionModel(PrecisionModels.FloatingSingle));
///
/// A predefined with
/// == .
///
public static readonly IGeometryFactory Fixed = new GeometryFactory(new PrecisionModel(PrecisionModels.Fixed));
private IPrecisionModel precisionModel;
///
/// Returns the PrecisionModel that Geometries created by this factory
/// will be associated with.
///
public IPrecisionModel PrecisionModel
{
get { return precisionModel; }
}
private ICoordinateSequenceFactory coordinateSequenceFactory;
///
///
///
public ICoordinateSequenceFactory CoordinateSequenceFactory
{
get { return coordinateSequenceFactory; }
}
private int srid;
///
///
///
public int SRID
{
get { return srid; }
}
///
///
///
///
///
///
public static IPoint CreatePointFromInternalCoord(ICoordinate coord, IGeometry exemplar)
{
exemplar.PrecisionModel.MakePrecise(coord);
return exemplar.Factory.CreatePoint(coord);
}
///
/// Constructs a GeometryFactory that generates Geometries having the given
/// PrecisionModel, spatial-reference ID, and CoordinateSequence implementation.
///
///
///
///
public GeometryFactory(IPrecisionModel precisionModel, int SRID,
ICoordinateSequenceFactory 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(ICoordinateSequenceFactory coordinateSequenceFactory)
: this(new PrecisionModel(), 0, coordinateSequenceFactory) { }
///
/// Constructs a GeometryFactory that generates Geometries having the given
/// {PrecisionModel} and the default CoordinateSequence
/// implementation.
///
/// The PrecisionModel to use.
public GeometryFactory(IPrecisionModel precisionModel)
: this(precisionModel, 0, GetDefaultCoordinateSequenceFactory()) { }
///
/// Constructs a GeometryFactory that generates Geometries having the given
/// PrecisionModel and spatial-reference ID, and the default CoordinateSequence
/// implementation.
///
/// The PrecisionModel to use.
/// 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) { }
///
/// Converts the ICollection to an array.
///
/// The ICollection of Points to convert.
/// The ICollection in array format.
public static IPoint[] ToPointArray(ICollection points)
{
IPoint[] list = new IPoint[points.Count];
int i = 0;
foreach (IPoint p in points)
list[i++] = p;
return list;
}
///
/// Converts the ICollection to an array.
///
/// The ICollection of Geometry's to convert.
/// The ICollection in array format.
public static IGeometry[] ToGeometryArray(ICollection geometries)
{
IGeometry[] list = new IGeometry[geometries.Count];
int i = 0;
foreach (IGeometry g in geometries)
list[i++] = g;
return list;
}
///
/// Converts the ICollection to an array.
///
/// The ICollection of LineStrings to convert.
/// The ICollection in array format.
public static ILineString[] ToLineStringArray(ICollection lineStrings)
{
ILineString[] list = new ILineString[lineStrings.Count];
int i = 0;
foreach (ILineString ls in lineStrings)
list[i++] = ls;
return list;
}
///
/// Converts the ICollection to an array.
///
/// The ICollection of LinearRings to convert.
/// The ICollection in array format.
public static ILinearRing[] ToLinearRingArray(ICollection linearRings)
{
ILinearRing[] list = new ILinearRing[linearRings.Count];
int i = 0;
foreach (ILinearRing lr in linearRings)
list[i++] = lr;
return list;
}
///
/// Converts the ICollection to an array.
///
/// The ICollection of Polygons to convert.
/// The ICollection in array format.
public static IPolygon[] ToPolygonArray(ICollection polygons)
{
IPolygon[] list = new IPolygon[polygons.Count];
int i = 0;
foreach (IPolygon p in polygons)
list[i++] = p;
return list;
}
///
/// Converts the ICollection to an array.
///
/// The ICollection of MultiPoints to convert.
/// The ICollection in array format.
public static IMultiPoint[] ToMultiPointArray(ICollection multiPoints)
{
IMultiPoint[] list = new IMultiPoint[multiPoints.Count];
int i = 0;
foreach (IMultiPoint mp in multiPoints)
list[i++] = mp;
return list;
}
///
/// Converts the ICollection to an array.
///
/// The ICollection of MultiLineStrings to convert.
/// The ICollection in array format.
public static IMultiLineString[] ToMultiLineStringArray(ICollection multiLineStrings)
{
IMultiLineString[] list = new IMultiLineString[multiLineStrings.Count];
int i = 0;
foreach (IMultiLineString mls in multiLineStrings)
list[i++] = mls;
return list;
}
///
/// Converts the ICollection to an array.
///
/// The ICollection of MultiPolygons to convert.
/// The ICollection in array format.
public static IMultiPolygon[] ToMultiPolygonArray(ICollection multiPolygons)
{
IMultiPolygon[] list = new IMultiPolygon[multiPolygons.Count];
int i = 0;
foreach (IMultiPolygon mp in multiPolygons)
list[i++] = mp;
return list;
}
///
/// If the Envelope is a null Envelope, returns an
/// empty Point. If the Envelope is a point, returns
/// a non-empty Point. If the Envelope is a
/// rectangle, returns a Polygon whose points are (minx, miny),
/// (maxx, miny), (maxx, maxy), (minx, maxy), (minx, miny).
///
/// The Envelope to convert to a Geometry.
///
/// 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)
/// throws a TopologyException if coordinates
/// is not a closed linestring, that is, if the first and last coordinates
/// are not equal.
///
public IGeometry ToGeometry(IEnvelope envelope)
{
if (envelope.IsNull)
return CreatePoint((ICoordinateSequence) null);
if (envelope.MinX == envelope.MaxX && envelope.MinY == envelope.MaxY)
return CreatePoint(new Coordinate(envelope.MinX, envelope.MinY));
return CreatePolygon(
CreateLinearRing(new ICoordinate[]
{
new Coordinate(envelope.MinX, envelope.MinY),
new Coordinate(envelope.MaxX, envelope.MinY),
new Coordinate(envelope.MaxX, envelope.MaxY),
new Coordinate(envelope.MinX, envelope.MaxY),
new Coordinate(envelope.MinX, envelope.MinY),
}),
null);
}
///
/// Creates a Point using the given Coordinate; a null Coordinate will create
/// an empty Geometry.
///
///
public IPoint CreatePoint(ICoordinate coordinate)
{
return CreatePoint(coordinate != null ?
CoordinateSequenceFactory.Create(new ICoordinate[] { coordinate }) : null);
}
///
/// Creates a Point using the given CoordinateSequence; a null or empty
/// CoordinateSequence will create an empty Point.
///
///
public IPoint CreatePoint(ICoordinateSequence coordinates)
{
return new Point(coordinates, this);
}
///
/// Creates a LineString using the given Coordinates; a null or empty array will
/// create an empty LineString. Consecutive points must not be equal.
///
/// An array without null elements, or an empty array, or null.
///
public ILineString CreateLineString(ICoordinate[] coordinates)
{
return CreateLineString(coordinates != null ?
CoordinateSequenceFactory.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.
///
/// A CoordinateSequence possibly empty, or null.
///
public ILineString CreateLineString(ICoordinateSequence coordinates)
{
return new LineString(coordinates, 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.
///
/// An array without null elements, or an empty array, or null.
public ILinearRing CreateLinearRing(ICoordinate[] coordinates)
{
return CreateLinearRing(coordinates != null ?
CoordinateSequenceFactory.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.
///
/// A CoordinateSequence possibly empty, or null.
public ILinearRing CreateLinearRing(ICoordinateSequence coordinates)
{
return new LinearRing(coordinates, this);
}
///
/// Constructs a Polygon with the given exterior boundary and
/// interior boundaries.
///
///
/// The outer boundary of the new Polygon, or
/// null or an empty LinearRing if
/// the empty point is to be created.
///
///
/// The inner boundaries of the new Polygon, or
/// null or empty LinearRing s if
/// the empty point is to be created.
///
///
public IPolygon CreatePolygon(ILinearRing shell, ILinearRing[] holes)
{
return new Polygon(shell, holes, this);
}
///
/// Creates a MultiPoint using the given Points; a null or empty array will
/// create an empty MultiPoint.
///
/// An array without null elements, or an empty array, or null.
public IMultiPoint CreateMultiPoint(IPoint[] point)
{
return new MultiPoint(point, this);
}
///
/// Creates a MultiPoint using the given Coordinates; a null or empty array will create an empty MultiPoint.
///
/// An array without null elements, or an empty array, or null.
public IMultiPoint CreateMultiPoint(ICoordinate[] coordinates)
{
return CreateMultiPoint(coordinates != null ?
CoordinateSequenceFactory.Create(coordinates) : null);
}
///
/// Creates a MultiPoint using the given CoordinateSequence; a null or empty CoordinateSequence will
/// create an empty MultiPoint.
///
/// A CoordinateSequence possibly empty, or null.
public IMultiPoint CreateMultiPoint(ICoordinateSequence coordinates)
{
if (coordinates == null)
coordinates = CoordinateSequenceFactory.Create(new ICoordinate[] { });
List points = new List();
for (int i = 0; i < coordinates.Count; i++)
points.Add(CreatePoint(coordinates.GetCoordinate(i)));
return CreateMultiPoint(points.ToArray());
}
///
/// Creates a MultiLineString using the given LineStrings; a null or empty
/// array will create an empty MultiLineString.
///
/// LineStrings, each of which may be empty but not null-
public IMultiLineString CreateMultiLineString(ILineString[] lineStrings)
{
return new MultiLineString(lineStrings, 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.
///
/// Polygons, each of which may be empty but not null.
public IMultiPolygon CreateMultiPolygon(IPolygon[] polygons)
{
return new MultiPolygon(polygons, this);
}
///
/// Creates a GeometryCollection using the given Geometries; a null or empty
/// array will create an empty GeometryCollection.
///
/// Geometries, each of which may be empty but not null.
public IGeometryCollection CreateGeometryCollection(IGeometry[] geometries)
{
return new GeometryCollection(geometries, this);
}
///
/// Build an appropriate Geometry, MultiGeometry, or
/// GeometryCollection to contain the Geometrys in
/// it.
///
/// If geomList contains a single Polygon,
/// the Polygon is returned.
/// If geomList contains several Polygons, a
/// MultiPolygon is returned.
/// If geomList contains some Polygons and
/// some LineStrings, 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.
///
///
/// The Geometry to combine.
///
/// A Geometry of the "smallest", "most type-specific"
/// class that can contain the elements of geomList.
///
public IGeometry BuildGeometry(ICollection geomList)
{
Type geomClass = null;
bool isHeterogeneous = false;
foreach (IGeometry geom in geomList)
{
Type partClass = geom.GetType();
if (geomClass == null)
geomClass = partClass;
if (partClass != geomClass)
isHeterogeneous = true;
}
// for the empty point, return an empty GeometryCollection
if (geomClass == null)
return CreateGeometryCollection(null);
if (isHeterogeneous)
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 point, since otherwise an empty collection would have already been returned
IEnumerator ienum = geomList.GetEnumerator();
ienum.MoveNext();
IGeometry geom0 = (IGeometry) ienum.Current;
bool isCollection = geomList.Count > 1;
if (isCollection)
{
if (geom0 is IPolygon)
return CreateMultiPolygon(ToPolygonArray(geomList));
else if (geom0 is ILineString)
return CreateMultiLineString(ToLineStringArray(geomList));
else if (geom0 is IPoint)
return CreateMultiPoint(ToPointArray(geomList));
Assert.ShouldNeverReachHere();
}
return geom0;
}
///
///
///
///
///
/// A clone of g based on a CoordinateSequence created by this
/// GeometryFactory's CoordinateSequenceFactory.
///
public IGeometry CreateGeometry(IGeometry 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 AnonymousCoordinateOperationImpl());
}
///
///
///
///
private static ICoordinateSequenceFactory GetDefaultCoordinateSequenceFactory()
{
return CoordinateArraySequenceFactory.Instance;
}
///
///
///
private class AnonymousCoordinateOperationImpl : GeometryEditor.CoordinateOperation
{
public override ICoordinate[] Edit(ICoordinate[] coordinates, IGeometry geometry)
{
return coordinates;
}
}
public static ICoordinate CreateCoordinate(double x, double y)
{
return new Coordinate(x, y);
}
}
}