using System; using System.Collections.Generic; using System.ComponentModel; using System.Xml.Serialization; using Deltares.Geographic; using Deltares.Geotechnics; using Deltares.Geotechnics.Exception; using Deltares.Mathematics; using Deltares.Standard; using Deltares.Standard.Attributes; using Deltares.Standard.EventPublisher; using Deltares.Standard.Reflection; using Deltares.Standard.Units; namespace Deltares.DeltaModel { /// /// Enumeration for dike cross section state: /// UsedCalculated, UsedNotCalculated, NotUsedCalculated, NotUsedNotCalculated /// public enum DikeCrossSectionState { UsedCalculated, UsedNotCalculated, NotUsedCalculated, NotUsedNotCalculated } /// /// DikeLocation as a specific point /// public class DikeCrossSection : DikeLocation, IGeographicPointFromString, IComparable { private IGeographicPoint beginPoint; private IGeographicPoint endPoint; private DikeLinePoint point; private bool used; /// /// Gets or sets the Dike Line Point. /// /// /// The point. /// [Browsable(false)] public DikeLinePoint Point { get { return point; } set { var propertyName = this.GetMemberName(dcs => dcs.Point); DataEventPublisher.BeforeChange(this, propertyName); point = value; if (point != null && DikeLine != null) { point.DikeLine = DikeLine; } DataEventPublisher.AfterChange(this, propertyName); } } /// /// Gets or sets a value indicating whether cross section is used. /// /// /// true if used; otherwise, false. /// [Browsable(false)] [Impact(Impact.Descriptive)] [XmlIgnore] public bool Used { get { return used; } set { this.SetAndNotify2(out used, value, dcs => dcs.Used); } } /// /// Gets the state of the cross section. /// /// /// The state of the cross section. /// [Browsable(false)] [Data] public DikeCrossSectionState CrossSectionState { get { if (Used) { return Double.IsNaN(AssessmentLevel) ? DikeCrossSectionState.UsedNotCalculated : DikeCrossSectionState.UsedCalculated; } return Double.IsNaN(AssessmentLevel) ? DikeCrossSectionState.NotUsedNotCalculated : DikeCrossSectionState.NotUsedCalculated; } } /// /// Gets and Sets the dikeline to which this location belongs /// public override DikeLine DikeLine { get { return base.DikeLine; } set { var dikelineName = this.GetMemberName(dcs => dcs.DikeLine); DataEventPublisher.BeforeChange(this, dikelineName); base.DikeLine = value; if (point != null && value != null) { point.DikeLine = value; } DataEventPublisher.AfterChange(this, dikelineName); } } /// /// Gets or sets the offset of the cross section along the dikeline /// [XmlIgnore] // State persisted by DikeLinePointInstance public override double Offset { get { return point.Offset; } set { point.Offset = value; } } /// /// Gets or sets the X-coordinate of geographic location of this cross section. /// /// /// The X-coordinate of geographic location of this cross section. /// [Label("X-coordinate")] [Description("X-coordinate of geographic location of the cross section")] [Unit(UnitType.Length)] [PropertyOrder(1, 1)] [Format("F2")] [ReadOnly(true)] [XmlIgnore] public double X { get { return point.X; } set { var xName = this.GetMemberName(dcs => dcs.X); DataEventPublisher.BeforeChange(this, xName); point.X = value; DataEventPublisher.AfterChange(this, xName); } } /// /// Gets or sets the Y-coordinate of geographic location of this cross section. /// /// /// The Y-coordinate of geographic location of this cross section. /// [Label("Y-coordinate")] [Description("Y-coordinate of geographic location of the cross section")] [Unit(UnitType.Length)] [PropertyOrder(1, 2)] [Format("F2")] [ReadOnly(true)] [XmlIgnore] public double Y { get { return point.Y; } set { var yName = this.GetMemberName(dcs => dcs.Y); DataEventPublisher.BeforeChange(this, yName); point.Y = value; DataEventPublisher.AfterChange(this, yName); } } /// /// Connects the piezometric heads. /// /// The piezometric heads. public void ConnectPiezometricHeads(IEnumerable piezometricHeads) { PiezometricHeads = PiezometricHeads.SnapToPoint(Point, piezometricHeads); } /// /// Connects the revetment cross sections. /// /// The revetment cross sections. public void ConnectRevetmentCrossSections(IEnumerable revetmentCrossSections) { foreach (var revetmentCrossSection in revetmentCrossSections) { if (revetmentCrossSection.BeginOffset <= Offset && revetmentCrossSection.EndOffset >= Offset) { BlockRevetmentCrossSection = revetmentCrossSection; return; } } BlockRevetmentCrossSection = null; } public override IGeographicPoint GetRepresentivePoint() { return Point; } public override string ToString() { return Name; } public int CompareTo(DikeCrossSection other) { return Point.CompareTo(other.Point); } public override bool Equals(object obj) { var otherCrossSection = obj as DikeCrossSection; if (ReferenceEquals(this, obj)) { return true; } if (otherCrossSection != null) { return Point.Equals(otherCrossSection.Point); } return false; } public override int GetHashCode() { return Point.GetHashCode(); } public void SetPointFromString(IList lineString) { const double tolerance = 1e-6; if (lineString.Count < 2) { throw new TooFewPointOnLineException(); } beginPoint = lineString[0]; endPoint = lineString[lineString.Count - 1]; var beginPoint2D = beginPoint.ToPoint2D(); var endPoint2D = endPoint.ToPoint2D(); var found = false; var expectingPointIntersection = false; for (var k = 0; k < DikeLine.Points.Count - 1; k++) { var currentDikeLinePoint = DikeLine.Points[k].ToPoint2D(); var nextDikeLinePoint = DikeLine.Points[k + 1].ToPoint2D(); Point2D intersectionPoint; var intersection = Routines2D.DetermineIf2DLinesIntersectStrickly(beginPoint2D, endPoint2D, currentDikeLinePoint, nextDikeLinePoint, out intersectionPoint, tolerance); if (intersection == LineIntersection.Intersects) { if (!expectingPointIntersection) { if (found) { throw new MultipleIntersectionsWithLineException(); } found = true; Point = new DikeLinePoint(intersectionPoint.X, intersectionPoint.Y, DikeLine); } expectingPointIntersection = !expectingPointIntersection && Routines2D.DetermineIfPointsCoincide(nextDikeLinePoint, intersectionPoint, tolerance); } } } } }