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