using System;
using Deltares.Geometry;
using Deltares.Geotechnics.SurfaceLines;
namespace Deltares.Dam.Data
{
public class NonWaterRetainingObjectInSurfaceLine
{
public NonWaterRetainingObject NonWaterRetainingObject { get; set; }
public SurfaceLine2 SurfaceLine { get; set; }
public MStabGridPosition GridPosition { get; set; }
public double StepSizeX { get; set; }
const double MinimumDistanceToEdgeDitch = 0.1000;
///
///
///
///
///
public double DetermineStartLocationForNonWaterRetainingObject(bool skipDitch)
{
// initialise at an invalid return value (i.e. a location outside the surfaceline)
double result = SurfaceLine.Geometry.Points[SurfaceLine.Geometry.Count - 1].X + 100;
const int distanceToEdgeSurfaceLine = 1;
if (NonWaterRetainingObject != null)
{
if (GridPosition == MStabGridPosition.Left)
{
result = Math.Max(SurfaceLine.Geometry.Points[0].X + distanceToEdgeSurfaceLine,
SurfaceLine.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.DikeToeAtRiver).X - NonWaterRetainingObject.MaxDistanceFromToe);
}
else
{
result = Math.Min(SurfaceLine.Geometry.Points[SurfaceLine.Geometry.Count - 1].X - distanceToEdgeSurfaceLine - NonWaterRetainingObject.Btotal(),
SurfaceLine.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.DikeToeAtPolder).X + NonWaterRetainingObject.MaxDistanceFromToe - NonWaterRetainingObject.Btotal());
}
if ((skipDitch) && (DoesPositionXFitInSurfaceLine(result)))
{
// the ditch is only at the polder side so only a problem when the Gridposition is right.
// So if the NWO does coincide with the ditch, the nwo has to be repositioned to the left of the ditch.
NonWaterRetainingObject.Point1 = new GeometryPoint();
NonWaterRetainingObject.Point1.X = result;
NonWaterRetainingObject.Point4 = new GeometryPoint();
NonWaterRetainingObject.Point4.X = result + NonWaterRetainingObject.Btotal();
if (DoesNonWaterRetainingObjectCoincideWithDitch())
{
result = SurfaceLine.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.DitchDikeSide).X -
NonWaterRetainingObject.Btotal() - MinimumDistanceToEdgeDitch;
}
}
}
return result;
}
public bool DoesPositionXFitInSurfaceLine(double fitPositionX)
{
return (fitPositionX >= SurfaceLine.Geometry.Points[0].X) &&
(fitPositionX <= SurfaceLine.Geometry.Points[SurfaceLine.Geometry.Count - 1].X);
}
///
///
///
///
///
///
public double DetermineNewFitPostionX(double fitPositionX, bool skipDitch)
{
double result;
if (GridPosition == MStabGridPosition.Left)
{
result = fitPositionX + StepSizeX;
}
else
{
result = fitPositionX - StepSizeX;
}
if (skipDitch)
{
NonWaterRetainingObject.Point1 = new GeometryPoint();
NonWaterRetainingObject.Point1.X = result;
NonWaterRetainingObject.Point4 = new GeometryPoint();
NonWaterRetainingObject.Point4.X = result + NonWaterRetainingObject.Btotal();
if (DoesNonWaterRetainingObjectCoincideWithDitch())
{
result = SurfaceLine.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.DitchDikeSide).X -
NonWaterRetainingObject.Btotal() - MinimumDistanceToEdgeDitch;
}
}
return result;
}
public double DistanceToToe(double fitPositionX)
{
double result = 0;
if (GridPosition == MStabGridPosition.Left)
{
if ((NonWaterRetainingObject.Point1 != null) && (NonWaterRetainingObject.Point4 != null))
{
result = SurfaceLine.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.DikeToeAtRiver).X -
(fitPositionX + (NonWaterRetainingObject.Point4.X - NonWaterRetainingObject.Point1.X));
}
}
else
{
result = fitPositionX - SurfaceLine.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.DikeToeAtPolder).X;
}
return result;
}
///
/// Create a new instance of , based on
/// , and fits the
/// non water retaining object in that surface line.
///
/// The fit position x.
///
public SurfaceLine2 FitNonWaterRetainingObjectInSurfaceLine(double fitPositionX)
{
// check to see if new position is still valid
if (IsStillValid(fitPositionX))
{
SurfaceLine2 newSurfaceLine = SurfaceLine.FullDeepClone();
if (NonWaterRetainingObject != null)
{
GeometryPoint point1 = new GeometryPoint();
point1.X = fitPositionX;
point1.Z = newSurfaceLine.Geometry.GetZAtX(fitPositionX);
// see if last point of NWO at z1 is above, on, or beneath the surface line. If on, then finished, otherwise turn NWO untill it is.
GeometryPoint point4 = new GeometryPoint();
point4.X = fitPositionX + NonWaterRetainingObject.Btotal();
point4.Z = point1.Z;
var position = newSurfaceLine.Geometry.PositionXzOfPointRelatedToExtrapolatedLine(point4);
var oldposition = position;
var rotationangle = 5.0;
var summedRotationAngle = 0.0;
if (position == RelativeXzPosition.OnGeometricLine)
{
// if point 4 already is on surfaceline, make sure that points 2 and 3 are not rotated
rotationangle = 0;
}
while (position != RelativeXzPosition.OnGeometricLine)
{
if (position == RelativeXzPosition.AboveGeometricLine)
{
point4 = RotatePoint(point1, point4, -rotationangle);
summedRotationAngle -= rotationangle;
}
else
{
point4 = RotatePoint(point1, point4, rotationangle);
summedRotationAngle += rotationangle;
}
position = newSurfaceLine.Geometry.PositionXzOfPointRelatedToExtrapolatedLine(point4);
if (position != oldposition && position != RelativeXzPosition.OnGeometricLine)
{
rotationangle = rotationangle * 0.5;
oldposition = position;
}
}
// now np4 is on the surface line. Delete all existing surfaceline points between fitPositionX and np4.x, then add the NWO lines.
newSurfaceLine.RemoveSegmentIncluding(point1.X, point4.X);
GeometryPoint point2 = new GeometryPoint();
point2.X = point1.X + NonWaterRetainingObject.H1*NonWaterRetainingObject.N1;
point2.Z = point1.Z - NonWaterRetainingObject.H1;
GeometryPoint point3 = new GeometryPoint();
point3.X = point2.X + Math.Sqrt( (NonWaterRetainingObject.B * NonWaterRetainingObject.B) - ( Math.Pow((NonWaterRetainingObject.H2 -
NonWaterRetainingObject.H1), 2)));
point3.Z = point1.Z - NonWaterRetainingObject.H2;;
point2 = RotatePoint(point1, point2, summedRotationAngle);
NonWaterRetainingObject.Point1 = newSurfaceLine.Geometry.GetPointAt(point1.X, 0, point1.Z);
if (NonWaterRetainingObject.Point1 == null)
{
NonWaterRetainingObject.Point1 = new GeometryPoint();
NonWaterRetainingObject.Point1.X = point1.X;
NonWaterRetainingObject.Point1.Z = point1.Z;
newSurfaceLine.AddCharacteristicPoint(NonWaterRetainingObject.Point1);
}
NonWaterRetainingObject.Point2 = newSurfaceLine.Geometry.GetPointAt(point2.X, 0, point2.Z);
if (NonWaterRetainingObject.Point2 == null)
{
NonWaterRetainingObject.Point2 = new GeometryPoint();
NonWaterRetainingObject.Point2.X = point2.X;
NonWaterRetainingObject.Point2.Z = point2.Z;
newSurfaceLine.AddCharacteristicPoint(NonWaterRetainingObject.Point2);
}
point3 = RotatePoint(NonWaterRetainingObject.Point1, point3, summedRotationAngle);
NonWaterRetainingObject.Point3 = newSurfaceLine.Geometry.GetPointAt(point3.X, 0, point3.Z);
if (NonWaterRetainingObject.Point3 == null)
{
NonWaterRetainingObject.Point3 = new GeometryPoint();
NonWaterRetainingObject.Point3.X = point3.X;
NonWaterRetainingObject.Point3.Z = point3.Z;
newSurfaceLine.AddCharacteristicPoint(NonWaterRetainingObject.Point3);
}
NonWaterRetainingObject.Point4 = newSurfaceLine.Geometry.GetPointAt(point4.X, 0, point4.Z);
if (NonWaterRetainingObject.Point4 == null)
{
NonWaterRetainingObject.Point4 = new GeometryPoint();
NonWaterRetainingObject.Point4.X = point4.X;
NonWaterRetainingObject.Point4.Z = point4.Z;
newSurfaceLine.AddCharacteristicPoint(NonWaterRetainingObject.Point4);
}
int nonWater1Index = -1, nonWater2Index = -1, nonWater3Index = -1, nonWater4Index = -1;
// the phreaticline needs adaption, identify the NWO points as characteristic points so the PlLinesCreator can handle that.
for (int i = 0; i < newSurfaceLine.CharacteristicPoints.Count; i++)
{
if (ReferenceEquals(newSurfaceLine.CharacteristicPoints[i].GeometryPoint, NonWaterRetainingObject.Point1))
{
nonWater1Index = i;
}
if (ReferenceEquals(newSurfaceLine.CharacteristicPoints[i].GeometryPoint, NonWaterRetainingObject.Point2))
{
nonWater2Index = i;
}
if (ReferenceEquals(newSurfaceLine.CharacteristicPoints[i].GeometryPoint, NonWaterRetainingObject.Point3))
{
nonWater3Index = i;
}
if (ReferenceEquals(newSurfaceLine.CharacteristicPoints[i].GeometryPoint, NonWaterRetainingObject.Point4))
{
nonWater4Index = i;
}
}
newSurfaceLine.CharacteristicPoints.Annotate(nonWater1Index, CharacteristicPointType.NonWaterRetainingObjectPoint1);
newSurfaceLine.CharacteristicPoints.Annotate(nonWater2Index, CharacteristicPointType.NonWaterRetainingObjectPoint2);
newSurfaceLine.CharacteristicPoints.Annotate(nonWater3Index, CharacteristicPointType.NonWaterRetainingObjectPoint3);
newSurfaceLine.CharacteristicPoints.Annotate(nonWater4Index, CharacteristicPointType.NonWaterRetainingObjectPoint4);
newSurfaceLine.SortPoints();
}
return newSurfaceLine;
}
return null;
}
private GeometryPoint RotatePoint(GeometryPoint centerPoint, GeometryPoint point, double rotationangle)
{
//a positive angle forces a anti clockwise rotation, a negative angle a clockwise rotation
var radangle = rotationangle * Math.PI / 180;
var dX = point.X - centerPoint.X;
var dZ = point.Z - centerPoint.Z;
point.X = (dX * Math.Cos(radangle)) - (dZ * Math.Sin(radangle)) + centerPoint.X;
point.Z = (dX * Math.Sin(radangle)) + (dZ * Math.Cos(radangle)) + centerPoint.Z;
return point;
}
///
///
///
///
///
private bool IsStillValid(double fitPositionX)
{
bool result;
if (GridPosition == MStabGridPosition.Left)
{
result = (fitPositionX + NonWaterRetainingObject.Btotal() <= SurfaceLine.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.DikeToeAtRiver).X);
}
else
{
result = (fitPositionX >= SurfaceLine.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.DikeToeAtPolder).X);
}
return result;
}
private bool DoesNonWaterRetainingObjectCoincideWithDitch()
{
var result = true;
// start by checking whether there is a ditch.
var ditchDikeSide = SurfaceLine.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.DitchDikeSide);
var ditchPolderSide = SurfaceLine.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.DitchPolderSide);
if (ditchDikeSide != null && ditchPolderSide != null)
{
// nwo does not coincide if both point1 and point 4 are either left or right from ditch. Note that the ditch can only exist at the Polder Side!
var ditchLeftX = ditchDikeSide.X;
var ditchRightX = ditchPolderSide.X;
result = (NonWaterRetainingObject.Point4.X < ditchLeftX) ||
(NonWaterRetainingObject.Point1.X > ditchRightX);
}
return !result;
}
}
}