Index: Ringtoets/MacroStabilityInwards/src/Ringtoets.MacroStabilityInwards.Data/Ringtoets.MacroStabilityInwards.Data.csproj =================================================================== diff -u -rf7df02224d9e80cda83c8b757617c449b3bcfd4e -rf6f910cf9e6c78af77bbac56f232242553e3f9de --- Ringtoets/MacroStabilityInwards/src/Ringtoets.MacroStabilityInwards.Data/Ringtoets.MacroStabilityInwards.Data.csproj (.../Ringtoets.MacroStabilityInwards.Data.csproj) (revision f7df02224d9e80cda83c8b757617c449b3bcfd4e) +++ Ringtoets/MacroStabilityInwards/src/Ringtoets.MacroStabilityInwards.Data/Ringtoets.MacroStabilityInwards.Data.csproj (.../Ringtoets.MacroStabilityInwards.Data.csproj) (revision f6f910cf9e6c78af77bbac56f232242553e3f9de) @@ -57,6 +57,7 @@ + @@ -69,6 +70,10 @@ Core.Common.Base False + + {88665510-CE20-4EF5-BE4A-39800720AA2C} + Core.Common.Geometry + {d4200f43-3f72-4f42-af0a-8ced416a38ec} Ringtoets.Common.Data Index: Ringtoets/MacroStabilityInwards/src/Ringtoets.MacroStabilityInwards.Data/SoilProfileUnderSurfaceLineFactory.cs =================================================================== diff -u --- Ringtoets/MacroStabilityInwards/src/Ringtoets.MacroStabilityInwards.Data/SoilProfileUnderSurfaceLineFactory.cs (revision 0) +++ Ringtoets/MacroStabilityInwards/src/Ringtoets.MacroStabilityInwards.Data/SoilProfileUnderSurfaceLineFactory.cs (revision f6f910cf9e6c78af77bbac56f232242553e3f9de) @@ -0,0 +1,154 @@ +// 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 +{ + public class SoilProfileUnderSurfaceLineFactory + { + public static SoilProfileUnderSurfaceLine Create(MacroStabilityInwardsSoilProfile 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); + } + + 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(MacroStabilityInwardsSoilLayer layer, MacroStabilityInwardsSoilProfile 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[] outerLoop, SoilLayerProperties properties) + { + if (outerLoop == null) + { + throw new ArgumentNullException(nameof(outerLoop)); + } + if (properties == null) + { + throw new ArgumentNullException(nameof(properties)); + } + OuterLoop = outerLoop; + InnerLoops = Enumerable.Empty(); + Properties = properties; + } + + public Point2D[] OuterLoop { get; } + public IEnumerable InnerLoops { get; } + public SoilLayerProperties Properties { get; } + } +} \ No newline at end of file Index: Ringtoets/MacroStabilityInwards/test/Ringtoets.MacroStabilityInwards.Data.Test/Ringtoets.MacroStabilityInwards.Data.Test.csproj =================================================================== diff -u -rf7df02224d9e80cda83c8b757617c449b3bcfd4e -rf6f910cf9e6c78af77bbac56f232242553e3f9de --- Ringtoets/MacroStabilityInwards/test/Ringtoets.MacroStabilityInwards.Data.Test/Ringtoets.MacroStabilityInwards.Data.Test.csproj (.../Ringtoets.MacroStabilityInwards.Data.Test.csproj) (revision f7df02224d9e80cda83c8b757617c449b3bcfd4e) +++ Ringtoets/MacroStabilityInwards/test/Ringtoets.MacroStabilityInwards.Data.Test/Ringtoets.MacroStabilityInwards.Data.Test.csproj (.../Ringtoets.MacroStabilityInwards.Data.Test.csproj) (revision f6f910cf9e6c78af77bbac56f232242553e3f9de) @@ -61,6 +61,7 @@ + Index: Ringtoets/MacroStabilityInwards/test/Ringtoets.MacroStabilityInwards.Data.Test/SoilProfileUnderSurfaceLineFactory.cs =================================================================== diff -u --- Ringtoets/MacroStabilityInwards/test/Ringtoets.MacroStabilityInwards.Data.Test/SoilProfileUnderSurfaceLineFactory.cs (revision 0) +++ Ringtoets/MacroStabilityInwards/test/Ringtoets.MacroStabilityInwards.Data.Test/SoilProfileUnderSurfaceLineFactory.cs (revision f6f910cf9e6c78af77bbac56f232242553e3f9de) @@ -0,0 +1,302 @@ +// 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.Linq; +using Core.Common.Base.Geometry; +using NUnit.Framework; +using Ringtoets.MacroStabilityInwards.Primitives; + +namespace Ringtoets.MacroStabilityInwards.Data.Test +{ + [TestFixture] + public class SoilProfileUnderSurfaceLineFactoryTest + { + [Test] + public void Create_SoilProfileNull_ThrowArgumentNullException() + { + // Setup + var surfaceLine = new RingtoetsMacroStabilityInwardsSurfaceLine(); + + // Call + TestDelegate test = () => SoilProfileUnderSurfaceLineFactory.Create(null, surfaceLine); + + // Assert + var exception = Assert.Throws(test); + Assert.AreEqual("soilProfile", exception.ParamName); + } + + [Test] + public void Create_SurfaceLineNull_ThrowArgumentNullException() + { + // Setup + var soilProfile = new MacroStabilityInwardsSoilProfile("name", 2.0, new[] + { + new MacroStabilityInwardsSoilLayer(2) + }, SoilProfileType.SoilProfile1D, 0); + + // Call + TestDelegate test = () => SoilProfileUnderSurfaceLineFactory.Create(soilProfile, null); + + // Assert + var exception = Assert.Throws(test); + Assert.AreEqual("surfaceLine", exception.ParamName); + } + + [Test] + public void Create_SurfaceLineOnTopOrAboveSoilLayer_ReturnsSoilLayerPointsAsRectangle() + { + // Setup + var surfaceLine = new RingtoetsMacroStabilityInwardsSurfaceLine(); + surfaceLine.SetGeometry(new[] + { + new Point3D(0, 0, 4), + new Point3D(0, 0, 3.2), + new Point3D(2, 0, 4) + }); + var soilLayer = new MacroStabilityInwardsSoilLayer(3.2); + var soilProfile = new MacroStabilityInwardsSoilProfile("name", 2.0, new[] + { + soilLayer + }, SoilProfileType.SoilProfile1D, 0); + + // Call + SoilProfileUnderSurfaceLine areas = SoilProfileUnderSurfaceLineFactory.Create(soilProfile, surfaceLine); + + // Assert + Assert.AreEqual(1, areas.LayersUnderSurfaceLine.Count()); + CollectionAssert.AreEqual(new[] + { + new Point2D(2, 3.2), + new Point2D(2, 2), + new Point2D(0, 2), + new Point2D(0, 3.2) + }, areas.LayersUnderSurfaceLine.ElementAt(0).OuterLoop); + } + + [Test] + public void Create_SurfaceLineBelowSoilLayer_ReturnsEmptyAreasCollection() + { + // Setup + var surfaceLine = new RingtoetsMacroStabilityInwardsSurfaceLine(); + surfaceLine.SetGeometry(new[] + { + new Point3D(0, 0, 2.0), + new Point3D(2, 0, 2.0) + }); + var soilLayer = new MacroStabilityInwardsSoilLayer(3.2); + var soilProfile = new MacroStabilityInwardsSoilProfile("name", 2.0, new[] + { + soilLayer + }, SoilProfileType.SoilProfile1D, 0); + + // Call + SoilProfileUnderSurfaceLine areas = SoilProfileUnderSurfaceLineFactory.Create(soilProfile, surfaceLine); + + // Assert + CollectionAssert.IsEmpty(areas.LayersUnderSurfaceLine); + } + + [Test] + public void Create_SurfaceLineThroughMiddleLayerButNotSplittingIt_ReturnsSoilLayerPointsAsRectangleFollowingSurfaceLine() + { + // Setup + var surfaceLine = new RingtoetsMacroStabilityInwardsSurfaceLine(); + surfaceLine.SetGeometry(new[] + { + new Point3D(0, 0, 3.0), + new Point3D(1, 0, 2.0), + new Point3D(2, 0, 3.0) + }); + const double bottom = 1.5; + const double top = 2.5; + var soilLayer = new MacroStabilityInwardsSoilLayer(top); + var soilProfile = new MacroStabilityInwardsSoilProfile("name", bottom, new[] + { + soilLayer + }, SoilProfileType.SoilProfile1D, 0); + + // Call + SoilProfileUnderSurfaceLine areas = SoilProfileUnderSurfaceLineFactory.Create(soilProfile, surfaceLine); + + // Assert + Assert.AreEqual(1, areas.LayersUnderSurfaceLine.Count()); + CollectionAssert.AreEqual(new[] + { + new Point2D(0.5, top), + new Point2D(1, 2.0), + new Point2D(1.5, top), + new Point2D(2, top), + new Point2D(2, bottom), + new Point2D(0, bottom), + new Point2D(0, top) + }, areas.LayersUnderSurfaceLine.ElementAt(0).OuterLoop); + } + + [Test] + public void Create_SurfaceLineThroughMiddleLayerButNotSplittingItIntersectionOnTopLevel_ReturnsSoilLayerPointsAsRectangleFollowingSurfaceLine() + { + // Setup + var surfaceLine = new RingtoetsMacroStabilityInwardsSurfaceLine(); + surfaceLine.SetGeometry(new[] + { + new Point3D(0, 0, 3.0), + new Point3D(0.5, 0, 2.5), + new Point3D(1, 0, 2.0), + new Point3D(1.5, 0, 2.5), + new Point3D(2, 0, 3.0) + }); + const double bottom = 1.5; + const double top = 2.5; + var soilLayer = new MacroStabilityInwardsSoilLayer(top); + var soilProfile = new MacroStabilityInwardsSoilProfile("name", bottom, new[] + { + soilLayer + }, SoilProfileType.SoilProfile1D, 0); + + // Call + SoilProfileUnderSurfaceLine areas = SoilProfileUnderSurfaceLineFactory.Create(soilProfile, surfaceLine); + + // Assert + Assert.AreEqual(1, areas.LayersUnderSurfaceLine.Count()); + CollectionAssert.AreEqual(new[] + { + new Point2D(0.5, top), + new Point2D(1, 2.0), + new Point2D(1.5, top), + new Point2D(2, top), + new Point2D(2, bottom), + new Point2D(0, bottom), + new Point2D(0, top) + }, areas.LayersUnderSurfaceLine.ElementAt(0).OuterLoop); + } + + [Test] + public void Create_SurfaceLineStartsBelowLayerTopButAboveBottom_ReturnsSoilLayerPointsAsRectangleFollowingSurfaceLine() + { + // Setup + var surfaceLine = new RingtoetsMacroStabilityInwardsSurfaceLine(); + surfaceLine.SetGeometry(new[] + { + new Point3D(0, 0, 2.0), + new Point3D(1, 0, 2.0), + new Point3D(2, 0, 3.0) + }); + const double bottom = 1.5; + const double top = 2.5; + var soilLayer = new MacroStabilityInwardsSoilLayer(top); + var soilProfile = new MacroStabilityInwardsSoilProfile("name", bottom, new[] + { + soilLayer + }, SoilProfileType.SoilProfile1D, 0); + + // Call + SoilProfileUnderSurfaceLine areas = SoilProfileUnderSurfaceLineFactory.Create(soilProfile, surfaceLine); + + // Assert + Assert.AreEqual(1, areas.LayersUnderSurfaceLine.Count()); + CollectionAssert.AreEqual(new[] + { + new Point2D(0, 2.0), + new Point2D(1, 2.0), + new Point2D(1.5, top), + new Point2D(2, top), + new Point2D(2, bottom), + new Point2D(0, bottom) + }, areas.LayersUnderSurfaceLine.ElementAt(0).OuterLoop); + } + + [Test] + public void Create_SurfaceLineEndsBelowLayerTopButAboveBottom_ReturnsSoilLayerPointsAsRectangleFollowingSurfaceLine() + { + // Setup + var surfaceLine = new RingtoetsMacroStabilityInwardsSurfaceLine(); + surfaceLine.SetGeometry(new[] + { + new Point3D(0, 0, 3.0), + new Point3D(1, 0, 2.0), + new Point3D(2, 0, 2.0) + }); + const double bottom = 1.5; + const double top = 2.5; + var soilLayer = new MacroStabilityInwardsSoilLayer(top); + var soilProfile = new MacroStabilityInwardsSoilProfile("name", bottom, new[] + { + soilLayer + }, SoilProfileType.SoilProfile1D, 0); + + // Call + SoilProfileUnderSurfaceLine areas = SoilProfileUnderSurfaceLineFactory.Create(soilProfile, surfaceLine); + + // Assert + Assert.AreEqual(1, areas.LayersUnderSurfaceLine.Count()); + CollectionAssert.AreEqual(new[] + { + new Point2D(0.5, top), + new Point2D(1, 2.0), + new Point2D(2, 2.0), + new Point2D(2, bottom), + new Point2D(0, bottom), + new Point2D(0, top) + }, areas.LayersUnderSurfaceLine.ElementAt(0).OuterLoop); + } + + [Test] + public void Create_SurfaceLineZigZagsThroughSoilLayer_ReturnsSoilLayerPointsSplitInMultipleAreas() + { + // Setup + var surfaceLine = new RingtoetsMacroStabilityInwardsSurfaceLine(); + surfaceLine.SetGeometry(new[] + { + new Point3D(0, 0, 4.0), + new Point3D(4, 0, 0.0), + new Point3D(8, 0, 4.0) + }); + const int bottom = 1; + const int top = 3; + var soilLayer = new MacroStabilityInwardsSoilLayer(top); + var soilProfile = new MacroStabilityInwardsSoilProfile("name", bottom, new[] + { + soilLayer + }, SoilProfileType.SoilProfile1D, 0); + + // Call + SoilProfileUnderSurfaceLine areas = SoilProfileUnderSurfaceLineFactory.Create(soilProfile, surfaceLine); + + // Assert + Assert.AreEqual(2, areas.LayersUnderSurfaceLine.Count()); + CollectionAssert.AreEqual(new[] + { + new Point2D(1, top), + new Point2D(3, bottom), + new Point2D(0, bottom), + new Point2D(0, top) + }, areas.LayersUnderSurfaceLine.ElementAt(0).OuterLoop); + CollectionAssert.AreEqual(new[] + { + new Point2D(5, bottom), + new Point2D(7, top), + new Point2D(8, top), + new Point2D(8, bottom) + }, areas.LayersUnderSurfaceLine.ElementAt(1).OuterLoop); + } + } +} \ No newline at end of file