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 */
}
}