// Copyright (C) Stichting Deltares 2024. All rights reserved.
//
// This file is part of the Dam Engine.
//
// The Dam Engine is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see .
//
// All names, logos, and references to "Deltares" are registered trademarks of
// Stichting Deltares and remain full property of Stichting Deltares at all times.
// All rights reserved.
using System;
using System.Collections.Generic;
using System.Runtime.CompilerServices;
using Deltares.DamEngine.Data.Geometry;
using Deltares.DamEngine.Data.Standard.Language;
using Deltares.DamEngine.Data.Standard.Validation;
namespace Deltares.DamEngine.Data.Geotechnics;
///
/// 2D Soil Profile Object
///
public class SoilProfile2D : SoilProfile
{
protected readonly List surfaces = new List();
protected GeometryData geometry = new GeometryData();
///
/// Initializes a new instance of the class.
///
public SoilProfile2D()
{
Name = LocalizationManager.GetTranslatedText(this, "DefaultNameSoilProfile2D");
}
///
/// Gets the surfaces.
///
///
/// The surfaces.
///
[Validate]
public virtual IList Surfaces
{
get
{
return surfaces;
}
}
///
/// Gets or sets the geometry.
///
///
/// The geometry.
///
public GeometryData Geometry
{
get
{
return geometry;
}
set
{
geometry = value;
}
}
///
/// Gets the soil profile 1D at the given X.
///
/// The x.
/// Soil Profile 1D
public virtual SoilProfile1D GetSoilProfile1D(double x)
{
const double diff = 0.001;
if (Geometry.Surfaces.Count == 0)
{
Geometry.Right = Geometry.MaxGeometryPointsX;
Geometry.Left = Geometry.MinGeometryPointsX;
}
var soilProfile = new SoilProfile1D
{
Name = "Generated at x = " + x + " from " + Name
};
var detector = new LayerDetector(Surfaces);
if (x > Geometry.Right)
{
x = Geometry.Right - diff;
}
if (x < Geometry.Left)
{
x = Geometry.Left + diff;
}
detector.DetermineMaterials(x);
if (detector.LayerList.Count > 0)
{
soilProfile.BottomLevel = detector.LayerList[detector.LayerList.Count - 1].EndPoint.Z;
for (var i = 0; i < detector.LayerList.Count; i++)
{
var layer = new SoilLayer1D(detector.LayerList[i].Soil, detector.LayerList[i].StartPoint.Z)
{
IsAquifer = detector.LayerList[i].IsAquifer
};
soilProfile.Layers.Add(layer);
}
}
return soilProfile;
}
///
/// Get the surface from the point
///
/// The point which is supposed to be within the soil layer
/// Surface
public SoilLayer2D GetSoilLayer(Point2D point)
{
for (var i = 0; i < Surfaces.Count; i++)
{
SoilLayer2D surface = Surfaces[i];
GeometryLoop surfaceLine = surface.GeometrySurface.OuterLoop;
if (surfaceLine.IsPointInLoopArea(point))
{
var found = true;
// if point lies in an innerloop it belongs to another area
foreach (GeometryLoop innerloop in surface.GeometrySurface.InnerLoops)
{
if (innerloop.IsPointInLoopArea(point))
{
found = false;
}
}
if (found)
{
return surface;
}
}
}
return null;
}
///
/// Clone the soil profile 2D
///
/// The cloned SoilProfile2D
public SoilProfile2D Clone()
{
var clonedSoilProfile2D = new SoilProfile2D
{
Name = Name
};
clonedSoilProfile2D.Geometry = geometry.Clone();
foreach (SoilLayer2D surface in Surfaces)
{
SoilLayer2D clonedSurface = surface.Clone();
clonedSoilProfile2D.Surfaces.Add(clonedSurface);
}
foreach (PreConsolidationStress preconsolidationStress in PreconsolidationStresses)
{
clonedSoilProfile2D.PreconsolidationStresses.Add((PreConsolidationStress)preconsolidationStress.Clone());
}
return clonedSoilProfile2D;
}
///
/// Returns a that represents this instance.
///
///
/// A that represents this instance.
///
public override string ToString()
{
return Name;
}
///
/// Get the soil layer from the old surfaces
///
///
///
///
public SoilLayer2D GetOriginalLayerFromOldSurfaces(GeometrySurface geometrySurface, IEnumerable oldSurfaces)
{
return GetOriginalLayerFromOldSurfaces(geometrySurface, oldSurfaces, 0.0);
}
///
/// Get the soil layer from the old surfaces
///
///
///
///
///
private SoilLayer2D GetOriginalLayerFromOldSurfaces(GeometrySurface geometrySurface, IEnumerable oldSurfaces,
double shift)
{
Point2D point = new Point2D(0.0, 0.0);
bool flag1 = false;
foreach (GeometryCurve curve in geometrySurface.OuterLoop.CurveList)
{
point = new Point2D((curve.HeadPoint.X + curve.EndPoint.X) / 2.0, (curve.HeadPoint.Z + curve.EndPoint.Z) / 2.0);
if (IsPointWithinOldSurfaces(point, oldSurfaces, shift, 1E-05) || IsPointWithinOldSurfaces(point, oldSurfaces, shift, -1E-05))
{
point.Z += 1E-05;
if (Routines2D.CheckIfPointIsInPolygon(geometrySurface.OuterLoop, point.X, point.Z) == PointInPolygon.InsidePolygon)
{
flag1 = true;
break;
}
point.Z -= 2E-05;
if (Routines2D.CheckIfPointIsInPolygon(geometrySurface.OuterLoop, point.X, point.Z) == PointInPolygon.InsidePolygon)
{
flag1 = true;
break;
}
}
}
if (!flag1)
{
GeometryPointString topGeometrySurface = geometrySurface.DetermineTopGeometrySurface();
topGeometrySurface.SortPointsByXAscending();
Point2D geometryPoint1 = topGeometrySurface[0];
geometryPoint1.X -= 1E-05;
geometryPoint1.Z -= 1E-05;
Point2D geometryPoint2 = topGeometrySurface[checked (topGeometrySurface.Count - 1)];
geometryPoint2.X += 1E-05;
geometryPoint2.Z -= 1E-05;
int num = this.IsPointWithinOldSurfaces(geometryPoint1, oldSurfaces, shift, -1E-05) ? 1 : 0;
bool flag2 = this.IsPointWithinOldSurfaces(geometryPoint2, oldSurfaces, shift, -1E-05);
double d = double.NaN;
if (num != 0 && !flag2)
{
point.X = geometryPoint1.X;
point.Z = geometryPoint1.Z;
flag1 = true;
d = geometryPoint1.X + 1E-05;
}
if (num == 0 & flag2)
{
point.X = geometryPoint2.X;
point.Z = geometryPoint2.Z;
flag1 = true;
d = geometryPoint2.X - 1E-05;
}
if (!double.IsNaN(d))
{
double xminFromSurfaces = GetXminFromSurfaces(oldSurfaces);
double xmaxFromSurfaces = GetXmaxFromSurfaces(oldSurfaces);
if (d <= xmaxFromSurfaces && d >= xminFromSurfaces)
flag1 = false;
}
}
if (flag1)
{
point.X -= shift;
foreach (SoilLayer2D oldSurface in oldSurfaces)
{
GeometryLoop previousOuterLoop = oldSurface.GeometrySurface.PreviousOuterLoop;
if (previousOuterLoop != null && previousOuterLoop.CurveList.Count > 2 &&
Routines2D.CheckIfPointIsInPolygon(previousOuterLoop, point.X, point.Z) == PointInPolygon.InsidePolygon)
{
bool flag3 = true;
foreach (GeometryLoop previousInnerLoop in oldSurface.GeometrySurface.PreviousInnerLoops)
{
if (Routines2D.CheckIfPointIsInPolygon(previousInnerLoop, point.X, point.Z) == PointInPolygon.InsidePolygon)
flag3 = false;
}
if (flag3)
return oldSurface;
}
}
foreach (SoilLayer2D oldSurface in oldSurfaces)
{
GeometryLoop outerLoop = oldSurface.GeometrySurface.OuterLoop;
if (outerLoop != null && outerLoop.CurveList.Count > 2 && Routines2D.CheckIfPointIsInPolygon(outerLoop, point.X, point.Z) == PointInPolygon.InsidePolygon)
{
bool flag4 = true;
foreach (GeometryLoop innerLoop in oldSurface.GeometrySurface.InnerLoops)
{
if (Routines2D.CheckIfPointIsInPolygon(innerLoop, point.X, point.Z) == PointInPolygon.InsidePolygon)
flag4 = false;
}
if (flag4)
return oldSurface;
}
}
}
return null;
}
private double GetXminFromSurfaces(IEnumerable oldSurfaces)
{
double val1 = double.MaxValue;
foreach (SoilLayer2D oldSurface in oldSurfaces)
val1 = Math.Min(val1, oldSurface.GeometrySurface.OuterLoop.GetMinX());
return val1;
}
private double GetXmaxFromSurfaces(IEnumerable oldSurfaces)
{
double val1 = double.MinValue;
foreach (SoilLayer2D oldSurface in oldSurfaces)
val1 = Math.Max(val1, oldSurface.GeometrySurface.OuterLoop.GetMaxX());
return val1;
}
private bool IsPointWithinOldSurfaces(Point2D point, IEnumerable oldSurfaces, double shift, double deviation)
{
bool flag = false;
point.X -= shift;
point.Z += deviation;
foreach (SoilLayer2D oldSurface in oldSurfaces)
{
GeometryLoop outerLoop = oldSurface.GeometrySurface.OuterLoop;
if (outerLoop != null && Routines2D.CheckIfPointIsInPolygon(outerLoop, point.X, point.Z) == PointInPolygon.InsidePolygon)
{
flag = true;
foreach (GeometryLoop innerLoop in oldSurface.GeometrySurface.InnerLoops)
{
if (Routines2D.CheckIfPointIsInPolygon(innerLoop, point.X, point.Z) == PointInPolygon.InsidePolygon)
flag = false;
}
}
if (!flag)
{
GeometryLoop previousOuterLoop = oldSurface.GeometrySurface.PreviousOuterLoop;
if (previousOuterLoop != null && Routines2D.CheckIfPointIsInPolygon(previousOuterLoop, point.X, point.Z) == PointInPolygon.InsidePolygon)
{
flag = true;
foreach (GeometryLoop previousInnerLoop in oldSurface.GeometrySurface.PreviousInnerLoops)
{
if (Routines2D.CheckIfPointIsInPolygon(previousInnerLoop, point.X, point.Z) == PointInPolygon.InsidePolygon)
flag = false;
}
}
}
if (flag)
return true;
}
return false;
}
}