using System; using System.Collections.Generic; using System.ComponentModel; using System.Linq; using Deltares.Geographic; using Deltares.Geometry; using Deltares.Geotechnics; using Deltares.Geotechnics.GeotechnicalGeometry; using Deltares.Geotechnics.SurfaceLines; using Deltares.Mathematics; using Deltares.Standard; using Deltares.Standard.Attributes; using Deltares.Standard.Data; using Deltares.Standard.EventPublisher; using Deltares.Standard.Validation; namespace Deltares.DeltaModel { /// /// Holder for revetment schematizations. /// /// The type of surface line revetment segments. public abstract class RevetmentCrossSection : IDisposable where T : SurfaceLineRevetmentSegment { private CreatingDelegatedList segments; private IHasSurfaceLine surfaceLineProvider; protected RevetmentCrossSection() { segments = new CreatingDelegatedList(); Segments.AddMethod = AddSegment; Segments.DeleteMethod = RemoveSegment; } protected RevetmentCrossSection(IHasSurfaceLine surfaceLineProvider) : this() { SurfaceLineProvider = surfaceLineProvider; } /// /// List of all segments of the cross section. /// [PropertyOrder(3, 0)] [Category("Segments")] [Browsable(false)] [Validate] [XmlOldName("RevetmentSegments")] public CreatingDelegatedList Segments { get { return segments; } private set { segments = value; } } /// /// The object which contains a which the segments use to project themselves upon. /// [Browsable(false)] public IHasSurfaceLine SurfaceLineProvider { get { return surfaceLineProvider; } set { surfaceLineProvider = value; foreach (var segment in segments.ToList()) { segment.SurfaceLineProvider = value; } } } /// /// Creates segments using zones by geographically finding intersections the the surafce line of the dike location /// /// List of revetment zones public void ConnectRevetmentZones(List revetmentZones) where U : RevetmentZone { const double tolerance = 100.0; LocalizedGeometryPointString surfaceLine = surfaceLineProvider.SurfaceLine; GeographicString geographicString = surfaceLine.GetGeograpicString(); segments.Clear(); foreach (var revetmentZone in revetmentZones) { IGeographic intersection = GeographicHelper.Instance.GetIntersection(geographicString.Points, revetmentZone.Points); var nearest = GeographicHelper.Instance.GetNearestCoordinatesOnGeographicString(revetmentZone, surfaceLine.Origin.X, surfaceLine.Origin.Y); var distance = Routines2D.Compute2DDistance(nearest.X, nearest.Y, surfaceLine.Origin.X, surfaceLine.Origin.Y); // todo along surfaceline if (distance < tolerance && intersection != null) { // If casting to T does not work, I want to fail hard var segment = (T)Activator.CreateInstance(typeof(T), surfaceLineProvider); segment.SegmentDescription = revetmentZone.Data; var otherPoint = geographicString.Points[0]; if (intersection is IGeographicPoint) { var intersectionPoint = (IGeographicPoint) intersection; double distanceFromPointsStart = Routines2D.Compute2DDistance(intersectionPoint.X, intersectionPoint.Y, otherPoint.X, otherPoint.Y); segment.EndX = distanceFromPointsStart; } else if (intersection is IGeographicString) { var intersectionGeographicString = (GeographicString)intersection; var firstPoint = intersectionGeographicString.Points.First(); var lastPoint = intersectionGeographicString.Points.Last(); var distanceFirstPoint = Routines2D.Compute2DDistance(firstPoint.X, firstPoint.Y, otherPoint.X, otherPoint.Y); var localizedFirstPoint = new GeometryPoint(distanceFirstPoint, 0, surfaceLine.GetZAtX(distanceFirstPoint)); double distanceLastPoint = Routines2D.Compute2DDistance(lastPoint.X, lastPoint.Y, otherPoint.X, otherPoint.Y); var localizedLastPoint = new GeometryPoint(distanceLastPoint, 0, surfaceLine.GetZAtX(distanceLastPoint)); segment.StartX = (distanceFirstPoint < distanceLastPoint) ? localizedFirstPoint.X : localizedLastPoint.X; segment.EndX = (distanceLastPoint >= distanceFirstPoint) ? localizedLastPoint.X : localizedFirstPoint.X; } Segments.Add(segment); } } } public List GetSegments(double start, double end) { const double delta = 0.001; var parts = new List(); var beginPoint = new GeometryPoint(start, 0, SurfaceLineProvider.SurfaceLine.GetZAtX(start)); while (beginPoint.X < end - delta && beginPoint.X < SurfaceLineProvider.SurfaceLine.Points.Last().X) { T segment = null; foreach (T existingSegment in Segments) { if (existingSegment.StartX <= beginPoint.X + delta && existingSegment.EndX >= beginPoint.X - delta) { if (segment == null || existingSegment.EndX > segment.EndX) { segment = existingSegment; } } } // detect next point in the surface line GeometryPoint endPoint = null; for (int i = 0; i < SurfaceLineProvider.SurfaceLine.Points.Count; i++) { if (SurfaceLineProvider.SurfaceLine.Points[i].X > beginPoint.X + delta) { endPoint = SurfaceLineProvider.SurfaceLine.Points[i]; break; } } if (endPoint == null) { break; } if (endPoint.X > end + delta) { endPoint = new GeometryPoint(end, 0, SurfaceLineProvider.SurfaceLine.GetZAtX(end)); } // detect whether there is a segment if (segment != null && segment.EndX < endPoint.X) { endPoint = new GeometryPoint(segment.EndX, 0, SurfaceLineProvider.SurfaceLine.GetZAtX(segment.EndX)); } var segmentLine = new SegmentLine { StartPoint = beginPoint, EndPoint = endPoint, Segment = segment }; parts.Add(segmentLine); beginPoint = endPoint; } return parts; } /// /// Indicates whether the segments cover a section completely /// /// Begin of the section /// End of the section /// Covered completely indication public bool IsCoveredCompletely(double start, double end) { const double delta = 0.001; bool startPointCovered = Segments.Any(p => p.StartX <= start + delta && p.EndX >= start - delta); if (!startPointCovered) { return false; } double reachedX = start; bool gotFurther = true; while (gotFurther) { gotFurther = false; foreach (var segment in Segments.Where(p => p.StartX <= reachedX + delta && p.EndX >= reachedX - delta)) { if (segment.EndX > reachedX) { reachedX = segment.EndX; gotFurther = true; break; } } } return reachedX >= end - delta; } public void Dispose() { Segments.AddMethod = null; Segments.DeleteMethod = null; Segments.CreateMethod = null; } private void RemoveSegment(T segment) { var previousSegment = segments.FirstOrDefault(s => s.IsConnectedTo(segment)); var nextSegment = segments.FirstOrDefault(s => segment.IsConnectedTo(s)); if (null != nextSegment && null != previousSegment) { previousSegment.ConnectTo(nextSegment); } DataEventPublisher.DataListModified(segments); } private void AddSegment(T segment) { if (Double.IsNaN(segment.StartX)) { var index = segments.IndexOf(segment); var previousIndex = index - 1; var nextIndex = index + 1; var previousSegment = previousIndex >= 0 ? segments[previousIndex] : null; var nextSegment = nextIndex < segments.Count ? segments[nextIndex] : null; if (previousSegment != null && nextSegment != null) { previousSegment.DisconnectFrom(nextSegment); nextSegment.StartX = (nextSegment.StartX + nextSegment.EndX) / 2; } segment.StartX = previousSegment == null ? 0 : previousSegment.EndX; segment.EndX = nextSegment == null ? segment.StartX + 5 : nextSegment.StartX; if (previousSegment != null) { previousSegment.ConnectTo(segment); } if (nextSegment != null) { segment.ConnectTo(nextSegment); } } segment.SurfaceLineProvider = surfaceLineProvider; DataEventPublisher.DataListModified(segments); } public class SegmentLine { public GeometryPoint EndPoint; public T Segment; public GeometryPoint StartPoint; public override string ToString() { return string.Format("{0:F3} - {1:F3} : {2}", StartPoint.X, EndPoint.X, Segment != null ? Segment.Description : "null"); } } } }