// Copyright (C) Stichting Deltares 2024. All rights reserved. // // This file is part of the application DAM - UI. // // DAM - UI is free software: you can redistribute it and/or modify // it under the terms of the GNU 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 General Public License for more details. // // You should have received a copy of the GNU 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.Drawing; using System.Linq; using Components.Persistence.Stability.Version2.Data; using Deltares.Geometry; using Deltares.Geotechnics.Soils; using Deltares.Mathematics; namespace Deltares.Dam.StixFileReader; /// /// Creates a from a . /// public class SoilProfile2DDataModel { /// /// Converts a to a . /// /// /// /// public SoilProfile2D Create(PersistableDataModel dataModel, double offsetX) { string geometryId = dataModel.Scenarios.Last().Stages.Last().GeometryId; PersistableGeometry geometry = dataModel.Geometry.First(g => g.Id == geometryId); var soilProfile2D = new SoilProfile2D(); foreach (PersistableLayer layer in geometry.Layers) { CreateCurvesFromLayer(layer, soilProfile2D.Geometry.Curves, offsetX); GeometrySurface surface = CreateSurfacesFromLayer(layer, soilProfile2D.Geometry.Surfaces, offsetX); foreach (PersistablePoint point in layer.Points) { if (!IsPointPresent(point, soilProfile2D.Geometry.Points, offsetX)) { soilProfile2D.Geometry.Points.Add(new GeometryPoint(point.X + offsetX, 0, point.Z)); } } PersistableSoil persistableSoil = FetchSoilProperties(layer.Id, dataModel); var soil = new Soil(); if (persistableSoil != null) { soil.Name = persistableSoil.Name; soil.Color = FetchSoilColor(persistableSoil, dataModel); } var soilLayer2D = new SoilLayer2D { Soil = soil, GeometrySurface = surface }; soilProfile2D.Surfaces.Add(soilLayer2D); } soilProfile2D.Geometry.Rebox(); CreateInnerLoops(soilProfile2D); return soilProfile2D; } private Color FetchSoilColor(PersistableSoil persistableSoil, PersistableDataModel dataModel) { var color = new Color(); if (dataModel.SoilVisualizations == null) { return color; } foreach (PersistableSoilVisualization soilVisualization in dataModel.SoilVisualizations.SoilVisualizations) { if (soilVisualization.SoilId == persistableSoil.Id) { color = soilVisualization.Color; } } return color; } private PersistableSoil FetchSoilProperties(string layerId, PersistableDataModel dataModel) { var soilId = string.Empty; foreach (PersistableSoilLayerCollection soilLayer in dataModel.SoilLayers) { foreach (PersistableSoilLayer persistableSoilLayer in soilLayer.SoilLayers) { if (persistableSoilLayer.LayerId == layerId) { soilId = persistableSoilLayer.SoilId; } } } return soilId == string.Empty ? null : dataModel.Soils.Soils.FirstOrDefault(soil => soil.Id == soilId); } private GeometrySurface CreateSurfacesFromLayer(PersistableLayer layer, ICollection geometrySurface, double offsetX) { var surface = new GeometrySurface(); for (var i = 0; i < layer.Points.Count(); i++) { surface.OuterLoop.Points.Add(new GeometryPoint(layer.Points.ElementAt(i).X + offsetX, 0, layer.Points.ElementAt(i).Z)); for (var j = 0; j < layer.Points.Count(); j++) { GeometryCurve curve = CreateCurveFromLayer(layer, j, offsetX); if (!IsCurvePresent(curve, surface.OuterLoop.CurveList)) { surface.OuterLoop.CurveList.Add(curve); } } surface.Name = layer.Label; } geometrySurface.Add(surface); return surface; } private void CreateCurvesFromLayer(PersistableLayer layer, ICollection geometryCurves, double offsetX) { for (var i = 0; i < layer.Points.Count(); i++) { GeometryCurve curve = CreateCurveFromLayer(layer, i, offsetX); if (!IsCurvePresent(curve, geometryCurves)) { geometryCurves.Add(curve); } } //GeometryCurve curve = CreateCurveFromLayer(layer, i, offsetX); } private GeometryCurve CreateCurveFromLayer(PersistableLayer layer, int index, double offsetX) { GeometryCurve curve; if (index == layer.Points.Count() - 1) { curve = CreateCurve(layer.Points.ElementAt(index), layer.Points.ElementAt(0), offsetX); } else { curve = CreateCurve(layer.Points.ElementAt(index), layer.Points.ElementAt(index + 1), offsetX); } return curve; } private GeometryCurve CreateCurve(PersistablePoint firstPoint, PersistablePoint secondPoint, double offsetX) { return new GeometryCurve { HeadPoint = new GeometryPoint(firstPoint.X + offsetX, 0, firstPoint.Z), EndPoint = new GeometryPoint(secondPoint.X + offsetX, 0, secondPoint.Z) }; } private bool IsCurvePresent(GeometryCurve curve, IEnumerable geometryCurves) { return geometryCurves.Any(geometryCurve => (ArePointsEqual(geometryCurve.HeadPoint, curve.HeadPoint) && ArePointsEqual(geometryCurve.EndPoint, curve.EndPoint)) || (ArePointsEqual(geometryCurve.EndPoint, curve.HeadPoint) && ArePointsEqual(geometryCurve.HeadPoint, curve.EndPoint))); } private bool IsPointPresent(PersistablePoint point, IEnumerable geometryPoints, double offsetX) { return geometryPoints.Any(geometryPoint => ArePointsEqual(geometryPoint, point, offsetX)); } private bool ArePointsEqual(GeometryPoint firstPoint, GeometryPoint secondPoint) { const double pointTolerance = 1E-6; return (Math.Abs(firstPoint.X - secondPoint.X) < pointTolerance) && (Math.Abs(firstPoint.Z - secondPoint.Z) < pointTolerance); } private bool ArePointsEqual(GeometryPoint firstPoint, PersistablePoint secondPoint, double offsetX) { const double pointTolerance = 1E-6; return (Math.Abs(firstPoint.X - (secondPoint.X + offsetX)) < pointTolerance) && (Math.Abs(firstPoint.Z - secondPoint.Z) < pointTolerance); } private struct LayerConnection(int innerLayer, int outerLayer, double areaOuterLayer) { public int InnerLayer { get; set; } = innerLayer; public int OuterLayer { get; set; } = outerLayer; public double AreaOuterLayer { get; set; } = areaOuterLayer; } private static void CreateInnerLoops(SoilProfile2D soilProfile) { List layerConnections = FindAllInnerLoops(soilProfile); // When layer 1 is in layer 2 and layer 2 is in layer 3, layer 3 is not an inner loop of layer 1 if (layerConnections.Count > 0) { List uniqueInnerLayers = layerConnections .Select(lc => lc.InnerLayer) .Distinct() .ToList(); foreach (int innerLayer in uniqueInnerLayers) { LayerConnection largestAreaConnection = layerConnections .Where(lc => lc.InnerLayer == innerLayer) .OrderByDescending(lc => lc.AreaOuterLayer) .LastOrDefault(); GeometryLoop loop = soilProfile.Surfaces[largestAreaConnection.InnerLayer].GeometrySurface.OuterLoop; soilProfile.Surfaces[largestAreaConnection.OuterLayer].GeometrySurface.AddInnerLoop(loop); } } } private static List FindAllInnerLoops(SoilProfile2D soilProfile) { var layerConnections = new List(); for (var index1 = 0; index1 < soilProfile.Surfaces.Count; index1++) { GeometryLoop loop1 = soilProfile.Surfaces[index1].GeometrySurface.OuterLoop; for (var index2 = 0; index2 < soilProfile.Surfaces.Count; index2++) { if (index1 == index2) { continue; } GeometryLoop loop2 = soilProfile.Surfaces[index2].GeometrySurface.OuterLoop; if (loop2.Points.All(loop1.IsPointInLoopArea) && CentroidOfLoop2IsInLoop1(loop2, loop1)) { layerConnections.Add(new LayerConnection(index2, index1, loop1.Area())); } } } return layerConnections; } private static bool CentroidOfLoop2IsInLoop1(GeometryLoop loop2, GeometryLoop loop1) { List loop2Points = loop2.GetLocalPoint2DList(); Point2D centroidOfLoop2Point2D = Routines2D.DeterminePolygonCentroid(loop2Points); var centroidOfLoop2 = new GeometryPoint(centroidOfLoop2Point2D.X, 0, centroidOfLoop2Point2D.Y); bool centroidOfLoop2IsInLoop1 = loop1.IsPointInLoopArea(centroidOfLoop2); return centroidOfLoop2IsInLoop1; } }