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); } } }