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