//-----------------------------------------------------------------------
//
// Copyright (c) 2009 Deltares. All rights reserved.
//
// B.S.T.I.M. The
// tom.the@deltares.nl
// 16-06-2009
// Contains class PolyLine
//-----------------------------------------------------------------------
using Deltares.Geometry;
namespace Deltares.Dam.Data
{
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
public class PolyLineException : Exception
{
public PolyLineException(string message)
: base(message)
{
}
}
public class PolyLine where T : GeometryPoint, new()
{
protected IList points;
public PolyLine()
{
this.points = new List();
}
public virtual int Id { get; private set; }
public virtual string Name { get; set; }
public virtual IList Points { get { return this.points; } private set { this.points = value; } }
///
/// Check if lines are equal
///
///
///
public virtual bool Equals(PolyLine other)
{
bool isEqual = (other.Points.Count == this.Points.Count);
if (isEqual)
{
for (int pointIndex = 0; pointIndex < this.Points.Count; pointIndex++)
{
isEqual = isEqual && (this.Points[pointIndex].LocationEquals(other.Points[pointIndex]));
}
}
return isEqual;
}
///
/// Check if line has a minimum of two points
///
///
public bool Exists()
{
return (this.Points.Count > 1);
}
///
/// Check if all the points are in strict ascending X order
///
///
public bool IsXStrictAscending()
{
bool isStrictAscending = true;
for (int pointIndex = 0; pointIndex < this.Points.Count - 1; pointIndex++)
{
if (this.Points[pointIndex + 1].X <= this.Points[pointIndex].X)
{
isStrictAscending = false;
break;
}
}
return isStrictAscending;
}
///
/// Check if all the points are in ascending X order
///
///
public bool IsXAscending()
{
bool isAscending = true;
for (int pointIndex = 0; pointIndex < this.Points.Count - 1; pointIndex++)
{
if (this.Points[pointIndex + 1].X < this.Points[pointIndex].X)
{
isAscending = false;
break;
}
}
return isAscending;
}
///
/// Gets point at X if present within tolerance or null if not present.
///
///
public T GetPointAtX(double X, double tolerance)
{
return (from T point in this.points
where Math.Abs(point.X - X) < tolerance
select point).FirstOrDefault();
}
private T InsertPointAtX(double X)
{
T newPoint = new T();
newPoint.X = X;
try
{
T pointAfter = (from T point in this.points
where point.X > X
select point).First();
this.points.Insert(this.points.IndexOf(pointAfter), newPoint);
}
catch
{
this.points.Add(newPoint);
}
return newPoint;
}
///
/// Gets point at X if present within tolerance; creates one there if not present.
///
///
public T EnsurePointAtX(double X, double tolerance)
{
T point = GetPointAtX(X, tolerance);
if (point == null)
{
point = InsertPointAtX(X);
}
return point;
}
///
/// If IsXStrictAscending then return the interpolated value for any X-value
///
///
///
public double YFromX(double X)
{
return YZFromX(X, PointType.XY);
}
public double ZFromX(double X)
{
return YZFromX(X, PointType.XZ);
}
private double YZFromX(double X, PointType pointType)
{
if (!this.IsXAscending())
{
throw new PolyLineException("Interpolation only possible with ascending polyline");
}
double valueYZ = 0.0;
// Less then first X
if (X <= this.Points[0].X)
{
valueYZ = pointType == PointType.XZ ? this.Points[0].Z : this.Points[0].Y;
}
// More then last X
else if (X >= this.Points[this.Points.Count - 1].X)
{
valueYZ = pointType == PointType.XZ ? this.Points[this.Points.Count - 1].Z : this.Points[this.Points.Count - 1].Y;
}
else
{
// X is inside boundaries
for (int pointIndex = 0; pointIndex < this.Points.Count - 1; pointIndex++)
{
if ((X > this.Points[pointIndex].X) && (X <= this.Points[pointIndex + 1].X))
{
// interpolate in this section
double fractionX = (X - this.Points[pointIndex].X) / (this.Points[pointIndex + 1].X - this.Points[pointIndex].X);
if (pointType == PointType.XZ)
valueYZ = this.Points[pointIndex].Z + fractionX * (this.Points[pointIndex + 1].Z - this.Points[pointIndex].Z);
else
valueYZ = this.Points[pointIndex].Y + fractionX * (this.Points[pointIndex + 1].Y - this.Points[pointIndex].Y);
break;
}
}
}
return valueYZ;
}
public IList IntersectionsXAtZ(double z)
{
var intersectionsX = new List();
if (this.points.Count >= 2)
{ //#bka: Tom is dit geen circular reference? Line staat PLLinesCreator! Die dit weer roept!?
var lineAtZ = new Deltares.Geometry.Line { BeginPoint = new GeometryPoint(this.points.First().X, 0, z), EndPoint = new GeometryPoint(this.points.Last().X, 0, z) };
for (int pointIndex = 0; pointIndex < this.points.Count - 1; pointIndex++)
{
var line = new Deltares.Geometry.Line { BeginPoint = this.points[pointIndex], EndPoint = this.points[pointIndex + 1] };
GeometryPoint intersectionPoint = new GeometryPoint();
if (LineHelper.GetStrictIntersectionPoint(line, lineAtZ, ref intersectionPoint))
{
intersectionsX.Add(intersectionPoint.X);
}
}
}
return intersectionsX;
}
public IList IntersectionPointsXzWithLineXz(Deltares.Geometry.Line line)
{
var intersectionPointsWithLine = new List();
if (this.points.Count >= 2)
{
for (int pointIndex = 0; pointIndex < this.points.Count - 1; pointIndex++)
{
var lineInPoly = new Deltares.Geometry.Line { BeginPoint = this.points[pointIndex], EndPoint = this.points[pointIndex + 1] };
GeometryPoint intersectionPoint = new GeometryPoint();
if (LineHelper.GetStrictIntersectionPoint(lineInPoly, line, ref intersectionPoint))
{
intersectionPointsWithLine.Add(intersectionPoint);
}
}
}
return intersectionPointsWithLine;
}
public override string ToString()
{
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.Append(this.Name);
stringBuilder.Append(" [");
foreach (T point in this.points)
{
if (this.points.IndexOf(point) > 0)
stringBuilder.Append(", ");
stringBuilder.Append(point.ToString());
}
stringBuilder.Append("]");
return stringBuilder.ToString();
}
public virtual void CopyPoints(PolyLine polyLine)
{
foreach (T point in polyLine.Points)
{
points.Add(point);
}
}
///
/// Deletes the coinsiding points.
///
/// The tolerance.
public virtual void DeleteCoinsidingPoints(double tolerance)
{
// First build a list of indices of points that have to be removed (from end of list to start)
var indicesToDelete = new List();
for (int pointIndex = Points.Count - 1; pointIndex > 0; pointIndex--)
{
for (int i = pointIndex - 1; i >= 0; i--)
{
if (Points[pointIndex].LocationEquals(Points[i], tolerance))
{
indicesToDelete.Add(i);
}
}
}
// Remove duplicate points beginning from the end
for (int index = 0; index < indicesToDelete.Count; index++)
{
Points.RemoveAt(indicesToDelete[index]);
}
}
public virtual void DeleteCoinsidingPoints()
{
const double defaultTolerance = 0.001;
DeleteCoinsidingPoints(defaultTolerance);
}
public virtual double MinZ()
{
if (this.Points.Count > 1)
{
double minZ = this.points.First().Z;
foreach (T point in this.points)
{
minZ = Math.Min(minZ, point.Z);
}
return minZ;
}
else
{
return 0.0;
}
}
public virtual double MaxZ()
{
if (this.Points.Count > 1)
{
double maxZ = this.points.First().Z;
foreach (T point in this.points)
{
maxZ = Math.Max(maxZ, point.Z);
}
return maxZ;
}
else
{
return 0.0;
}
}
}
}