using System; using GeoAPI.Geometries; using GisSharpBlog.NetTopologySuite.Algorithm; using GisSharpBlog.NetTopologySuite.Operation; namespace GisSharpBlog.NetTopologySuite.Geometries { /// /// Basic implementation of LineString. /// [Serializable] public class LineString : Geometry, ILineString { /// /// The points of this LineString. /// private ICoordinateSequence points; /// /// /// /// /// The points of the linestring, or null /// to create the empty point. Consecutive points may not be equal. /// /// public LineString(ICoordinateSequence points, IGeometryFactory factory) : base(factory) { if (points == null) { points = factory.CoordinateSequenceFactory.Create(new ICoordinate[] {}); } if (points.Count == 1) { throw new ArgumentException("point array must contain 0 or >1 elements", "points"); } this.points = points; GeometryChangedAction(); } /* BEGIN ADDED BY MPAUL42: monoGIS team */ /// /// Initializes a new instance of the class. /// /// /// For create this is used a standard /// with == . /// /// The coordinates used for create this . public LineString(ICoordinate[] points) : this(DefaultFactory.CoordinateSequenceFactory.Create(points), DefaultFactory) {} /// /// /// public override ICoordinate[] Coordinates { get { return points.ToCoordinateArray(); } } /// /// /// public ICoordinateSequence CoordinateSequence { get { return points; } } /// /// /// public override ICoordinate Coordinate { get { if (IsEmpty) { return null; } return points.GetCoordinate(0); } } /// /// /// public override Dimensions Dimension { get { return Dimensions.Curve; } } /// /// /// public override Dimensions BoundaryDimension { get { if (IsClosed) { return Dimensions.False; } return Dimensions.Point; } } /// /// /// public override bool IsEmpty { get { return points.Count == 0; } } /// /// /// public override int NumPoints { get { return points.Count; } } /// /// /// public IPoint StartPoint { get { if (IsEmpty) { return null; } return GetPointN(0); } } /// /// /// public IPoint EndPoint { get { if (IsEmpty) { return null; } return GetPointN(NumPoints - 1); } } /// /// /// public virtual bool IsClosed { get { if (IsEmpty) { return false; } return GetCoordinateN(0).Equals2D(GetCoordinateN(NumPoints - 1)); } } /// /// /// public bool IsRing { get { return IsClosed && IsSimple; } } /// /// /// public override string GeometryType { get { return "LineString"; } } /// /// Returns the length of this LineString /// /// The length of the polygon. public override double Length { get { return CGAlgorithms.Length(points); } } /// /// /// public override bool IsSimple { get { return (new IsSimpleOp()).IsSimple(this); } } /// /// /// public override IGeometry Boundary { get { if (IsEmpty) { return Factory.CreateGeometryCollection(null); } if (IsClosed) { return Factory.CreateMultiPoint((ICoordinate[]) null); } return Factory.CreateMultiPoint(new[] { StartPoint, EndPoint }); } } /// /// /// /// /// public ICoordinate GetCoordinateN(int n) { return points.GetCoordinate(n); } /// /// /// /// /// public IPoint GetPointN(int n) { return Factory.CreatePoint(points.GetCoordinate(n)); } /// /// Creates a whose coordinates are in the reverse order of this objects. /// /// A with coordinates in the reverse order. public ILineString Reverse() { ICoordinateSequence seq = (ICoordinateSequence) points.Clone(); // Personalized implementation using Array.Reverse: maybe it's faster? ICoordinate[] array = seq.ToCoordinateArray(); Array.Reverse(array); return Factory.CreateLineString(array); } /// /// /// /// /// /// public override bool EqualsExact(IGeometry other, double tolerance) { if (!IsEquivalentClass(other)) { return false; } ILineString otherLineString = (ILineString) other; if (points.Count != otherLineString.NumPoints) { return false; } for (int i = 0; i < points.Count; i++) { if (!Equal(points.GetCoordinate(i), otherLineString.GetCoordinateN(i), tolerance)) { return false; } } return true; } /// /// /// /// public override void Apply(ICoordinateFilter filter) { for (int i = 0; i < points.Count; i++) { filter.Filter(points.GetCoordinate(i)); } } /// /// /// /// public override void Apply(IGeometryFilter filter) { filter.Filter(this); } /// /// /// /// public override void Apply(IGeometryComponentFilter filter) { filter.Filter(this); } /// /// /// /// public override object Clone() { LineString ls = (LineString) base.Clone(); ls.points = (ICoordinateSequence) points.Clone(); return ls; } /// /// Normalizes a LineString. A normalized linestring /// has the first point which is not equal to it's reflected point /// less than the reflected point. /// public override void Normalize() { for (int i = 0; i < points.Count/2; i++) { int j = points.Count - 1 - i; // skip equal points on both ends if (!points.GetCoordinate(i).Equals(points.GetCoordinate(j))) { if (points.GetCoordinate(i).CompareTo(points.GetCoordinate(j)) > 0) { CoordinateArrays.Reverse(Coordinates); } return; } } } /// /// /// /// /// protected internal override int CompareToSameClass(object o) { LineString line = (LineString) o; // MD - optimized implementation int i = 0; int j = 0; while (i < points.Count && j < line.points.Count) { int comparison = points.GetCoordinate(i).CompareTo(line.points.GetCoordinate(j)); if (comparison != 0) { return comparison; } i++; j++; } if (i < points.Count) { return 1; } if (j < line.points.Count) { return -1; } return 0; } /// /// /// /// protected override IEnvelope ComputeEnvelopeInternal() { if (IsEmpty) { return new Envelope(); } //Convert to array, then access array directly, to avoid the function-call overhead //of calling Getter millions of times. ToArray may be inefficient for //non-BasicCoordinateSequence CoordinateSequences. [Jon Aquino] ICoordinate[] coordinates = points.ToCoordinateArray(); double minx = coordinates[0].X; double miny = coordinates[0].Y; double maxx = coordinates[0].X; double maxy = coordinates[0].Y; for (int i = 1; i < coordinates.Length; i++) { minx = minx < coordinates[i].X ? minx : coordinates[i].X; maxx = maxx > coordinates[i].X ? maxx : coordinates[i].X; miny = miny < coordinates[i].Y ? miny : coordinates[i].Y; maxy = maxy > coordinates[i].Y ? maxy : coordinates[i].Y; } return new Envelope(minx, maxx, miny, maxy); } /* END ADDED BY MPAUL42: monoGIS team */ } }