using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using Deltares.DamEngine.Calculators.Properties;
using Deltares.DamEngine.Data.General;
using Deltares.DamEngine.Data.General.PlLines;
using Deltares.DamEngine.Data.Geometry;
using Deltares.DamEngine.Data.Geotechnics;
using Deltares.DamEngine.Data.Standard;
namespace Deltares.DamEngine.Calculators.KernelWrappers.MacroStabilityCommon
{
public static class PlLinesToWaternetConverter
{
///
/// Converts the pl lines to a waternet.
///
/// The pl lines.
/// The 1D soil profile.
/// Length of the penetration.
/// Left side of the 2D profile.
/// Right side of the 2D profile.
///
public static Waternet ConvertPlLineToWaternet(PlLines plLines, SoilProfile1D soilProfile1D, double penetrationLength, double xLeft, double xRight)
{
ThrowWhenPlLinesIsNull(plLines);
ThrowWhenSoilProfileIsNull(soilProfile1D);
var waternet = new Waternet
{
IsGenerated = false
};
PlLine plLine = plLines.Lines[PlLineType.Pl1];
if (plLine != null && !IsBelowSoilProfile(soilProfile1D, plLine))
{
waternet.PhreaticLine = CreateLine(plLine);
waternet.PhreaticLine.SyncCalcPoints();
}
plLine = plLines.Lines[PlLineType.Pl2];
var headLine = CreateLine(plLine);
if (headLine != null && !IsBelowSoilProfile(soilProfile1D, plLine))
{
waternet.HeadLineList.Add(headLine);
if (soilProfile1D.BottomAquiferLayer != null)
{
var level = soilProfile1D.BottomAquiferLayer.TopLevel + penetrationLength;
var waternetLine = CreateWaternetLine(level, xLeft, xRight);
waternetLine.HeadLine = headLine;
waternetLine.HeadLine.SyncCalcPoints();
waternet.WaternetLineList.Add(waternetLine);
}
}
plLine = plLines.Lines[PlLineType.Pl3];
headLine = CreateLine(plLine);
if (headLine != null && !IsBelowSoilProfile(soilProfile1D, plLine))
{
waternet.HeadLineList.Add(headLine);
if (soilProfile1D.BottomAquiferLayer != null)
{
var level = soilProfile1D.BottomAquiferLayer.TopLevel;
var waternetLine = CreateWaternetLine(level, xLeft, xRight);
waternetLine.HeadLine = headLine;
waternetLine.HeadLine.SyncCalcPoints();
waternet.WaternetLineList.Add(waternetLine);
}
}
plLine = plLines.Lines[PlLineType.Pl4];
headLine = CreateLine(plLine);
if (headLine != null && !IsBelowSoilProfile(soilProfile1D, plLine))
{
waternet.HeadLineList.Add(headLine);
if (soilProfile1D.InBetweenAquiferLayer != null)
{
var level = soilProfile1D.InBetweenAquiferLayer.TopLevel;
var waternetLine = CreateWaternetLine(level, xLeft, xRight);
waternetLine.HeadLine = headLine;
waternetLine.HeadLine.SyncCalcPoints();
waternet.WaternetLineList.Add(waternetLine);
}
}
return waternet;
}
///
/// Converts the to a based on a 2D profile.
///
/// The to convert.
/// The to convert the with.
/// The penetration length.
/// A .
/// Thrown when or
/// is null.
public static Waternet ConvertPlLineToWaternet(PlLines plLines, SoilProfile2D soilProfile, double penetrationLength)
{
ThrowWhenPlLinesIsNull(plLines);
ThrowWhenSoilProfileIsNull(soilProfile);
// Get all the xCoordinates to make cross sections
IEnumerable points = soilProfile.Surfaces.SelectMany(surf => surf.GeometrySurface.OuterLoop.CalcPoints);
var xCoordinates = points.Select(point => point.X).OrderBy(x => x).Distinct().ToArray();
var bottomAquiferCoordinates = GetAquiferCoordinates(sp => sp.BottomAquiferLayer, xCoordinates, soilProfile).ToArray();
var inBetweenAquiferCoordinates = GetAquiferCoordinates(sp => sp.InBetweenAquiferLayer, xCoordinates, soilProfile).ToArray();
var waternet = new Waternet();
PlLine plLine = plLines.Lines[PlLineType.Pl1];
if (plLine != null)
{
waternet.PhreaticLine = CreateLine(plLine);
}
plLine = plLines.Lines[PlLineType.Pl2];
if (plLine != null)
{
var headLine = CreateLine(plLine);
waternet.HeadLineList.Add(headLine);
if (bottomAquiferCoordinates.Any())
{
WaternetLine waternetLine = CreateWaternetLine(bottomAquiferCoordinates, penetrationLength);
waternetLine.HeadLine = headLine;
waternet.WaternetLineList.Add(waternetLine);
}
}
plLine = plLines.Lines[PlLineType.Pl3];
if (plLine != null)
{
var headLine = CreateLine(plLine);
waternet.HeadLineList.Add(headLine);
if (bottomAquiferCoordinates.Any())
{
WaternetLine waternetLine = CreateWaternetLine(bottomAquiferCoordinates);
waternetLine.HeadLine = headLine;
waternet.WaternetLineList.Add(waternetLine);
}
}
plLine = plLines.Lines[PlLineType.Pl4];
if (plLine != null)
{
var headLine = CreateLine(plLine);
waternet.HeadLineList.Add(headLine);
if (inBetweenAquiferCoordinates.Any())
{
WaternetLine waternetLine = CreateWaternetLine(inBetweenAquiferCoordinates);
waternetLine.HeadLine = headLine;
waternet.WaternetLineList.Add(waternetLine);
}
}
return waternet;
}
private static TLineType CreateLine(PlLine plLine)
where TLineType : GeometryPointString, new()
{
if (plLine == null || !plLine.Points.Any())
{
return null;
}
var line = new TLineType();
line.Points.AddRange(plLine.Points);
return line;
}
internal static WaternetLine CreateWaternetLine(double level, double xLeft, double xRight)
{
WaternetLine waternetLine = new WaternetLine();
waternetLine.Points.Add(new GeometryPoint(xLeft, level));
waternetLine.Points.Add(new GeometryPoint(xRight, level));
waternetLine.SyncCalcPoints();
return waternetLine;
}
private static WaternetLine CreateWaternetLine(IEnumerable coordinates)
{
return CreateWaternetLine(coordinates, 0);
}
private static WaternetLine CreateWaternetLine(IEnumerable coordinates, double zOffSet)
{
var line = new WaternetLine();
foreach (Point2D coordinate in coordinates)
{
var point = new GeometryPoint(coordinate.X, coordinate.Z + zOffSet);
line.Points.Add(point);
}
line.SyncCalcPoints();
return line;
}
private static IEnumerable GetAquiferCoordinates(Func getSoilLayerFunc, IEnumerable xCoordinates,
SoilProfile2D soilProfile)
{
SoilLayer1D previousAquiferLayer = null;
var coordinates = new List();
foreach (double xCoordinate in xCoordinates)
{
SoilProfile1D crossSection = soilProfile.GetSoilProfile1D(xCoordinate);
// Determine if the bottom aquifer layer is in range of the previous aquifer layer
// If not, return empty coordinates, because the aquifer layer is interrupted
SoilLayer1D currentAquifer = getSoilLayerFunc(crossSection);
if (previousAquiferLayer != null &&
currentAquifer != null
&& !AreHorizontallyConnected(previousAquiferLayer, currentAquifer))
{
return Enumerable.Empty();
}
if (currentAquifer != null)
{
previousAquiferLayer = currentAquifer;
coordinates.Add(new Point2D(xCoordinate, currentAquifer.TopLevel));
}
}
// Perform a short validation that the coordinates are fully defined from the beginning to the end
// of the profile. If not, the aquifer is not continuous.
if (!coordinates.Any() || coordinates.First().X != xCoordinates.First() || coordinates.Last().X != xCoordinates.Last())
{
return Enumerable.Empty();
}
return coordinates;
}
private static bool AreHorizontallyConnected(SoilLayer1D leftSoilLayer, SoilLayer1D rightSoilLayer)
{
// The layers are identical
if (ReferenceEquals(leftSoilLayer, rightSoilLayer))
{
return true;
}
// Left soil layer envelopes whole right soil layer
if (leftSoilLayer.BottomLevel <= rightSoilLayer.BottomLevel
&& leftSoilLayer.TopLevel >= rightSoilLayer.TopLevel)
{
return true;
}
// Right soil layer envelopes whole left soil layer
if (rightSoilLayer.BottomLevel <= leftSoilLayer.BottomLevel
&& rightSoilLayer.TopLevel >= leftSoilLayer.TopLevel)
{
return true;
}
return (rightSoilLayer.TopLevel <= leftSoilLayer.TopLevel && rightSoilLayer.TopLevel >= leftSoilLayer.BottomLevel) // Top level lies inbetween the left soil layer
|| (rightSoilLayer.BottomLevel >= leftSoilLayer.BottomLevel && rightSoilLayer.BottomLevel <= leftSoilLayer.TopLevel); // Bottom level lies inbetween the left soil layer
}
private static bool IsBelowSoilProfile(SoilProfile1D soilProfile, PlLine line)
{
double bottomSoilProfileLevel = soilProfile.BottomLevel;
return line.Points.Any(point => point.Z <= bottomSoilProfileLevel);
}
///
/// Throws when the soil profile is not assigned.
///
/// The soil profile.
///
private static void ThrowWhenSoilProfileIsNull(SoilProfile soilProfile)
{
if (soilProfile == null)
{
throw new NoNullAllowedException(Resources.PlLinesToWaternetConverter_NoSoilProfileDefined);
}
}
///
/// Throws when the pl lines object is not assigned.
///
/// The pl lines.
///
private static void ThrowWhenPlLinesIsNull(PlLines plLines)
{
if (plLines == null)
{
throw new NoNullAllowedException(Resources.PlLinesToWaternetConverter_NoPlLinesDefined);
}
}
}
}