// 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; } }