using System; using System.Collections.Generic; using System.Linq; using Deltares.Dam.Data.Sensors.Specifications; using Deltares.Geometry; using Deltares.Geotechnics; using Deltares.Geotechnics.SurfaceLines; using Deltares.Standard.Specifications.Extensions; namespace Deltares.Dam.Data.Sensors { internal class SensorPLLine1Creator : SensorPLLineCreatorBase { public SensorPLLine1Creator(SensorLocation sensorLocation, IDictionary sensorValues) : base(sensorLocation, PLLineType.PL1, sensorValues) { } /// /// Creates the PL line. /// /// public override PLLine CreatePLLine() { var lineConstructor = new PLLineConstructor(); double waterLevel = 0; try { waterLevel = WaterLevelAtRiver; } catch (Exception e) { throw new PLLinesCreatorException("There was an error trying to read the water level", e); } // Make sure there is an intersection with the surfaceline waterLevel = this.SensorLocation.SurfaceLine.EnsureWaterLevelIsAboveRiverBottom(waterLevel).Value; // Add begin boundary lineConstructor.Insert(new PLLinePoint(XBeginBoundary, waterLevel)); // add all sensors to the pl line var sortedSensors = SensorsSortedAlongProfile.ToList(); double lastZ = waterLevel; double lastX = XBeginBoundary; foreach (Sensor sensor in sortedSensors) { var x = lastX = GetSensorXValue(sensor); var z = lastZ = GetSensorZValue(sensor); var point = new PLLinePoint(x, z) { Name = sensor.Name }; lineConstructor.Insert(point); } // insert intersection point (at dike river side) var xIntersection = IntersectionXAtRiverWaterLevel(waterLevel); lineConstructor.Insert(new PLLinePoint(xIntersection, waterLevel) { Name = "Intersection point dike river side" }); // insert offset below dike top at river point? var useLocationAsDataSource = new UseLocationAsDataSource(); if (useLocationAsDataSource.IsSatisfiedBy(SensorLocation.SourceTypePl1PlLineOffsetBelowDikeTopAtRiver)) { double offset = waterLevel - SensorLocation.PLLineOffsetBelowDikeTopAtRiver; lineConstructor.Insert(new PLLinePoint(XDikeTopAtRiver, offset)); } // insert offset below dike top at polder point? if (useLocationAsDataSource.IsSatisfiedBy(SensorLocation.SourceTypePl1PlLineOffsetBelowDikeTopAtPolder)) { double offset = waterLevel - SensorLocation.PLLineOffsetBelowDikeTopAtPolder; var x = XDikeTopAtPolder; lineConstructor.Insert(new PLLinePoint(x, offset)); } // insert offset below shoulder base inside? if (useLocationAsDataSource.IsSatisfiedBy(SensorLocation.SourceTypePl1PlLineOffsetBelowShoulderBaseInside)) { double offset = lastZ = ZShouldeBaseInside - SensorLocation.PLLineOffsetDryBelowShoulderBaseInside; lineConstructor.Insert(new PLLinePoint(XShoulderBaseInside, offset)); } // insert offset below dike toe at river? if (useLocationAsDataSource.IsSatisfiedBy(SensorLocation.SourceTypePl1PlLineOffsetBelowDikeToeAtPolder)) { double offset = lastZ = ZDikeToeAtPolder - SensorLocation.PLLineOffsetBelowDikeToeAtPolder; var x = XDikeToeAtPolder; lineConstructor.Insert(new PLLinePoint(x, offset)); if (lastX < x) lastX = x; } if (DikeHasDitch) { var ditchWaterLevelSensor = SensorLocation.Sensors .GetBySpecification(new DitchWaterLevelSensorSpecification(SensorLocation.SurfaceLine.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.DitchDikeSide).X, SensorLocation.SurfaceLine.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.DitchPolderSide).X)) .FirstOrDefault(); var polderLevel = ditchWaterLevelSensor != null ? SensorValues[ditchWaterLevelSensor] : PolderLevel; double? intersection = GetDitchWaterLevelIntersectionAtXDikeSide(polderLevel); if (intersection != null) { lineConstructor.Insert(new PLLinePoint(intersection.Value, polderLevel)); double? intersectionPolderSide = GetDitchWaterLevelIntersectionAtXPolderSide(polderLevel); if (intersectionPolderSide != null) lineConstructor.Insert(new PLLinePoint(intersectionPolderSide.Value, polderLevel)); } lineConstructor.Insert(new PLLinePoint(XEndBoundary, polderLevel)); } else { double depth = lastZ; double xLocation = XDikeToeAtPolder; if (useLocationAsDataSource.IsSatisfiedBy(SensorLocation.SourceTypePl1PlLineOffsetBelowDikeToeAtPolder)) { depth = ZDikeToeAtPolder - SensorLocation.PLLineOffsetBelowDikeToeAtPolder; } else { var sensor = PolderLevelSensor; if (sensor != null) { xLocation = sensor.RelativeLocation; depth = PolderLevel; } } lineConstructor.Insert(new PLLinePoint(xLocation, depth)); // always continue horiontal to end lineConstructor.Insert(new PLLinePoint(XEndBoundary, depth)); /* * TODO: verify with Kin Sun else if (lastZ <= PolderLevel) { lineConstructor.Insert(new PLLinePoint(XEndBoundary, lastZ)); } else { // add tail of surface line foreach (GeometryPoint geometryPoint in SensorLocation.SurfaceLine.GetSurfaceLineTailExcluding(lastX)) { lineConstructor.Insert(new PLLinePoint(geometryPoint.X, geometryPoint.Z) { Name = geometryPoint.Name }); } } */ } return lineConstructor.CreatePLLine(PLLineType); } /// /// Gets the Polders the level intersection at X dike side. /// /// The polder level. /// public double? GetDitchWaterLevelIntersectionAtXDikeSide(double level) { var ditchDikeSide = SensorLocation.SurfaceLine.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.DitchDikeSide); if (ditchDikeSide == null) throw new PLLinesCreatorException("Ditch at dike side is not defined in surface line, but was expected"); var ditchPolderSide = SensorLocation.SurfaceLine.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.DitchPolderSide); if (ditchPolderSide == null) throw new PLLinesCreatorException("Ditch at polder side is not defined in surface line, but was expected"); var ditchBottomDikeSide = SensorLocation.SurfaceLine.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.BottomDitchDikeSide); if (ditchBottomDikeSide == null) throw new PLLinesCreatorException("Ditch at bottom polder side is not defined in surface line, but was expected"); var waterlevelLine = new Deltares.Geometry.Line(); double startX = SensorLocation.SurfaceLine.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.SurfaceLevelOutside).X; double endX = SensorLocation.SurfaceLine.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.SurfaceLevelInside).X; var waterLevelBeginPoint = new GeometryPoint(startX, 0, level); var waterLevelEndPoint = new GeometryPoint(endX, 0, level); waterlevelLine.SetBeginAndEndPoints(waterLevelBeginPoint, waterLevelEndPoint); var surfaceLineSegment = new Deltares.Geometry.Line(); var beginPoint = new GeometryPoint(ditchDikeSide.X, 0, ditchDikeSide.Z); var endPoint = new GeometryPoint(ditchBottomDikeSide.X, 0, ditchBottomDikeSide.Z); surfaceLineSegment.SetBeginAndEndPoints(beginPoint, endPoint); GeometryPoint intersectPoint = surfaceLineSegment.GetIntersectPointXZ(waterlevelLine); if (intersectPoint != null) { return intersectPoint.X; } return null; } public double? GetDitchWaterLevelIntersectionAtXPolderSide(double level) { var ditchDikeSide = SensorLocation.SurfaceLine.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.DitchDikeSide); if (ditchDikeSide == null) throw new PLLinesCreatorException("Ditch at dike side is not defined in surface line, but was expected"); var ditchPolderSide = SensorLocation.SurfaceLine.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.DitchPolderSide); if (ditchPolderSide == null) throw new PLLinesCreatorException("Ditch at polder side is not defined in surface line, but was expected"); var ditchBottomPolderSide = SensorLocation.SurfaceLine.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.BottomDitchPolderSide); if (ditchBottomPolderSide == null) throw new PLLinesCreatorException("Ditch at bottom polder side is not defined in surface line, but was expected"); var waterlevelLine = new Deltares.Geometry.Line(); double startX = SensorLocation.SurfaceLine.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.SurfaceLevelOutside).X; double endX = SensorLocation.SurfaceLine.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.SurfaceLevelInside).X; var waterLevelBeginPoint = new GeometryPoint(startX, 0, level); var waterLevelEndPoint = new GeometryPoint(endX, 0, level); waterlevelLine.SetBeginAndEndPoints(waterLevelBeginPoint, waterLevelEndPoint); var surfaceLineSegment = new Deltares.Geometry.Line(); var beginPoint = new GeometryPoint(ditchPolderSide.X, 0, ditchPolderSide.Z); var endPoint = new GeometryPoint(ditchBottomPolderSide.X, 0, ditchBottomPolderSide.Z); surfaceLineSegment.SetBeginAndEndPoints(beginPoint, endPoint); GeometryPoint intersectPoint = surfaceLineSegment.GetIntersectPointXZ(waterlevelLine); if (intersectPoint != null) { return intersectPoint.X; } return null; } /// /// Gets the water level at river. /// protected double WaterLevelAtRiver { get { Sensor sensor = null; try { // use single, because there should be exactly one waterlevel sensor sensor = WaterLevelSensor; } catch (Exception e) { throw new PLLinesCreatorException("There are multiple or no water level sensors defined.", e); } var value = SensorLocation.GetValue(x => x.SourceTypePl1WaterLevelAtRiver, SensorValues, sensor); if (value.HasValue) return value.Value; var message = string.Format("Water level at river for the location '{0}' was not set or initialized", SensorLocation.LocationName); throw new PLLinesCreatorException(message); } } /// /// Gets the polder level. /// public double PolderLevel { get { var sensor = PolderLevelSensor; if (sensor != null) { var value = SensorLocation.GetValue(x => x.SourceTypePl1WaterLevelAtPolder, SensorValues, sensor); if (value.HasValue) return value.Value; var message = string.Format("Polder level at river for the location '{0}' was not set or initialized", SensorLocation.LocationName); throw new PLLinesCreatorException(message); } else { return SensorLocation.PolderLevel; } } } /// /// Gets the X dike top at river. /// public double XDikeTopAtRiver { get { return SensorLocation.SurfaceLine.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.DikeTopAtRiver).X; } } /// /// Gets the X dike top at polder. /// public double XDikeTopAtPolder { get { return SensorLocation.SurfaceLine.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.DikeTopAtPolder).X; } } /// /// Gets the X dike toe at polder. /// public double XDikeToeAtPolder { get { return SensorLocation.SurfaceLine.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.DikeToeAtPolder).X; } } /// /// Gets the X shoulder base inside. /// public double XShoulderBaseInside { get { return SensorLocation.SurfaceLine.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.ShoulderBaseInside).X; } } /// /// Gets the Z shoulde base inside. /// public double ZShouldeBaseInside { get { return SensorLocation.SurfaceLine.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.ShoulderBaseInside).Z; } } /// /// Gets the Z dike toe at polder. /// public double ZDikeToeAtPolder { get { return SensorLocation.SurfaceLine.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.DikeToeAtPolder).Z; } } /// /// Gets the index of the insert position for a given value x in the line of points /// /// The line. /// The x value. /// private int GetIndexOf(PLLine line, double xValue) { int index = 0; foreach (var point in line.Points) { if (xValue > point.X) index++; else break; } return index; } } }