// 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.Collections.ObjectModel;
using System.Linq;
using Core.Common.Base.Geometry;
using Core.Common.Geometry;
using Ringtoets.MacroStabilityInwards.Primitives;
namespace Ringtoets.MacroStabilityInwards.Data
{
///
/// Class for constructing soil profiles for which the geometry of the layers lay under a surface line.
///
public static class SoilProfileUnderSurfaceLineFactory
{
///
/// Creates a new .
///
/// The soil profile containing layers under the .
/// The surface line for which determines the top of the .
/// A new containing geometries from the
/// under the .
public static SoilProfileUnderSurfaceLine Create(MacroStabilityInwardsSoilProfile1D soilProfile, RingtoetsMacroStabilityInwardsSurfaceLine surfaceLine)
{
if (soilProfile == null)
{
throw new ArgumentNullException(nameof(soilProfile));
}
if (surfaceLine == null)
{
throw new ArgumentNullException(nameof(surfaceLine));
}
Point2D[] localizedSurfaceLine = surfaceLine.ProjectGeometryToLZ().ToArray();
IEnumerable surfaceLineGeometry = CreateSurfaceLineAreaToDepth(localizedSurfaceLine, soilProfile.Bottom);
IEnumerable layerGeometries = soilProfile.Layers.Select(l => As2DGeometry(l, soilProfile, localizedSurfaceLine.First().X, localizedSurfaceLine.Last().X));
return GeometriesToIntersections(layerGeometries, surfaceLineGeometry);
}
///
/// Creates a new .
///
/// The soil profile containing layers.
/// A new containing geometries from the
/// .
public static SoilProfileUnderSurfaceLine Create(MacroStabilityInwardsSoilProfile2D soilProfile)
{
if (soilProfile == null)
{
throw new ArgumentNullException(nameof(soilProfile));
}
IList layersUnderSurfaceLine = new List();
foreach (var layer in soilProfile.Layers)
{
layersUnderSurfaceLine.Add(new SoilLayerUnderSurfaceLine(RingToPoints(layer.OuterRing), layer.Holes.Select(RingToPoints), layer.Properties));
}
return new SoilProfileUnderSurfaceLine(layersUnderSurfaceLine);
}
private static Point2D[] RingToPoints(Ring ring)
{
return ring.Points.ToArray();
}
private static SoilProfileUnderSurfaceLine GeometriesToIntersections(IEnumerable layerGeometries, IEnumerable surfaceLineGeometry)
{
var collection = new Collection();
IEnumerable surfaceLineGeometryArray = surfaceLineGeometry.ToArray();
foreach (TempSoilLayerGeometry layer in layerGeometries)
{
foreach (Point2D[] soilLayerArea in CreateSoilLayerAreas(surfaceLineGeometryArray, layer.OuterLoop))
{
collection.Add(new SoilLayerUnderSurfaceLine(soilLayerArea, layer.Properties));
}
}
return new SoilProfileUnderSurfaceLine(collection);
}
private static TempSoilLayerGeometry As2DGeometry(MacroStabilityInwardsSoilLayer1D layer, MacroStabilityInwardsSoilProfile1D soilProfile, double minX, double maxX)
{
double top = layer.Top;
double bottom = layer.Top - soilProfile.GetLayerThickness(layer);
return new TempSoilLayerGeometry(new[]
{
new Point2D(minX, top),
new Point2D(maxX, top),
new Point2D(maxX, bottom),
new Point2D(minX, bottom)
}, layer.Properties);
}
private static IEnumerable CreateSurfaceLineAreaToDepth(Point2D[] localizedSurfaceLine, double soilProfileBottom)
{
foreach (Point2D point in localizedSurfaceLine)
{
yield return point;
}
double geometryBottom = Math.Min(soilProfileBottom, localizedSurfaceLine.Min(p => p.Y)) - 1;
yield return new Point2D(localizedSurfaceLine.Last().X, geometryBottom);
yield return new Point2D(localizedSurfaceLine.First().X, geometryBottom);
}
private static IEnumerable CreateSoilLayerAreas(IEnumerable surfaceLineGeometry, IEnumerable soilLayerGeometry)
{
return GetSoilLayerWithSurfaceLineIntersection(surfaceLineGeometry, soilLayerGeometry);
}
private static IEnumerable GetSoilLayerWithSurfaceLineIntersection(IEnumerable surfaceLineGeometry, IEnumerable soilLayerGeometry)
{
return AdvancedMath2D.PolygonIntersectionWithPolygon(surfaceLineGeometry, soilLayerGeometry).Where(arr => arr.Length > 2);
}
private class TempSoilLayerGeometry
{
public TempSoilLayerGeometry(Point2D[] outerLoop, SoilLayerProperties properties)
{
OuterLoop = outerLoop;
Properties = properties;
InnerLoops = Enumerable.Empty();
}
public Point2D[] OuterLoop { get; }
public SoilLayerProperties Properties { get; }
public IEnumerable InnerLoops { get; }
}
}
public class SoilProfileUnderSurfaceLine
{
public SoilProfileUnderSurfaceLine(IEnumerable layersUnderSurfaceLine)
{
if (layersUnderSurfaceLine == null)
{
throw new ArgumentNullException(nameof(layersUnderSurfaceLine));
}
LayersUnderSurfaceLine = layersUnderSurfaceLine;
}
public IEnumerable LayersUnderSurfaceLine { get; }
}
public class SoilLayerUnderSurfaceLine
{
public SoilLayerUnderSurfaceLine(Point2D[] outerRing, SoilLayerProperties properties)
: this(outerRing, Enumerable.Empty(), properties) {}
public SoilLayerUnderSurfaceLine(Point2D[] outerRing, IEnumerable holes, SoilLayerProperties properties)
{
if (outerRing == null)
{
throw new ArgumentNullException(nameof(outerRing));
}
if (holes == null)
{
throw new ArgumentNullException(nameof(holes));
}
if (properties == null)
{
throw new ArgumentNullException(nameof(properties));
}
OuterRing = outerRing;
Holes = holes;
Properties = properties;
}
public Point2D[] OuterRing { get; }
public IEnumerable Holes { get; }
public SoilLayerProperties Properties { get; }
}
}