// Copyright (C) Stichting Deltares 2017. All rights reserved.
//
// This file is part of Ringtoets.
//
// Ringtoets 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.Linq;
using Core.Common.Base.Data;
using Core.Common.Base.Geometry;
using Core.Components.Chart.Data;
using Ringtoets.MacroStabilityInwards.Data;
using Ringtoets.MacroStabilityInwards.Primitives;
namespace Ringtoets.MacroStabilityInwards.Forms.Factories
{
///
/// Factory for creating arrays of to use in
/// (created via ).
///
internal static class MacroStabilityInwardsChartDataPointsFactory
{
///
/// Create surface line points in 2D space based on the provided .
///
/// The to create the surface line points for.
/// An array of points in 2D space or an empty array when is null.
public static Point2D[] CreateSurfaceLinePoints(MacroStabilityInwardsSurfaceLine surfaceLine)
{
return surfaceLine?.LocalGeometry.ToArray() ?? new Point2D[0];
}
///
/// Create a surface level outside point in 2D space based on the provided .
///
/// The surface line to create the surface level outside point for.
/// An array with a surface level outside point in 2D space or an empty array when:
///
/// - is null;
/// - the surface level outside point in is null.
///
///
public static Point2D[] CreateSurfaceLevelOutsidePoint(MacroStabilityInwardsSurfaceLine surfaceLine)
{
return GetLocalPointsFromGeometry(surfaceLine, surfaceLine?.SurfaceLevelOutside);
}
///
/// Create a dike top at river point in 2D space based on the provided .
///
/// The surface line to create the dike top at river point for.
/// An array with a dike top at river point in 2D space or an empty array when:
///
/// - is null;
/// - the dike top at river point in is null.
///
///
public static Point2D[] CreateDikeTopAtRiverPoint(MacroStabilityInwardsSurfaceLine surfaceLine)
{
return GetLocalPointsFromGeometry(surfaceLine, surfaceLine?.DikeTopAtRiver);
}
///
/// Create a dike toe at river point in 2D space based on the provided .
///
/// The surface line to create the dike toe at river point for.
/// An array with a dike toe at river point in 2D space or an empty array when:
///
/// - is null;
/// - the dike toe at river point in is null.
///
///
public static Point2D[] CreateDikeToeAtRiverPoint(MacroStabilityInwardsSurfaceLine surfaceLine)
{
return GetLocalPointsFromGeometry(surfaceLine, surfaceLine?.DikeToeAtRiver);
}
///
/// Create a dike top at polder point in 2D space based on the provided .
///
/// The surface line to create the dike top at polder point for.
/// An array with a dike top at polder point in 2D space or an empty array when:
///
/// - is null;
/// - the dike top at polder point in is null.
///
///
public static Point2D[] CreateDikeTopAtPolderPoint(MacroStabilityInwardsSurfaceLine surfaceLine)
{
return GetLocalPointsFromGeometry(surfaceLine, surfaceLine?.DikeTopAtPolder);
}
///
/// Create a shoulder base inside point in 2D space based on the provided .
///
/// The surface line to create the shoulder base inside point for.
/// An array with a shoulder base inside point in 2D space or an empty array when:
///
/// - is null;
/// - the shoulder base inside point in is null.
///
///
public static Point2D[] CreateShoulderBaseInsidePoint(MacroStabilityInwardsSurfaceLine surfaceLine)
{
return GetLocalPointsFromGeometry(surfaceLine, surfaceLine?.ShoulderBaseInside);
}
///
/// Create a shoulder top inside point in 2D space based on the provided .
///
/// The surface line to create the shoulder top inside point for.
/// An array with a shoulder top inside point in 2D space or an empty array when:
///
/// - is null;
/// - the shoulder top inside point in is null.
///
///
public static Point2D[] CreateShoulderTopInsidePoint(MacroStabilityInwardsSurfaceLine surfaceLine)
{
return GetLocalPointsFromGeometry(surfaceLine, surfaceLine?.ShoulderTopInside);
}
///
/// Create a dike toe at polder point in 2D space based on the provided .
///
/// The surface line to create the dike toe at polder point for.
/// An array with a dike toe at polder point in 2D space or an empty array when:
///
/// - is null;
/// - the dike toe at polder point in is null.
///
///
public static Point2D[] CreateDikeToeAtPolderPoint(MacroStabilityInwardsSurfaceLine surfaceLine)
{
return GetLocalPointsFromGeometry(surfaceLine, surfaceLine?.DikeToeAtPolder);
}
///
/// Create a ditch dike side point in 2D space based on the provided .
///
/// The surface line to create the ditch dike side point for.
/// An array with a ditch dike side point in 2D space or an empty array when:
///
/// - is null;
/// - the ditch dike side point in is null.
///
///
public static Point2D[] CreateDitchDikeSidePoint(MacroStabilityInwardsSurfaceLine surfaceLine)
{
return GetLocalPointsFromGeometry(surfaceLine, surfaceLine?.DitchDikeSide);
}
///
/// Create a bottom ditch dike side point in 2D space based on the provided .
///
/// The surface line to create the bottom ditch dike side point for.
/// An array with a bottom ditch dike side point in 2D space or an empty array when:
///
/// - is null;
/// - the bottom ditch dike side point in is null.
///
///
public static Point2D[] CreateBottomDitchDikeSidePoint(MacroStabilityInwardsSurfaceLine surfaceLine)
{
return GetLocalPointsFromGeometry(surfaceLine, surfaceLine?.BottomDitchDikeSide);
}
///
/// Create a bottom ditch polder side point in 2D space based on the provided .
///
/// The surface line to create the bottom ditch polder side point for.
/// An array with a bottom ditch polder side point in 2D space or an empty array when:
///
/// - is null;
/// - the bottom ditch polder side point in is null.
///
///
public static Point2D[] CreateBottomDitchPolderSidePoint(MacroStabilityInwardsSurfaceLine surfaceLine)
{
return GetLocalPointsFromGeometry(surfaceLine, surfaceLine?.BottomDitchPolderSide);
}
///
/// Create a surface level inside point in 2D space based on the provided .
///
/// The surface line to create the surface level inside point for.
/// An array with a surface level inside point in 2D space or an empty array when:
///
/// - is null;
/// - the surface level inside point in is null.
///
///
public static Point2D[] CreateSurfaceLevelInsidePoint(MacroStabilityInwardsSurfaceLine surfaceLine)
{
return GetLocalPointsFromGeometry(surfaceLine, surfaceLine?.SurfaceLevelInside);
}
///
/// Create a ditch polder side point in 2D space based on the provided .
///
/// The surface line to create the ditch polder side point for.
/// An array with a ditch polder side point in 2D space or an empty array when:
///
/// - is null;
/// - the ditch polder side point in is null.
///
///
public static Point2D[] CreateDitchPolderSidePoint(MacroStabilityInwardsSurfaceLine surfaceLine)
{
return GetLocalPointsFromGeometry(surfaceLine, surfaceLine?.DitchPolderSide);
}
///
/// Create areas of holes in 2D space based on the provided .
///
/// The soil profile to create the holes for.
/// An array with an array of points in 2D space or an empty array when
/// is null.
public static IEnumerable CreateHolesAreas(IMacroStabilityInwardsSoilProfileUnderSurfaceLine soilProfile)
{
return soilProfile?.Layers.SelectMany(l => l.Holes).ToArray() ?? new Point2D[0][];
}
///
/// Create an area of the outer ring in 2D space based on the provided .
///
/// The soil layer to create the outer ring for.
/// A collection containing a single array of points in 2D space
/// or an empty collection when is null.
public static IEnumerable CreateOuterRingArea(IMacroStabilityInwardsSoilLayerUnderSurfaceLine soilLayer)
{
return soilLayer != null
? new[]
{
soilLayer.OuterRing
}
: new Point2D[0][];
}
///
/// Create points of the phreatic line in 2D space based on the provided .
///
/// The phreatic line to create the points for.
/// An array of points in 2D space or an empty array when
/// is null.
public static Point2D[] CreatePhreaticLinePoints(MacroStabilityInwardsPhreaticLine phreaticLine)
{
return phreaticLine?.Geometry.ToArray() ?? new Point2D[0];
}
///
/// Create points of the waternet zone in 2D space based on the provide .
///
/// The waternet line to create the zone for.
/// The that may intersect with
/// the and by doing that restricts the
/// drawn height of it.
/// An array of points in 2D space or an empty array when or
/// is null.
public static IEnumerable CreateWaternetZonePoints(MacroStabilityInwardsWaternetLine waternetLine,
MacroStabilityInwardsSurfaceLine surfaceLine)
{
if (waternetLine == null || surfaceLine == null)
{
return new Point2D[0][];
}
Point2D[] surfaceLineLocalGeometry = surfaceLine.LocalGeometry.ToArray();
Point2D[] phreaticLineGeometry = waternetLine.PhreaticLine.Geometry.ToArray();
Point2D[] waternetLineGeometry = waternetLine.Geometry.ToArray();
return IsSurfaceLineAboveWaternetZone(surfaceLineLocalGeometry, waternetLineGeometry, phreaticLineGeometry)
? CreateZoneAreas(waternetLineGeometry, phreaticLineGeometry)
: GetWaternetZoneWithSurfaceLineIntersection(surfaceLineLocalGeometry, waternetLineGeometry, phreaticLineGeometry);
}
#region SoilLayers and Surface Line Helpers
private static Point2D[] GetLocalPointsFromGeometry(MacroStabilityInwardsSurfaceLine surfaceLine,
Point3D worldCoordinate)
{
if (surfaceLine == null || worldCoordinate == null)
{
return new Point2D[0];
}
return new[]
{
surfaceLine.GetLocalPointFromGeometry(worldCoordinate)
};
}
#endregion
#region Grid Helpers
///
/// Creates grid points in 2D space based on the provided .
///
/// The grid to create the grid points for.
/// The grid determination type.
/// An array of interpolated points in 2D space based on the provided
/// or an empty array when:
///
/// - is null;
/// - is ;
/// - The grid boundaries are .
///
///
public static Point2D[] CreateGridPoints(MacroStabilityInwardsGrid grid, MacroStabilityInwardsGridDeterminationType gridDeterminationType)
{
if (grid == null
|| gridDeterminationType == MacroStabilityInwardsGridDeterminationType.Automatic
|| !AreGridSettingsValid(grid))
{
return new Point2D[0];
}
var points = new List();
IEnumerable interPolatedVerticalPositions = GetInterPolatedVerticalPositions(grid.ZBottom,
grid.ZTop,
grid.NumberOfVerticalPoints);
foreach (RoundedDouble interPolatedVerticalPosition in interPolatedVerticalPositions)
{
points.AddRange(GetInterPolatedHorizontalPoints(grid.XLeft,
grid.XRight,
interPolatedVerticalPosition,
grid.NumberOfHorizontalPoints));
}
return points.ToArray();
}
private static bool AreGridSettingsValid(MacroStabilityInwardsGrid grid)
{
return !double.IsNaN(grid.XLeft)
&& !double.IsNaN(grid.XRight)
&& !double.IsNaN(grid.ZTop)
&& !double.IsNaN(grid.ZBottom);
}
private static IEnumerable GetInterPolatedVerticalPositions(RoundedDouble startPoint,
RoundedDouble endPoint,
int nrOfPoints)
{
if (nrOfPoints <= 1)
{
yield return startPoint;
yield break;
}
int nrofInterPolatedPoints = nrOfPoints - 1;
RoundedDouble deltaZ = endPoint - startPoint;
RoundedDouble deltaZBetweenPoints = nrOfPoints < 2
? (RoundedDouble) 0.0
: (RoundedDouble) (deltaZ / nrofInterPolatedPoints);
RoundedDouble z = startPoint;
int nrOfRepetitions = nrofInterPolatedPoints < 0
? 0
: nrofInterPolatedPoints;
for (var i = 0; i < nrOfRepetitions + 1; i++)
{
yield return z;
z += deltaZBetweenPoints;
}
}
private static IEnumerable GetInterPolatedHorizontalPoints(RoundedDouble startPoint,
RoundedDouble endPoint,
RoundedDouble zPoint,
int nrOfPoints)
{
if (nrOfPoints <= 1)
{
yield return new Point2D(startPoint, zPoint);
yield break;
}
int nrofInterPolatedPoints = nrOfPoints - 1;
RoundedDouble deltaX = endPoint - startPoint;
RoundedDouble deltaXBetweenPoints = nrOfPoints < 2
? (RoundedDouble) 0
: (RoundedDouble) (deltaX / nrofInterPolatedPoints);
RoundedDouble x = startPoint;
int nrOfRepetitions = nrofInterPolatedPoints < 0
? 0
: nrofInterPolatedPoints;
for (var i = 0; i < nrOfRepetitions + 1; i++)
{
yield return new Point2D(x, zPoint);
x += deltaXBetweenPoints;
}
}
#endregion
#region Waternet Helpers
private static IEnumerable GetWaternetZoneWithSurfaceLineIntersection(Point2D[] surfaceLineLocalGeometry,
Point2D[] waternetLineGeometry,
Point2D[] phreaticLineGeometry)
{
IEnumerable waternetZoneAsPolygons = CreateZoneAreas(waternetLineGeometry, phreaticLineGeometry);
return waternetZoneAsPolygons.Select(waternetZoneAsPolygon => ClipWaternetZoneToSurfaceLine(surfaceLineLocalGeometry, waternetZoneAsPolygon)).ToArray();
}
private static Point2D[] ClipWaternetZoneToSurfaceLine(Point2D[] surfaceLineLocalGeometry, Point2D[] waternetZoneAsPolygon)
{
double leftX = waternetZoneAsPolygon.Min(p => p.X);
double rightX = waternetZoneAsPolygon.Max(p => p.X);
Segment2D[] surfaceLineSegments = Math2D.ConvertLinePointsToLineSegments(surfaceLineLocalGeometry).ToArray();
Segment2D[] waternetZoneSegments = Math2D.ConvertLinePointsToLineSegments(waternetZoneAsPolygon).ToArray();
var intersectionPoints = new List();
foreach (Segment2D surfaceLineSegment in surfaceLineSegments)
{
foreach (Segment2D waternetZoneSegment in waternetZoneSegments)
{
Segment2DIntersectSegment2DResult intersectionPointResult = Math2D.GetIntersectionBetweenSegments(surfaceLineSegment, waternetZoneSegment);
if (intersectionPointResult.IntersectionType == Intersection2DType.Intersects)
{
intersectionPoints.Add(intersectionPointResult.IntersectionPoints.First());
}
}
}
IEnumerable allXCoordinates = waternetZoneAsPolygon.Select(p => p.X)
.Concat(surfaceLineLocalGeometry.Select(p => p.X)
.Concat(intersectionPoints.Select(p => p.X))
.Where(x => x >= leftX && x <= rightX))
.OrderBy(d => d)
.Distinct();
var topLine = new List();
var bottomLine = new List();
foreach (double xCoordinate in allXCoordinates)
{
Point2D surfaceLineIntersection = Math2D.SegmentsIntersectionWithVerticalLine(surfaceLineSegments, xCoordinate).First();
Point2D[] waternetZoneIntersection = Math2D.SegmentsIntersectionWithVerticalLine(waternetZoneSegments, xCoordinate).Distinct().ToArray();
if (waternetZoneIntersection.Any())
{
double waternetZoneTop = waternetZoneIntersection.Max(p => p.Y);
double waternetZoneBottom = waternetZoneIntersection.Min(p => p.Y);
if (waternetZoneBottom >= surfaceLineIntersection.Y)
{
continue;
}
if (waternetZoneTop <= surfaceLineIntersection.Y)
{
Point2D[] waternetZonePoints = waternetZoneIntersection.OrderBy(p => p.Y).ToArray();
bottomLine.Add(waternetZonePoints.First());
topLine.Add(waternetZonePoints.Last());
}
if (waternetZoneTop > surfaceLineIntersection.Y &&
waternetZoneBottom < surfaceLineIntersection.Y)
{
Point2D[] waternetZonePoints = waternetZoneIntersection.OrderBy(p => p.Y).ToArray();
bottomLine.Add(waternetZonePoints.First());
topLine.Add(surfaceLineIntersection);
}
}
}
var area = new List();
area.AddRange(topLine);
area.AddRange(bottomLine.OrderByDescending(p => p.X));
if (topLine.Any())
{
area.Add(topLine.First());
}
return area.ToArray();
}
private static bool IsSurfaceLineAboveWaternetZone(Point2D[] surfaceLineLocalGeometry, Point2D[] waternetLineGeometry, Point2D[] phreaticLineGeometry)
{
double surfaceLineLowestPointY = surfaceLineLocalGeometry.Min(p => p.Y);
double waternetZoneHeighestPointY = Math.Max(waternetLineGeometry.Max(p => p.Y), phreaticLineGeometry.Max(p => p.Y));
return surfaceLineLowestPointY >= waternetZoneHeighestPointY;
}
private static IEnumerable CreateZoneAreas(Point2D[] waternetLineGeometry, Point2D[] phreaticLineGeometry)
{
var areas = new List();
Segment2D[] phreaticLineSegments = Math2D.ConvertLinePointsToLineSegments(phreaticLineGeometry).ToArray();
Segment2D[] waternetLineSegments = Math2D.ConvertLinePointsToLineSegments(waternetLineGeometry).ToArray();
var intersectionPoints = new List();
foreach (Segment2D phreaticLineSegment in phreaticLineSegments)
{
foreach (Segment2D waternetLineSegment in waternetLineSegments)
{
Segment2DIntersectSegment2DResult intersectionPointResult = Math2D.GetIntersectionBetweenSegments(phreaticLineSegment, waternetLineSegment);
if (intersectionPointResult.IntersectionType == Intersection2DType.Intersects)
{
intersectionPoints.Add(intersectionPointResult.IntersectionPoints.First());
}
}
}
IEnumerable allXCoordinates = phreaticLineGeometry.Select(p => p.X)
.Concat(waternetLineGeometry.Select(p => p.X))
.Concat(intersectionPoints.Select(p => p.X))
.OrderBy(d => d)
.Distinct();
var waternetLineArea = new List();
var phreaticLineArea = new List();
var areaPoints = new List();
foreach (double xCoordinate in allXCoordinates)
{
Point2D phreaticLineIntersection = Math2D.SegmentsIntersectionWithVerticalLine(phreaticLineSegments, xCoordinate).First();
Point2D waternetLineIntersection = Math2D.SegmentsIntersectionWithVerticalLine(waternetLineSegments, xCoordinate).First();
waternetLineArea.Add(new Point2D(xCoordinate, waternetLineIntersection.Y));
phreaticLineArea.Add(new Point2D(xCoordinate, phreaticLineIntersection.Y));
if (intersectionPoints.Any(p => Math.Abs(p.X - xCoordinate) < 1e-6))
{
areaPoints.AddRange(phreaticLineArea);
areaPoints.AddRange(waternetLineArea.OrderByDescending(p => p.X));
areaPoints.Add(phreaticLineArea.First());
areas.Add(areaPoints.ToArray());
waternetLineArea.Clear();
phreaticLineArea.Clear();
areaPoints.Clear();
waternetLineArea.Add(new Point2D(xCoordinate, waternetLineIntersection.Y));
phreaticLineArea.Add(new Point2D(xCoordinate, phreaticLineIntersection.Y));
}
}
areaPoints.AddRange(phreaticLineArea);
areaPoints.AddRange(waternetLineArea.OrderByDescending(p => p.X));
areaPoints.Add(phreaticLineArea.First());
areas.Add(areaPoints.ToArray());
return areas;
}
#endregion
}
}