Index: dam engine/branches/Initial Source/Deltares.DamEngine.Data/Geotechnics/SoilProfile2D.cs =================================================================== diff -u --- dam engine/branches/Initial Source/Deltares.DamEngine.Data/Geotechnics/SoilProfile2D.cs (revision 0) +++ dam engine/branches/Initial Source/Deltares.DamEngine.Data/Geotechnics/SoilProfile2D.cs (revision 282) @@ -0,0 +1,188 @@ +// Copyright (C) Stichting Deltares 2017. All rights reserved. +// +// This file is part of the Macro Stability kernel. +// +// The Macro Stability kernel is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero 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 Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero 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.Collections.Generic; +using Deltares.DamEngine.Data.Geometry; +using Deltares.DamEngine.Data.Standard.Language; +using Deltares.DamEngine.Data.Standard.Validation; + +namespace Deltares.DamEngine.Data.Geotechnics +{ + /// + /// 2D Soil Profile Object + /// + public class SoilProfile2D : SoilProfile + { + private readonly Dictionary cachedSoilProfiles1D = new Dictionary(); + private GeometryData geometry = new GeometryData(); + private readonly List surfaces = new List(); + + /// + /// Initializes a new instance of the class. + /// + public SoilProfile2D() + { + Name = LocalizationManager.GetTranslatedText(this, "DefaultNameSoilProfile2D"); + } + + /// + /// Gets the surfaces. + /// + /// + /// The surfaces. + /// + [Validate] + public IList Surfaces + { + get + { + return surfaces; + } + } + + /// + /// Gets or sets the geometry. + /// + /// + /// The geometry. + /// + public GeometryData Geometry + { + get + { + return geometry; + } + set + { + geometry = value; + } + } + + /// + /// Gets the soil profile 1D at the given X. + /// + /// The x. + /// Soil Profile 1D + public SoilProfile1D GetSoilProfile1D(double x) + { + const double diff = 0.001; + SoilProfile1D soilProfile = GetCachedSoilProfile1D(x); + + if (soilProfile != null) + { + return soilProfile; + } + + soilProfile = new SoilProfile1D + { + Name = "Generated at x = " + x + " from " + Name + }; + var detector = new LayerDetector(Surfaces); + if (x > Geometry.Right) + { + x = Geometry.Right - diff; + } + if (x < Geometry.Left) + { + x = Geometry.Left + diff; + } + + detector.DetermineMaterials(x); + + if (detector.LayerList.Count > 0) + { + soilProfile.BottomLevel = detector.LayerList[detector.LayerList.Count - 1].EndPoint.Z; + for (int i = 0; i < detector.LayerList.Count; i++) + { + var layer = new SoilLayer1D(detector.LayerList[i].Soil, detector.LayerList[i].StartPoint.Z) + { + IsAquifer = detector.LayerList[i].IsAquifer + }; + soilProfile.Layers.Add(layer); + } + } + + + cachedSoilProfiles1D[x] = soilProfile; + + return soilProfile; + } + + /// + /// Get the surface from the point + /// + /// The point which is supposed to be within the soil layer + /// Surface + public SoilLayer2D GetSoilLayer(Point2D point) + { + for (int i = 0; i < Surfaces.Count; i++) + { + SoilLayer2D surface = Surfaces[i]; + GeometryLoop surfaceLine = surface.GeometrySurface.OuterLoop; + if (surfaceLine.IsPointInLoopArea(point)) + { + bool found = true; + + // if point lies in an innerloop it belongs to another area + foreach (var innerloop in surface.GeometrySurface.InnerLoops) + { + if (innerloop.IsPointInLoopArea(point)) + { + found = false; + } + } + + if (found) + { + return surface; + } + } + } + + return null; + } + + /// + /// Returns a that represents this instance. + /// + /// + /// A that represents this instance. + /// + public override string ToString() + { + return Name; + } + + /// + /// Gets the cached soil profile1 d. + /// + /// The x. + /// + private SoilProfile1D GetCachedSoilProfile1D(double x) + { + if (cachedSoilProfiles1D.ContainsKey(x)) + { + return cachedSoilProfiles1D[x]; + } + return null; + } + } +} \ No newline at end of file Index: dam engine/branches/Initial Source/Deltares.DamEngine.Data/Deltares.DamEngine.Data.csproj =================================================================== diff -u -r278 -r282 --- dam engine/branches/Initial Source/Deltares.DamEngine.Data/Deltares.DamEngine.Data.csproj (.../Deltares.DamEngine.Data.csproj) (revision 278) +++ dam engine/branches/Initial Source/Deltares.DamEngine.Data/Deltares.DamEngine.Data.csproj (.../Deltares.DamEngine.Data.csproj) (revision 282) @@ -74,16 +74,23 @@ + + + + + + + @@ -94,17 +101,25 @@ + + + + + + + + @@ -120,8 +135,10 @@ + + @@ -132,6 +149,7 @@ + Index: dam engine/branches/Initial Source/Deltares.DamEngine.Calculators/General/DAMFailureMechanismeCalculator.cs =================================================================== diff -u -r276 -r282 --- dam engine/branches/Initial Source/Deltares.DamEngine.Calculators/General/DAMFailureMechanismeCalculator.cs (.../DAMFailureMechanismeCalculator.cs) (revision 276) +++ dam engine/branches/Initial Source/Deltares.DamEngine.Calculators/General/DAMFailureMechanismeCalculator.cs (.../DAMFailureMechanismeCalculator.cs) (revision 282) @@ -20,6 +20,7 @@ using Deltares.Dam.Data; using Deltares.DamEngine.Data.Design; using Deltares.DamEngine.Data.General; +using Deltares.DamEngine.Data.General.NWO; using Deltares.DamEngine.Data.Geometry; using Deltares.DamEngine.Data.Geotechnics; Index: dam engine/branches/Initial Source/Deltares.DamEngine.Data/Geotechnics/LayerDetector.cs =================================================================== diff -u --- dam engine/branches/Initial Source/Deltares.DamEngine.Data/Geotechnics/LayerDetector.cs (revision 0) +++ dam engine/branches/Initial Source/Deltares.DamEngine.Data/Geotechnics/LayerDetector.cs (revision 282) @@ -0,0 +1,367 @@ +// Copyright (C) Stichting Deltares 2017. All rights reserved. +// +// This file is part of the Macro Stability kernel. +// +// The Macro Stability kernel is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero 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 Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero 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.Collections.Generic; +using Deltares.DamEngine.Data.Geometry; +using Deltares.DamEngine.Data.Standard; + +namespace Deltares.DamEngine.Data.Geotechnics +{ + /// + ///When publisherEventArgs vertical is drawn in the Geometry, this reports the intersection layers. + /// + /// Step 1: To Determine the possibility of Surface and Vertical intersection, Min/Max of each surface + /// is checked with Vertical's X coordinate. + /// Step 2: Intersection Points of each surface with the vertical are determined and added to pointlist + /// in sorted order (greatest Y at first). + /// Step 3: For forming the Intersection Curves, the consecutive points in the pointlist are checked if + /// their mid-point lies in the surface and not in the innerloop. They are stored in the sorted order. + /// + public class LayerDetector + { + private readonly List intersectionSurfacesList = new List(); + private readonly List layerList = new List(); + private readonly List pointList = new List(); + private readonly IList soilSurfaces; + + private double verticalXCoordinate; + + /// + /// Initializes a new instance of the class. + /// + /// The soil surfaces. + public LayerDetector(IList soilSurfaces) + { + this.soilSurfaces = soilSurfaces; + } + + /// + /// Gets the layer list. + /// + /// + /// The layer list. + /// + public List LayerList + { + get + { + return layerList; + } + } + + + /// + /// Determines the materials. + /// + /// A vertical x coordinate. + public void DetermineMaterials(double aVerticalXCoordinate) + { + verticalXCoordinate = aVerticalXCoordinate; + + // The detection process + StartDetection(); + } + + private void StartDetection() + { + ClearLists(); + GetIntersectionPointList(); + DeleteDuplicateCurve(); + } + + private void GetIntersectionPointList() + { + foreach (var surface in soilSurfaces) + { + if (intersectionSurfacesList.Contains(surface) == false) + { + foreach (var curve in surface.GeometrySurface.OuterLoop.CurveList) + { + FindIntersections(curve.HeadPoint, curve.EndPoint, surface); + } + // check if it has inner loops + if (surface.GeometrySurface.InnerLoops.Count > 0) + { + List loopList = surface.GeometrySurface.InnerLoops; + foreach (var loop in loopList) + { + foreach (var curve in loop.CurveList) + { + FindIntersections(curve.HeadPoint, curve.EndPoint, surface); + } + } + } + //create intersection curves + if (pointList.Count > 0) + { + GetLayerList(); + pointList.Clear(); + } + } + } + } + + // finds intersections with regard to publisherEventArgs curve + private void FindIntersections(Point2D aHeadpoint, Point2D aEndPoint, SoilLayer2D aSurfaceRefKey) + { + double maxvalue = 999999999.0; + double minvalue = -999999999.0; + var verticalHeadPoint = new Point2D(verticalXCoordinate, maxvalue); + var verticalEndPoint = new Point2D(verticalXCoordinate, minvalue); + Point2D intersectionPoint; + + LineIntersection intersectionResult = Routines2D.DetermineIf2DLinesIntersectStrickly(verticalHeadPoint.X, verticalHeadPoint.Z, + verticalEndPoint.X, verticalEndPoint.Z, aHeadpoint.X, aHeadpoint.Z, aEndPoint.X, aEndPoint.Z, out intersectionPoint); + + if (intersectionResult == LineIntersection.Intersects) + { + AddPointToList(new LayerIntersectionPoint(intersectionPoint, aSurfaceRefKey)); + } + else if (intersectionResult == LineIntersection.NoIntersection || intersectionResult == LineIntersection.Parallel) + { + const double cEpsilon = 1.0e-3; + if ((Routines2D.DoesPointExistInLine(verticalHeadPoint.X, verticalHeadPoint.Z, verticalEndPoint.X, verticalEndPoint.Z, + aHeadpoint.X, aHeadpoint.Z, cEpsilon)) && (Routines2D.DoesPointExistInLine(verticalHeadPoint.X, verticalHeadPoint.Z, + verticalEndPoint.X, verticalEndPoint.Z, aEndPoint.X, aEndPoint.Z, cEpsilon))) + { + AddPointToList(new LayerIntersectionPoint(aHeadpoint, aSurfaceRefKey)); + AddPointToList(new LayerIntersectionPoint(aEndPoint, aSurfaceRefKey)); + } + } + } + + private void GetLayerList() + { + int pointCount = pointList.Count; + + if (pointCount > 1) + { + object point1 = null; + + for (int index = 0; index < pointCount; index++) + { + if (point1 == null) + { + point1 = pointList[index]; + } + else + { + //point not same condition + bool notSameCondition = ((pointList[index].IntersectionPoint.X.IsNearEqual(( + (LayerIntersectionPoint) point1).IntersectionPoint.X)) && (pointList[index].IntersectionPoint.Z.IsNearEqual(( + (LayerIntersectionPoint) point1).IntersectionPoint.Z))); + + if (notSameCondition == false) + { + object point2 = pointList[index]; + FindLayer((LayerIntersectionPoint) point1, (LayerIntersectionPoint) point2); + point1 = pointList[index]; + } + } + } + } + } + + private void ClearLists() + { + pointList.Clear(); + layerList.Clear(); + intersectionSurfacesList.Clear(); + } + + // To make it top to bottom + private void CheckTopToBottom(ref Point2D aHeadPoint, ref Point2D aEndPoint) + { + if (aHeadPoint.Z.IsLessThan(aEndPoint.Z)) + { + var temp = aHeadPoint; + aHeadPoint = aEndPoint; + aEndPoint = temp; + } + } + + // Finds what kind of passage does this curve make with regard to the surface + private void FindLayer(LayerIntersectionPoint aPoint1, LayerIntersectionPoint aPoint2) + { + var midPoint = new GeometryPoint() + { + X = (aPoint1.IntersectionPoint.X + aPoint2.IntersectionPoint.X)/2, + Z = (aPoint1.IntersectionPoint.Z + aPoint2.IntersectionPoint.Z)/2 + }; + + // check where the mid point lies + PointInPolygon polygonResult = Routines2D.CheckIfPointIsInPolygon(aPoint1.SurfaceRefKey.GeometrySurface.OuterLoop, + midPoint.X, midPoint.Z); + + + var startPoint = aPoint1.IntersectionPoint; + var endPoint = aPoint2.IntersectionPoint; + + Soil soil = aPoint1.SurfaceRefKey.Soil; + var isAquifer = aPoint1.SurfaceRefKey.IsAquifer; + if (polygonResult == PointInPolygon.InsidePolygon || polygonResult == PointInPolygon.OnPolygonEdge) + { + bool isPresentInInnerLoop = false; + List innerLoopList = aPoint1.SurfaceRefKey.GeometrySurface.InnerLoops; + foreach (var innerLoop in innerLoopList) + { + PointInPolygon innerPolygonResult = Routines2D.CheckIfPointIsInPolygon(innerLoop, midPoint.X, midPoint.Z); + if (innerPolygonResult != PointInPolygon.OutsidePolygon) + { + isPresentInInnerLoop = true; + } + } + if (isPresentInInnerLoop == false) + { + var layerCurve = new Layer(startPoint, endPoint, soil) + { + IsAquifer = isAquifer + }; + AddLayerToList(layerCurve); + } + } + } + + // Adds the LayerIntersectionCurve in publisherEventArgs sorted order - Top to bottom + private void AddLayerToList(Layer aLayer) + { + int count = layerList.Count; + bool isAdded = false; + var startPoint = aLayer.StartPoint; + var endPoint = aLayer.EndPoint; + CheckTopToBottom(ref startPoint, ref endPoint); + aLayer.StartPoint = startPoint; + aLayer.EndPoint = endPoint; + + if (count == 0) + { + layerList.Add(aLayer); + } + else + { + for (int index = 0; index < count; index++) + { + if (aLayer.StartPoint.Z.IsGreaterThanOrEqualTo(layerList[index].StartPoint.Z)) + { + layerList.Insert(index, aLayer); + isAdded = true; + break; + } + } + if (isAdded == false) + { + layerList.Add(aLayer); + } + } + } + + // Adds the LayerIntersectionPoints (ignores duplicates when found within same surface) + private void AddPointToList(LayerIntersectionPoint aPoint) + { + if (intersectionSurfacesList.Contains(aPoint.SurfaceRefKey) == false) + { + intersectionSurfacesList.Add(aPoint.SurfaceRefKey); + } + + int count = pointList.Count; + bool isPointFound = false; + if (count > 0) + { + for (int index = 0; index < count; index++) // to find duplicate + { + if ((aPoint.IntersectionPoint.X.IsNearEqual(pointList[index].IntersectionPoint.X)) + && (aPoint.IntersectionPoint.Z.IsNearEqual(pointList[index].IntersectionPoint.Z)) + && (aPoint.SurfaceRefKey == pointList[index].SurfaceRefKey)) + { + isPointFound = true; + break; + } + } + if (isPointFound == false) // to be added in the sorted order Z greater at the top + { + bool isAdded = false; + for (int index = 0; index < count; index++) + { + if (aPoint.IntersectionPoint.Z.IsGreaterThanOrEqualTo(pointList[index].IntersectionPoint.Z)) + { + pointList.Insert(index, aPoint); + isAdded = true; + break; + } + } + + if (isAdded == false) + { + pointList.Add(aPoint); + } + } + } + else + { + pointList.Add(aPoint); + } + } + + /// + /// if two surfaces share the same curve choose any one surface + /// + private void DeleteDuplicateCurve() + { + var duplicateList = new List(); + int curveCount = layerList.Count; + object curve1 = null; + + for (int index = 0; index < curveCount; index++) + { + if (curve1 == null) + { + curve1 = layerList[index]; + } + else + { + var curve2 = layerList[index]; + + // check if there is overlapping + var curveOne = (Layer) curve1; + var curveTwo = curve2; + + if (curveOne.StartPoint.Z.IsGreaterThanOrEqualTo(curveTwo.StartPoint.Z) && curveOne.EndPoint.Z.IsLessThanOrEqualTo(curveTwo.EndPoint.Z)) + { + duplicateList.Add(layerList[index]); + } + // Case - No space between two consecutive curves + else + { + curve1 = layerList[index]; + } + } + } + + for (int index = 0; index < duplicateList.Count; index++) + { + if (layerList.Contains(duplicateList[index])) + { + layerList.Remove(duplicateList[index]); + } + } + } + } +} \ No newline at end of file Index: dam engine/branches/Initial Source/Deltares.DamEngine.Data/Geotechnics/SoilSurfaceProfile.cs =================================================================== diff -u --- dam engine/branches/Initial Source/Deltares.DamEngine.Data/Geotechnics/SoilSurfaceProfile.cs (revision 0) +++ dam engine/branches/Initial Source/Deltares.DamEngine.Data/Geotechnics/SoilSurfaceProfile.cs (revision 282) @@ -0,0 +1,601 @@ +// Copyright (C) Stichting Deltares 2017. All rights reserved. +// +// This file is part of the Delta Shell Light Library. +// +// The Delta Shell Light Library 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 System.Xml.Serialization; +using Deltares.DamEngine.Data.Geometry; +using Deltares.DamEngine.Data.Standard; +using Deltares.DamEngine.Data.Standard.Validation; + +namespace Deltares.DamEngine.Data.Geotechnics +{ + /// + /// + /// A SoilSurfaceProfile constructs a SoilProfile2D object by merging an existing SoilProfile1D with a SurfaceLine + /// + /// Note that actual contruction of 2D based on surface line and 1D happens on setting the properties using dirty flags. + /// + public class SoilSurfaceProfile : SoilProfile2D + { + private Soil dikeEmbankmentMaterial; + private bool dirty; + private bool initial = true; + private SoilProfile1D soilProfile; + private SoilProfile1D orgSoilProfile; + private GeometryPointString surfaceLine; + private SurfaceLine2 surfaceLine2; + private bool createSettlementZones; + + /// + /// Initializes a new instance of the class. + /// + public SoilSurfaceProfile() + { + Name = "Soil Surface Profile"; + } + + /// + /// Gets or sets the surface line. + /// + /// + /// The surface line. + /// + [Validate] + public GeometryPointString SurfaceLine + { + get + { + return surfaceLine; + } + set + { + surfaceLine = value; + dirty = true; + } + } + + /// + /// Gets or sets the surface line2. + /// + [Validate] + public SurfaceLine2 SurfaceLine2 + { + get + { + return surfaceLine2; + } + set + { + surfaceLine2 = value; + if (surfaceLine2 != null) + { + SurfaceLine = surfaceLine2.Geometry; + } + else + { + SurfaceLine = null; + } + dirty = true; + } + } + + /// + /// Gets or sets the soil profile. + /// + /// + /// The soil profile. + /// + [Validate] + public SoilProfile1D SoilProfile + { + get + { + return orgSoilProfile; + } + set + { + orgSoilProfile = value; + dirty = true; + } + } + + /// + /// Gets or sets the dike material. + /// + /// + /// The dike material. + /// + public Soil DikeEmbankmentMaterial + { + get + { + return dikeEmbankmentMaterial; + } + set + { + dikeEmbankmentMaterial = value; + dirty = true; + } + } + + /// + /// List of preconsolidation stresses + /// + [XmlIgnore] + public override List PreconsolidationStresses + { + get + { + if (orgSoilProfile != null) + { + return orgSoilProfile.PreconsolidationStresses; + } + return null; + } + } + + /// + /// Gets the surfaces. + /// + /// + /// The surfaces. + /// + [XmlIgnore] + [Validate] + public override IList Surfaces + { + get + { + if (initial || dirty) + { + UpdateLayers(); + } + return base.Surfaces; + } + } + + /// + /// Gets or sets a value indicating whether to [create settlement zones]. + /// + /// + /// true if [create settlement zones]; otherwise, false. + /// + public bool CreateSettlementZones + { + get + { + return createSettlementZones; + } + set + { + createSettlementZones = value; + } + } + + /// + /// Generates a 1D profile at a given x + /// + /// + /// Generated 1D soil profile + public override SoilProfile1D GetSoilProfile1D(double x) + { + if (initial || dirty) + { + initial = false; + + UpdateLayers(); + } + + // Try to obtain a cached soil profile (performance optimization) + var soilProfile1D = GetCachedSoilProfile1D(x); + if (soilProfile1D != null) + { + return soilProfile1D; + } + + // Otherwise, create and configure a new soil profile + soilProfile1D = new SoilProfile1D(); + + double top = SurfaceLine.GetZAtX(x); + soilProfile1D.BottomLevel = soilProfile.BottomLevel; + + if (top > soilProfile.TopLevel) + { + var emptyTopLayer = new SoilLayer1D(null, top) + { + SoilProfile = soilProfile1D + }; + soilProfile1D.Layers.Add(emptyTopLayer); + } + + for (int i = 0; i < soilProfile.Layers.Count; i++) + { + SoilLayer1D layer = soilProfile.Layers[i]; + if (layer.BottomLevel < top) + { + // Perform without publishing events because otherwise the soil profile cache would get lost + DataEventPublisher.InvokeWithoutPublishingEvents(() => + { + var newLayer = new SoilLayer1D(layer.Soil, Math.Min(layer.TopLevel, top)) + { + IsAquifer = layer.IsAquifer, + WaterpressureInterpolationModel = layer.WaterpressureInterpolationModel, + SoilProfile = soilProfile1D + }; + soilProfile1D.Layers.Add(newLayer); + }); + } + } + + // Add the newly created soil profile to the cache + cachedSoilProfiles1D[x] = soilProfile1D; + + return soilProfile1D; + } + + /// + /// Returns a that represents this instance (either Name or SoilProfile). + /// + /// + /// A that represents this instance. + /// + public override string ToString() + { + if (!string.IsNullOrEmpty(Name)) + { + return Name; + } + if (orgSoilProfile != null) + { + return orgSoilProfile.ToString(); + } + return "Soil Surface Profile with null Soil Profile"; + } + + /// + /// Converts to soil profile2D. + /// + /// + public SoilProfile2D ConvertToSoilProfile2D() + { + var soilProfile2D = new SoilProfile2D + { + Geometry = Geometry + }; + soilProfile2D.Surfaces.AddRange(Surfaces); + soilProfile2D.Name = Name; + return soilProfile2D; + + } + + #region IDisposable + + public override void Dispose() + { + DataEventPublisher.OnAfterChange -= DataEventPublisherListener; + // TODO: Base also subscribed to this event: reuse? + DataEventPublisher.OnDataListModified -= DataEventPublisherListener; + // TODO: Base also subscribed to this event: reuse? + DataEventPublisher.OnActionCompleted -= DataEventPublisher_OnActionCompleted; + + var disposableSurfaceLine = surfaceLine as IDisposable; + if (disposableSurfaceLine != null) + { + disposableSurfaceLine.Dispose(); + } + + base.Dispose(); + } + + #endregion + + /// + /// Handles the events of the DataEventPublisher control: + /// sets dirty to true if sender is SoilLayer1D and Properties[0] is SoilProfile + /// + /// The source of the event. + /// The instance containing the event data. + private void DataEventPublisherListener(object sender, PublishEventArgs e) + { + if (!dirty && NeedsUpdate(sender)) + { + if (!(sender is SoilLayer1D && e.Properties.Length > 0 && e.Properties[0].Equals("SoilProfile"))) + { + dirty = true; + } + } + if (orgSoilProfile != null && ReferenceEquals(sender, orgSoilProfile.Layers) && e is DataListModifiedArgs) + { + UpdateLayers(); + } + } + + /// + /// Handles the OnActionCompleted event of the DataEventPublisher control: Updates layers. + /// + /// The source of the event. + /// The instance containing the event data. + private void DataEventPublisher_OnActionCompleted(object sender, PublishEventArgs e) + { + if (dirty && !initial) + { + UpdateLayers(); + } + } + + /// + /// Checks whether an update is necessary + /// + /// + /// true if an update is necessary; otherwise, false. + /// + private bool NeedsUpdate(object sender) + { + if (sender == null) + { + return false; + } + + // check surface line + if (sender == surfaceLine + || (surfaceLine != null && sender == surfaceLine.Points)) + { + return true; + } + + // check soil profile + if (sender == orgSoilProfile) + { + return true; + } + + // check soil layers in soil profile + if (sender is SoilLayer1D + && orgSoilProfile != null + && orgSoilProfile.Layers.Any(layer => layer == sender)) + { + return true; + } + + // check points in surface line + if (sender is GeometryPoint && surfaceLine != null) + { + return surfaceLine.Points.Any(point => point == sender); + } + + return false; + } + + /// + /// Updates the dike material. + /// + private void UpdateDikeMaterial() + { + if (soilProfile != null && SurfaceLine != null) + { + double topSurfaceLine = SurfaceLine.GetMaxZ(); + if (!double.IsNaN(topSurfaceLine) && (soilProfile.Layers.Count == 0 || soilProfile.TopLevel < topSurfaceLine)) + { + double newTopLevel = topSurfaceLine + 0.5; + + if (soilProfile.Layers.Count > 0 && soilProfile.Layers[0].Soil == DikeEmbankmentMaterial) + { + SoilLayer1D dikeMaterialLayer = soilProfile.Layers[0]; + dikeMaterialLayer.TopLevel = newTopLevel; + } + else + { + // Add toplayer of dikematerial + var newLayer = new SoilLayer1D + { + TopLevel = newTopLevel, + Soil = DikeEmbankmentMaterial, + }; + + // special handling for dummy soil profiles + if (soilProfile.Layers.Count == 0 && DikeEmbankmentMaterial == null) + { + soilProfile.BottomLevel = SurfaceLine.GetMinZ() - 1; + } + + soilProfile.Layers.Insert(0, newLayer); + soilProfile.EnsureLastLayerHasHeight(); + } + } + } + } + + /// + /// Adds the layer geometry. + /// + /// The data. + /// The layer. + /// The minimum x. + /// The maximum x. + private static void AddLayerGeometry(GeometryData data, SoilLayer1D layer, double minX, double maxX) + { + var top = layer.TopLevel; + var bottom = layer.BottomLevel; + + if (Math.Abs(layer.BottomLevel - layer.SoilProfile.BottomLevel) < GeometryConstants.Accuracy) + { + bottom = data.Bottom; + } + + var bottomLeft = new GeometryPoint(minX, 0, bottom); + var bottomRight = new GeometryPoint(maxX, 0, bottom); + var topLeft = new GeometryPoint(minX, 0, top); + var topRight = new GeometryPoint(maxX, 0, top); + + data.Points.Add(bottomLeft); + data.Points.Add(bottomRight); + data.Points.Add(topLeft); + data.Points.Add(topRight); + + data.Curves.Add(new GeometryCurve(bottomLeft, bottomRight)); + data.Curves.Add(new GeometryCurve(bottomRight, topRight)); + data.Curves.Add(new GeometryCurve(topRight, topLeft)); + data.Curves.Add(new GeometryCurve(topLeft, bottomLeft)); + } + + private void AddSurfaceLineGeometry(GeometryData data) + { + var current = surfaceLine.Points[0]; + data.Points.Add(current); + for (int i = 1; i < surfaceLine.Points.Count; ++i) + { + var previous = current; + current = surfaceLine.Points[i]; + + data.Points.Add(current); + data.Curves.Add(new GeometryCurve(previous, current)); + } + } + + private void AddSettlementZones(GeometryData locGeometry) + { + + if (surfaceLine2 != null && surfaceLine2.HasDike()) + { + var xToeRiver = surfaceLine2.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.DikeToeAtRiver).X; + AddVerticalAt(locGeometry, xToeRiver); + var xTopRiver = surfaceLine2.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.DikeTopAtRiver).X; + var xRiver = xToeRiver + (xTopRiver - xToeRiver) / 3.0; + AddVerticalAt(locGeometry, xRiver); + + var xToePolder = surfaceLine2.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.DikeToeAtPolder).X; + var xTopPolder = surfaceLine2.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.DikeTopAtPolder).X; + var xPolder = xTopPolder + 2 * (xToePolder - xTopPolder) / 3.0; + AddVerticalAt(locGeometry, xPolder); + AddVerticalAt(locGeometry, xToePolder); + } + } + + private void AddVerticalAt(GeometryData aGeometry, double x) + { + const double ymax = 100000.0; + var topX = new GeometryPoint(x, 0, ymax); + var bottomX = new GeometryPoint(x, 0, -ymax); + aGeometry.Points.Add(topX); + aGeometry.Points.Add(bottomX); + aGeometry.Curves.Add(new GeometryCurve(topX, bottomX)); + aGeometry.NewlyEffectedCurves.Add(aGeometry.Curves.Last()); + } + + private void BuildGeometryModel() + { + if (surfaceLine == null + || soilProfile == null + || soilProfile.Layers.Count == 0 + || surfaceLine.GetMaxZ() < soilProfile.BottomLevel + || surfaceLine.Points.Count < 2) + { + return; + } + + var bounds = SurfaceLine.GetGeometryBounds(); + double minX = bounds.Left; + double maxX = bounds.Right; + + Geometry.Clear(); + Geometry.Left = minX; + Geometry.Right = maxX; + Geometry.Bottom = Math.Min(soilProfile.BottomLevel, surfaceLine.GetMinZ() - 1); + + // add profile geometry + soilProfile.Layers.Sort(); + foreach (var layer in soilProfile.Layers) + { + AddLayerGeometry(Geometry, layer, minX, maxX); + } + + // add surface line geometry + AddSurfaceLineGeometry(Geometry); + + // add the extra lines to create the settlementzones if required + if (createSettlementZones) + { + AddSettlementZones(Geometry); + } + Geometry.NewlyEffectedPoints.AddRange(Geometry.Points); + Geometry.NewlyEffectedCurves.AddRange(Geometry.Curves); + Geometry.RegenerateGeometry(); + Geometry.DeleteLooseCurves(); + } + + private void RebuildSurfaces(GeometryData locGeometry) + { + Surfaces.Clear(); + if (locGeometry == null || surfaceLine == null) + { + return; + } + var gu = new GeotechnicsUtilities(); + gu.RemoveGeometryDataAboveSurfaceLine(ref locGeometry, surfaceLine); + foreach (var geometrySurface in locGeometry.Surfaces) + { + var bounds = geometrySurface.GetGeometryBounds(); + var z = (bounds.Top + bounds.Bottom) * 0.5; + + var soilLayer = soilProfile.GetLayerAt(z); + + if (soilLayer != null) + { + Surfaces.Add(new SoilLayer2D + { + GeometrySurface = geometrySurface, + IsAquifer = soilLayer.IsAquifer, + WaterpressureInterpolationModel = soilLayer.WaterpressureInterpolationModel, + Soil = soilLayer.Soil, + SoilProfile = this + }); + } + } + } + + /// + /// Updates the layers. + /// + private void UpdateLayers() + { + dirty = false; + initial = false; + + // Clear all cached soil profiles + cachedSoilProfiles1D.Clear(); + + DataEventPublisher.InvokeWithoutPublishingEvents(() => + { + if (orgSoilProfile != null) + { + soilProfile = (SoilProfile1D)orgSoilProfile.Clone(); + + UpdateDikeMaterial(); + BuildGeometryModel(); + RebuildSurfaces(Geometry); + } + }); + DataEventPublisher.DataListModified(Surfaces); + } + } +} \ No newline at end of file Index: dam engine/branches/Initial Source/Deltares.DamEngine.Data/Geotechnics/SurfaceLineException.cs =================================================================== diff -u --- dam engine/branches/Initial Source/Deltares.DamEngine.Data/Geotechnics/SurfaceLineException.cs (revision 0) +++ dam engine/branches/Initial Source/Deltares.DamEngine.Data/Geotechnics/SurfaceLineException.cs (revision 282) @@ -0,0 +1,35 @@ +// Copyright (C) Stichting Deltares 2017. All rights reserved. +// +// This file is part of the Delta Shell Light Library. +// +// The Delta Shell Light Library 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. + +namespace Deltares.DamEngine.Data.Geotechnics +{ + /// + /// Surface Line Exception + /// + public class SurfaceLineException : System.Exception + { + /// + /// Initializes a new instance of the class. + /// + /// The message that describes the error. + public SurfaceLineException(string message) : base(message) {} + } +} \ No newline at end of file Index: dam engine/branches/Initial Source/Deltares.DamEngine.Data/General/Sensors/SensorLocation.cs =================================================================== diff -u --- dam engine/branches/Initial Source/Deltares.DamEngine.Data/General/Sensors/SensorLocation.cs (revision 0) +++ dam engine/branches/Initial Source/Deltares.DamEngine.Data/General/Sensors/SensorLocation.cs (revision 282) @@ -0,0 +1,473 @@ +//----------------------------------------------------------------------- +// +// Copyright (c) 2012 Deltares. All rights reserved. +// +// B. Faassen +// barry.faassen@deltares.nl +// 1-8-2012 +// n.a. +//----------------------------------------------------------------------- + +using System; +using System.Collections; +using System.Collections.Generic; +using System.ComponentModel; +using System.Linq; +using System.Linq.Expressions; +using System.Xml.Serialization; +using Deltares.DamEngine.Data.Geotechnics; +using Deltares.DamEngine.Data.Standard; + +namespace Deltares.DamEngine.Data.General.Sensors +{ + /// + /// Association class for sensor data and a location + /// + [Serializable] + public class SensorLocation + { + #region Business Rules + + /// + /// Specication to test if the value of the candidate is valid + /// + internal class IgnoreOrLocationData : PredicateSpecification + { + public IgnoreOrLocationData() + : base(x => x == DataSourceTypeSensors.Ignore || x == DataSourceTypeSensors.LocationData) + { + Description = "Only Ignore or LocationData value allowed for this property."; + } + } + + /// + /// Specication to test if the value of the candidate is valid + /// + internal class SensorOrLocationData : PredicateSpecification + { + public SensorOrLocationData() + : base(x => x == DataSourceTypeSensors.Sensor || x == DataSourceTypeSensors.LocationData) + { + Description = "Only Sensor or LocationData value allowed for this property."; + } + } + + #endregion + + /// + /// Constructor is needed for XML deserialization + /// + + public SensorLocation() + { + PL1WaterLevelAtRiver = DataSourceTypeSensors.LocationData; + PL1WaterLevelAtPolder = DataSourceTypeSensors.LocationData; + } + + private Group sensorGroup; + + /// + /// Gets the PL line offset below dike top at river. + /// + public double PLLineOffsetBelowDikeTopAtRiver + { + get { return Location.PlLineOffsetBelowDikeTopAtRiver; } + } + + /// + /// Gets the PL line offset below dike top at polder. + /// + public double PLLineOffsetBelowDikeTopAtPolder + { + get { return Location.PLLineOffsetDryBelowDikeTopAtPolder; } + } + + /// + /// Gets the PL line offset below dike toe at polder. + /// + public double PLLineOffsetBelowDikeToeAtPolder + { + get { return Location.PlLineOffsetBelowDikeToeAtPolder; } + } + + /// + /// Gets the PL line offset dry below shoulder base inside. + /// + public double PLLineOffsetDryBelowShoulderBaseInside + { + get { return Location.PlLineOffsetBelowShoulderBaseInside; } + } + + /// + /// Gets or sets the DAM location. + /// + /// + /// The location. + /// + [XmlIgnore] + [Specification(typeof(NotNullSpecification))] + public Location Location { get; set; } + + /// + /// Gets the location Name. + /// + /// + /// If the Name is empty it could indicate that there is no reference + /// to a valid location + /// + [XmlIgnore] + public string LocationName + { + get { return (Location != null) ? Location.Name : string.Empty; } + } + + /// + /// Gets or sets the sensor group. + /// + /// + /// The group. + /// + [Specification(typeof(NotNullSpecification))] + public Group Group + { + get { return sensorGroup; } + set + { + sensorGroup = value; + } + } + + public void ResetGroupID(int id) + { + sensorGroup.ID = id; + } + + /// + /// Gets the group ID. + /// + /// + /// If the ID has value -1 then the there is no valid reference (null) + /// or the group is transient. + /// + [XmlIgnore] + public int GroupID + { + get + { + if (sensorGroup == null) + return -1; + + return sensorGroup.ID; + } + } + + /// + /// Gets the sensor selection. + /// + [XmlIgnore] + public IEnumerable Sensors + { + get + { + if (sensorGroup == null) + return new Sensor[0]; + + return sensorGroup.Selection; + } + } + + /// + /// Gets or sets the PL3 data source type. + /// + /// + /// The PL3. + /// + [Specification(typeof(SensorOrLocationData))] + public DataSourceTypeSensors PL3 { get; set; } + + /// + /// Gets or sets the PL4 data source type. + /// + /// + /// The PL4. + /// + [Specification(typeof(SensorOrLocationData))] + public DataSourceTypeSensors PL4 { get; set; } + + + /// + /// Gets or sets the outer water level data source type. + /// + /// + /// The outer water level. + /// + [Specification(typeof(SensorOrLocationData))] + public DataSourceTypeSensors PL1WaterLevelAtRiver { get; set; } + + /// + /// Gets or sets the PL1 PL line offset below dike top at river data source type. + /// + /// + /// Data source type for PL1 PLLine offset below dike top at river. + /// + [Specification(typeof(IgnoreOrLocationData))] + public DataSourceTypeSensors PL1PLLineOffsetBelowDikeTopAtRiver { get; set; } + + /// + /// Gets or sets the PL1 PL line offset below dike top at polder data source type + /// + /// + /// The PL1 PL line offset below dike top at polder. + /// + [Specification(typeof(IgnoreOrLocationData))] + public DataSourceTypeSensors PL1PLLineOffsetBelowDikeTopAtPolder { get; set; } + + /// + /// Gets or sets the PL1 PL line offset below shoulder base inside data source type + /// + /// + /// The PL1 PL line offset below shoulder base inside. + /// + [Specification(typeof(IgnoreOrLocationData))] + public DataSourceTypeSensors PL1PLLineOffsetBelowShoulderBaseInside { get; set; } + + /// + /// Gets or sets the PL1 PL line offset below dike toe at polder data source type. + /// + /// + /// The PL1 PL line offset below dike toe at polder. + /// + [Specification(typeof(IgnoreOrLocationData))] + public DataSourceTypeSensors PL1PLLineOffsetBelowDikeToeAtPolder { get; set; } + + /// + /// Gets or sets the PL1 polder level data source type. + /// + /// + /// The PL1 polder level. + /// + [Specification(typeof(SensorOrLocationData))] + public DataSourceTypeSensors PL1WaterLevelAtPolder { get; set; } + + /// + /// Gets the sensor count. + /// + public int SensorCount + { + get + { + return sensorGroup == null ? 0 : Group.SensorCount; + } + } + + public SurfaceLine2 SurfaceLine + { + get { return Location.SurfaceLine2; } + } + + public double RiverLevel + { + get { return Location.RiverLevel; } + } + + public double PolderLevel + { + get { return Location.PolderLevel; } + } + + public double? HeadPl3 + { + get { return Location.HeadPl3; } + } + + public double? HeadPl4 + { + get { return Location.HeadPl4; } + } + + public string Alias { get; set; } // ToDo Tom/Kin Sun Waarvoor nodig? Wordt nergens gebruikt. Kan gewoon weg!? + + public string Profile + { + get; //{ return SoilProfile2D } ; + set; + } + + public string MStabFile + { + get; //{ return SoilProfile2D } ; + set; + } + + /// + /// Gets the PiezometricHead type sensors sorted by relative location along profile. + /// + /// Type of the pl line. + /// + internal SortedDictionary GetSensorsSortedByRelativeLocationAlongProfile(PLLineType plLineType) + { + var calculatedRelativeLocations = BuildRelativeLocationTable(); + + var table = new SortedDictionary(); + + // leave out the water level and polder level sensors + var candidateSensors = + Sensors.GetBySpecification(new PiezometricHeadSensorSpecification()); + + foreach (var sensor in candidateSensors) + { + if (sensor.PLLineMappings.Contains(plLineType)) + { + double relativeLocation = sensor.RelativeLocationSpecified ? + sensor.RelativeLocation : calculatedRelativeLocations[sensor]; + + if (table.ContainsKey(relativeLocation)) + { + throw new InvalidOperationException( + "Error creating lookup table with sensors sorted by relative location along profile. The x-location " + relativeLocation + " already exists. Sensor " + sensor); + } + + table.Add(relativeLocation, sensor); + } + } + return table; + } + + /// + /// Builds the relative location table. + /// + /// + internal IDictionary BuildRelativeLocationTable() + { + var surfaceLevelOutside = SurfaceLine.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.SurfaceLevelOutside); + if (surfaceLevelOutside == null) + throw new InvalidOperationException("No SurfaceLevelOutside point on surface line defined"); + + double startPoint = surfaceLevelOutside.X; + + var dict = new Dictionary(); + foreach (Sensor sensor in Sensors) + { + double relativeLocation = startPoint + (Location.XRdDikeLine - sensor.XRd); + dict.Add(sensor, relativeLocation); + } + return dict; + } + + internal static class MemberNames + { + internal static readonly string OffsetBelowDikeToeAtPolder = StaticReflection.GetMemberName(x => x.PL1PLLineOffsetBelowDikeToeAtPolder); + internal static readonly string OffsetBelowDikeTopAtPolder = StaticReflection.GetMemberName(x => x.PL1PLLineOffsetBelowDikeTopAtPolder); + internal static readonly string OffsetBelowDikeTopAtRiver = StaticReflection.GetMemberName(x => x.PL1PLLineOffsetBelowDikeTopAtRiver); + internal static readonly string OffsetBelowShoulderBaseInside = StaticReflection.GetMemberName(x => x.PL1PLLineOffsetBelowShoulderBaseInside); + internal static readonly string WaterLevelAtRiver = StaticReflection.GetMemberName(x => x.PL1WaterLevelAtRiver); + internal static readonly string PolderLevel = StaticReflection.GetMemberName(x => x.PL1WaterLevelAtPolder); + internal static readonly string PL3 = StaticReflection.GetMemberName(x => x.PL3); + internal static readonly string PL4 = StaticReflection.GetMemberName(x => x.PL4); + } + + public double? GetValue(Expression> expression, IDictionary sensorValues, Sensor sensor) + { + if (sensorValues == null) throw new ArgumentNullException("sensorValues"); + if (sensor == null) throw new ArgumentNullException("sensor"); + + if (!sensorValues.ContainsKey(sensor)) + throw new ArgumentException("The given sensor is not an item/key in the table of sensor values"); + + var memberName = StaticReflection.GetMemberName(expression); + + if (memberName == MemberNames.OffsetBelowDikeToeAtPolder) + { + if (PL1PLLineOffsetBelowDikeToeAtPolder == DataSourceTypeSensors.LocationData) + return Location.PlLineOffsetBelowDikeToeAtPolder; + } + + if (memberName == MemberNames.OffsetBelowDikeTopAtPolder) + { + if (PL1PLLineOffsetBelowDikeTopAtPolder == DataSourceTypeSensors.LocationData) + return Location.PlLineOffsetBelowDikeTopAtPolder; + } + + if (memberName == MemberNames.OffsetBelowDikeTopAtRiver) + { + if (PL1PLLineOffsetBelowDikeTopAtRiver == DataSourceTypeSensors.LocationData) + return Location.PlLineOffsetBelowDikeTopAtRiver; + } + + if (memberName == MemberNames.OffsetBelowShoulderBaseInside) + { + if (PL1PLLineOffsetBelowShoulderBaseInside == DataSourceTypeSensors.LocationData) + return Location.PlLineOffsetBelowShoulderBaseInside; + } + + if (memberName == MemberNames.WaterLevelAtRiver) + { + if (PL1WaterLevelAtRiver == DataSourceTypeSensors.LocationData) + return Location.RiverLevel; + + if (PL1WaterLevelAtRiver == DataSourceTypeSensors.Sensor) + return sensorValues[sensor]; + } + + if (memberName == MemberNames.PolderLevel) + { + if (PL1WaterLevelAtPolder == DataSourceTypeSensors.LocationData) + return Location.PolderLevel; + + if (PL1WaterLevelAtPolder == DataSourceTypeSensors.Sensor) + return sensorValues[sensor]; + } + + if (memberName == MemberNames.PL3) + { + if (PL3 == DataSourceTypeSensors.LocationData) + return Location.HeadPl3; + + if (PL3 == DataSourceTypeSensors.Sensor) + return sensorValues[sensor]; + } + + if (memberName == MemberNames.PL4) + { + if (PL4 == DataSourceTypeSensors.LocationData) + return Location.HeadPl4; + + if (PL4 == DataSourceTypeSensors.Sensor) + return sensorValues[sensor]; + } + + + return null; + } + + /// + /// Determines whether this instance is valid. + /// + /// + /// true if this instance is valid; otherwise, false. + /// + public bool IsValid() + { + return !Validator.Validate(this).Any(); + } + + /// + /// Gets or sets the GetGroups function (injectable list, for UI purposes). + /// + /// + /// The list of available Groups. + /// + [XmlIgnore] + public static Func> GetGroups { get; set; } + + private ICollection GetGroupsDomain() + { + if (GetGroups == null) + { + return null; + } + + return GetGroups(this).ToList(); + } + } +} Index: dam engine/branches/Initial Source/Deltares.DamEngine.Data/Geotechnics/SurfaceLine2Validator.cs =================================================================== diff -u -r278 -r282 --- dam engine/branches/Initial Source/Deltares.DamEngine.Data/Geotechnics/SurfaceLine2Validator.cs (.../SurfaceLine2Validator.cs) (revision 278) +++ dam engine/branches/Initial Source/Deltares.DamEngine.Data/Geotechnics/SurfaceLine2Validator.cs (.../SurfaceLine2Validator.cs) (revision 282) @@ -52,7 +52,7 @@ /// /// The surfaceline being evaluated. /// The collection of validation results. - private IEnumerable ValidateGeometryPointsAreOrdered(SurfaceLine2 surfaceline) + public IEnumerable ValidateGeometryPointsAreOrdered(SurfaceLine2 surfaceline) { if (!ArePointsAscending(surfaceline)) { @@ -67,7 +67,7 @@ /// /// The surfaceline being evaluated. /// The collection of validation results. - private IEnumerable ValidateCharacteristicPointsAreOrdered(SurfaceLine2 surfaceline) + public IEnumerable ValidateCharacteristicPointsAreOrdered(SurfaceLine2 surfaceline) { if (!AreAllCharacteristicPointsXCoordinatesAscending(surfaceline)) { Index: dam engine/branches/Initial Source/Deltares.DamEngine.Data/Standard/ListExtension.cs =================================================================== diff -u --- dam engine/branches/Initial Source/Deltares.DamEngine.Data/Standard/ListExtension.cs (revision 0) +++ dam engine/branches/Initial Source/Deltares.DamEngine.Data/Standard/ListExtension.cs (revision 282) @@ -0,0 +1,515 @@ +// Copyright (C) Stichting Deltares 2017. All rights reserved. +// +// This file is part of the Delta Shell Light Library. +// +// The Delta Shell Light Library 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; + +namespace Deltares.DamEngine.Data.Standard +{ + /// + /// Defines a library of common IList, ICollection or IEnumerable extension methods + /// + public static class ListExtensions + { + public static bool IsEmpty(IEnumerable collection) + { + return collection == null || !collection.Any(); + } + + /// + /// Gets or creates rows of a given sequence i.e. the sequence will be transformed to a grid + /// + /// The element type in the sequence + /// The sequence to transform + /// The size of one row + /// A sequence of rows containing the number of rowSize elements + public static IEnumerable> Rows(this IEnumerable sequence, int rowSize) + { + int count = sequence.Count(); + + for (int i = 0; i < count/rowSize; i++) + { + yield return sequence.Skip(i*rowSize).Take(rowSize); + } + } + + /// + /// Removes the conditionally. + /// + /// + /// The collection. + /// The predicate. + public static void RemoveConditionally(this IList collection, Predicate predicate) + { + var work = new Queue(); + foreach (var item in collection) + { + if (predicate(item)) + { + work.Enqueue(item); + } + } + + while (work.Count > 0) + { + var item = work.Dequeue(); + collection.Remove(item); + } + } + + /// + /// Adds a range of items to the list without adding null elements + /// + /// The type of the elements in the list + /// The collection to add the items to + /// The items (collection) to add to the list + public static void AddRangeLeavingNullElementsOut(this IList collection, IEnumerable items) + where T : class + { + AddRangeConditionally(collection, items, x => x != null); + } + + /// + /// Gets the unique ID. It fills in gaps of the collection + /// + /// The type if the collection item + /// The collection to inspect. + /// The lambda that can gets the id from a item in the collection. + /// A unique ID greater then 0 + public static int GetUniqueID(this IEnumerable collection, Func idGetter) + { + if (collection == null) + { + throw new ArgumentNullException("collection"); + } + + const int tmp = 1; + bool any = collection.Any(item => idGetter(item) == tmp); + if (!any) + { + return tmp; + } + + int min = 1, max = 2; // min is inclusive, max is exclusive/untested + + while (collection.Any(item => idGetter(item) == max)) + { + min = max; + max *= 2; + } + + while (max != min + 1) + { + int pivot = (max + min)/2; + if (collection.Any(item => idGetter(item) == pivot)) + { + min = pivot; + } + else + { + max = pivot; + } + } + + return max; + } + + /// + /// Adds a range of items to the list + /// + /// The type of the elements in the list + /// The list to add the items to + /// The items (collection) to add to the list + public static void AddRange(this IList theListToAddTo, IEnumerable collection) + { + if (theListToAddTo == null) + { + throw new ArgumentNullException("theListToAddTo"); + } + + if (collection == null) + { + throw new ArgumentNullException("collection"); + } + + foreach (var item in collection) + { + theListToAddTo.Add(item); + } + } + + /// + /// Sorts the items in a list + /// + /// The type of the elements in the list + /// the list to be sorted + public static void Sort(this IList sortList) + { + if (sortList is ISortableList) + { + ((ISortableList) sortList).Sort(); + } + else if (sortList is List) + { + ((List) sortList).Sort(); + } + else + { + var workList = new List(); + foreach (var item in sortList) + { + workList.Add(item); + } + + workList.Sort(); + + sortList.Clear(); + foreach (var item in workList) + { + sortList.Add(item); + } + } + } + + public static void Sort(this IList sortList, Comparison func) + { + if (sortList is ISortableList) + { + ((ISortableList) sortList).Sort(); + } + else if (sortList is List) + { + ((List) sortList).Sort(); + } + else + { + var workList = new List(); + foreach (var item in sortList) + { + workList.Add(item); + } + + workList.Sort(func); + + // Silence events for custom IList implementations, as we do not want to fire events for clear or add: + sortList.Clear(); + foreach (var item in workList) + { + sortList.Add(item); + } + } + } + + /// + /// Sorts the items in a list in reversed order + /// + /// The type of the elements in the list + /// the list to be sorted + public static void Reverse(this IList sortList) + { + if (sortList is ISortableList) + { + ((ISortableList) sortList).Reverse(); + } + else if (sortList is List) + { + ((List) sortList).Reverse(); + } + else + { + var workList = new List(); + foreach (var item in sortList) + { + workList.Add(item); + } + + workList.Reverse(); + + sortList.Clear(); + foreach (var item in workList) + { + sortList.Add(item); + } + } + } + + public static T Find(this IList findList, Predicate match) + { + if (findList is IFindList) + { + return ((IFindList) findList).Find(match); + } + else if (findList is List) + { + return ((List) findList).Find(match); + } + else + { + throw new NotImplementedException("Find"); + } + } + + public static List FindAll(this IList findList, Predicate match) + { + if (findList is IFindList) + { + return ((IFindList) findList).FindAll(match); + } + else if (findList is List) + { + return ((List) findList).FindAll(match); + } + else + { + throw new NotImplementedException("FindAll"); + } + } + + public static int FindIndex(this IList findList, Predicate match) + { + if (findList is IFindList) + { + return ((IFindList) findList).FindIndex(match); + } + else if (findList is List) + { + return ((List) findList).FindIndex(match); + } + else + { + throw new NotImplementedException("Find"); + } + } + + public static T FindLast(this IList findList, Predicate match) + { + if (findList is IFindList) + { + return ((IFindList) findList).FindLast(match); + } + else if (findList is List) + { + return ((List) findList).FindLast(match); + } + else + { + throw new NotImplementedException("Find"); + } + } + + public static int FindLastIndex(this IList findList, Predicate match) + { + if (findList is IFindList) + { + return ((IFindList) findList).FindLastIndex(match); + } + if (findList is List) + { + return ((List) findList).FindLastIndex(match); + } + else + { + throw new NotImplementedException("Find"); + } + } + + /// + /// Adds a range of items to the list + /// + /// The type of the elements in the list + /// The list to add the items to + /// The items (collection) to add to the list + /// The items predicate or requirement that needs to be true before the item can be added + public static void AddRangeConditionally(this IList collection, IEnumerable items, + Func predicate) + where T : class + { + if (collection == null) + { + throw new ArgumentNullException("collection"); + } + + if (items == null) + { + throw new ArgumentNullException("items"); + } + + if (predicate == null) + { + throw new ArgumentNullException("predicate"); + } + + foreach (var item in items) + { + if (predicate(item)) + { + collection.Add(item); + } + } + } + + /// + /// Adds a range of items to the list + /// + /// The type of the elements in the list + /// The type of the elements in the collection + /// The collection to add the items to + /// The items to add to the list + /// + public static void AddRange(this IList collection, + IEnumerable items, + Func selector) + { + if (items == null) + { + throw new ArgumentNullException("collection"); + } + + if (items == null) + { + throw new ArgumentNullException("items"); + } + + if (selector == null) + { + throw new ArgumentNullException("selector"); + } + + foreach (var item in items) + { + collection.Add(selector(item)); + } + } + + /// + /// Maps a list of a specific type to a list with another type + /// + /// The source list element type + /// The destination type + /// The source list + /// The selector that returns the destination type instance + /// A collection with the mapped items + public static IEnumerable MapTo( + this IEnumerable source, Func selector) + { + if (source == null) + { + throw new ArgumentNullException("source"); + } + + if (selector == null) + { + throw new ArgumentNullException("selector"); + } + + foreach (var item in source) + { + yield return selector(item); + } + } + + /// + /// Removes null elements from a list + /// + /// + /// + public static void RemoveNullElements(this IList list) + where T : class + { + int index; + while ((index = list.IndexOf(null)) >= 0) + { + list.RemoveAt(index); + } + } + + /// + /// Performs a binary search on the specified collection. + /// + /// The type of the item. + /// The type of the searched item. + /// The list to be searched. + /// The value to search for. + /// The comparer that is used to compare the value with the list items. + /// + public static int BinarySearch(this IList list, TSearch value, Func comparer) + { + if (list == null) + { + throw new ArgumentNullException("list"); + } + if (comparer == null) + { + throw new ArgumentNullException("comparer"); + } + + int lower = 0; + int upper = list.Count - 1; + + int middle = lower; + while (lower <= upper) + { + middle = lower + (upper - lower)/2; + int comparisonResult = comparer(value, list[middle]); + if (comparisonResult < 0) + { + upper = middle - 1; + } + else if (comparisonResult > 0) + { + lower = middle + 1; + } + else + { + return middle; + } + } + + return ~lower; + } + + /// + /// Performs a binary search on the specified collection. + /// + /// The type of the item. + /// The list to be searched. + /// The value to search for. + /// + public static int BinarySearch(this IList list, TItem value) + { + return BinarySearch(list, value, Comparer.Default); + } + + /// + /// Performs a binary search on the specified collection. + /// + /// The type of the item. + /// The list to be searched. + /// The value to search for. + /// The comparer that is used to compare the value with the list items. + /// + public static int BinarySearch(this IList list, TItem value, IComparer comparer) + { + return list.BinarySearch(value, comparer.Compare); + } + } +} \ No newline at end of file Index: dam engine/branches/Initial Source/Deltares.DamEngine.Data/General/Location.cs =================================================================== diff -u -r276 -r282 --- dam engine/branches/Initial Source/Deltares.DamEngine.Data/General/Location.cs (.../Location.cs) (revision 276) +++ dam engine/branches/Initial Source/Deltares.DamEngine.Data/General/Location.cs (.../Location.cs) (revision 282) @@ -14,10 +14,15 @@ using System.ComponentModel; using System.Globalization; using System.IO; +using System.Linq; using System.Xml.Serialization; using Deltares.DamEngine.Data.Design; +using Deltares.DamEngine.Data.General.Gauges; +using Deltares.DamEngine.Data.General.PlLines; using Deltares.DamEngine.Data.Geometry; using Deltares.DamEngine.Data.Geotechnics; +using Deltares.DamEngine.Data.Probabilistic; +using Deltares.DamEngine.Data.Standard; using Deltares.DamEngine.Data.Standard.Language; using Deltares.DamEngine.Data.Standard.Validation; @@ -123,8 +128,7 @@ public const string IntrusionVerticalWaterPressure = "IntrusionVerticalWaterPressure"; } - [TrackChanges] - public class Location : IDisposable + public class Location { // Added initial value as these properties must be tested for real values on import public const string AllCategory = "MainItems"; @@ -3772,18 +3776,6 @@ return sb.ToString();*/ } - public void Dispose() - { - if (surfaceLine != null) - { - surfaceLine.Dispose(); - } - if (LocalXZSurfaceLine2 != null) - { - LocalXZSurfaceLine2.Dispose(); - } - } - public ICollection GetDomain(string property) { switch (property) Index: dam engine/branches/Initial Source/Deltares.DamEngine.Data/Standard/IFindList.cs =================================================================== diff -u --- dam engine/branches/Initial Source/Deltares.DamEngine.Data/Standard/IFindList.cs (revision 0) +++ dam engine/branches/Initial Source/Deltares.DamEngine.Data/Standard/IFindList.cs (revision 282) @@ -0,0 +1,35 @@ +// Copyright (C) Stichting Deltares 2017. All rights reserved. +// +// This file is part of the Delta Shell Light Library. +// +// The Delta Shell Light Library 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; + +namespace Deltares.DamEngine.Data.Standard +{ + public interface IFindList + { + T Find(Predicate match); + List FindAll(Predicate match); + int FindIndex(Predicate match); + T FindLast(Predicate match); + int FindLastIndex(Predicate match); + } +} \ No newline at end of file Index: dam engine/branches/Initial Source/Deltares.DamEngine.Data/Geotechnics/Layer.cs =================================================================== diff -u --- dam engine/branches/Initial Source/Deltares.DamEngine.Data/Geotechnics/Layer.cs (revision 0) +++ dam engine/branches/Initial Source/Deltares.DamEngine.Data/Geotechnics/Layer.cs (revision 282) @@ -0,0 +1,93 @@ +// Copyright (C) Stichting Deltares 2017. All rights reserved. +// +// This file is part of the Macro Stability kernel. +// +// The Macro Stability kernel is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero 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 Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero 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 Deltares.DamEngine.Data.Geometry; + +namespace Deltares.DamEngine.Data.Geotechnics +{ + /// + /// publisherEventArgs helper struct, to aid in Layer Intersection + /// TODO: Comment + /// + public struct LayerIntersectionPoint + { + private readonly Point2D intersectionPoint; + private readonly SoilLayer2D surfaceRefKey; + + internal LayerIntersectionPoint(Point2D aIntersectionPoint, SoilLayer2D aSurfaceRefKey) + { + intersectionPoint = aIntersectionPoint; + surfaceRefKey = aSurfaceRefKey; + } + + internal Point2D IntersectionPoint + { + get + { + return intersectionPoint; + } + } + + internal SoilLayer2D SurfaceRefKey + { + get + { + return surfaceRefKey; + } + } + } + + /// + /// publisherEventArgs helper struct, to aid in Layer Intersection + /// TODO: Comment + /// + public class Layer : SoilLayer1D + { + /// + /// Initializes a new instance of the class. + /// + /// A start point. + /// An end point. + /// A stability soil properties ID. + public Layer(Point2D aStartPoint, Point2D aEndPoint, Soil aStabilitySoilPropertiesId) + { + StartPoint = aStartPoint; + EndPoint = aEndPoint; + Soil = aStabilitySoilPropertiesId; + } + + /// + /// Gets or sets the start point. + /// + /// + /// The start point. + /// + public Point2D StartPoint { get; set; } + + /// + /// Gets or sets the end point. + /// + /// + /// The end point. + /// + public Point2D EndPoint { get; set; } + } +} \ No newline at end of file Index: dam engine/branches/Initial Source/Deltares.DamEngine.Data/General/Segment.cs =================================================================== diff -u --- dam engine/branches/Initial Source/Deltares.DamEngine.Data/General/Segment.cs (revision 0) +++ dam engine/branches/Initial Source/Deltares.DamEngine.Data/General/Segment.cs (revision 282) @@ -0,0 +1,236 @@ +//----------------------------------------------------------------------- +// +// Copyright (c) 2010 Deltares. All rights reserved. +// +// B.S.T.I.M. The +// tom.the@deltares.nl +// 18-05-2010 +// Segment data +//----------------------------------------------------------------------- + +using System; +using System.Collections.Generic; +using System.Globalization; +using System.Linq; +using System.Text; +using Deltares.DamEngine.Data.Geotechnics; + +namespace Deltares.DamEngine.Data.General +{ + public class SoilGeometryProbability : IComparable + { + public virtual SoilProfile1D SoilProfile { get; set; } + public virtual string SoilGeometry2DName { get; set; } + public virtual SoilProfile2D SoilProfile2D { get; set; } + public virtual FailureMechanismSystemType? SegmentFailureMechanismType { get; set; } + public virtual double Probability { get; set; } // Probability of occurance; number between 0.0 and 100.0 + + /// + /// Assigns the specified soil geometry probability. + /// + /// The soil geometry probability. + public void Assign(SoilGeometryProbability soilGeometryProbability) + { + if (soilGeometryProbability.SoilProfile != null) + { + SoilProfile = new SoilProfile1D(); + SoilProfile.Assign(soilGeometryProbability.SoilProfile); + } + SegmentFailureMechanismType = soilGeometryProbability.SegmentFailureMechanismType; + Probability = soilGeometryProbability.Probability; + SoilGeometry2DName = soilGeometryProbability.SoilGeometry2DName; + } + + public SoilGeometryType SoilGeometryType + { + get + { + if (SoilProfile != null) + { + return SoilGeometryType.SoilGeometry1D; + } + else + { + if (SoilGeometry2DName == null) + { + throw new Exception("No soilprofile assigned"); + } + return SoilGeometryType.SoilGeometry2D; + } + } + } + + /// + /// Returns either the 1D-geometry or the 2D-geometry name + /// + public virtual string SoilGeometryName + { + get + { + string soilGeometryName = ""; + if (this.SoilProfile != null) + { + soilGeometryName = this.SoilProfile.Name; + } + else + { + soilGeometryName = this.SoilGeometry2DName; + } return soilGeometryName; + } + } + + public int CompareTo(SoilGeometryProbability other) + { + return - this.Probability.CompareTo(other.Probability); + } + } + + public class Segment + { + private List soilGeometryProbabilities = new List(); + + public virtual string Name { get; set; } + + /// + /// Gets the soil probalilities for this segment + /// + public virtual List SoilProfileProbabilities + { + get { return this.soilGeometryProbabilities; } + } + + public SoilProfile1D GetMostProbableProfile(FailureMechanismSystemType? segmentFailureMechanismType) + { + IEnumerable spps = from SoilGeometryProbability spp in this.soilGeometryProbabilities + where !spp.SegmentFailureMechanismType.HasValue || !segmentFailureMechanismType.HasValue || spp.SegmentFailureMechanismType == segmentFailureMechanismType + orderby spp.Probability descending + select spp; + if (spps.Count() > 0) + return spps.First().SoilProfile; + else + return null; + } + + public string GetMostProbableGeometry2DName(FailureMechanismSystemType? segmentFailureMechanismType) + { + IEnumerable spps = from SoilGeometryProbability spp in this.soilGeometryProbabilities + where !spp.SegmentFailureMechanismType.HasValue || !segmentFailureMechanismType.HasValue || spp.SegmentFailureMechanismType == segmentFailureMechanismType + orderby spp.Probability descending + select spp; + if (spps.Count() > 0) + return spps.First().SoilGeometry2DName; + else + return null; + } + + public void AddSoilProfileProbability(SoilProfile1D soilProfile, double probability, FailureMechanismSystemType? segmentFailureMechanismType) + { + if (this.soilGeometryProbabilities.Where(x => x.SoilProfile == soilProfile && x.SegmentFailureMechanismType == segmentFailureMechanismType).Count() == 0) + this.soilGeometryProbabilities.Add(new SoilGeometryProbability() { SoilProfile = soilProfile, Probability = probability, SegmentFailureMechanismType = segmentFailureMechanismType, SoilGeometry2DName = null }); + } + + public double? GetSoilProfileProbability(SoilProfile1D soilProfile, FailureMechanismSystemType? segmentFailureMechanismType) + { + IEnumerable probs = this.soilGeometryProbabilities.Where( + x => (x.SoilProfile == soilProfile) && + (segmentFailureMechanismType == null || x.SegmentFailureMechanismType == segmentFailureMechanismType || x.SegmentFailureMechanismType == null)); + + if (probs.Count() > 0) + return probs.Select(x => x.Probability).Average(); + else + return null; + } + + public void AddSoilGeometry2DProbability(string soilGeometry2DName, double probability, FailureMechanismSystemType? segmentFailureMechanismType) + { + if (this.soilGeometryProbabilities.Where(x => x.SoilGeometry2DName == soilGeometry2DName && x.SegmentFailureMechanismType == segmentFailureMechanismType).Count() == 0) + this.soilGeometryProbabilities.Add(new SoilGeometryProbability() { SoilProfile = null, Probability = probability, SegmentFailureMechanismType = segmentFailureMechanismType, SoilGeometry2DName = soilGeometry2DName }); + } + + public double? GetSoilGeometry2DProbability(string soilGeometry2DName, FailureMechanismSystemType? segmentFailureMechanismType) + { + IEnumerable probs = this.soilGeometryProbabilities.Where( + x => (x.SoilGeometry2DName == soilGeometry2DName) && + (segmentFailureMechanismType == null || x.SegmentFailureMechanismType == segmentFailureMechanismType || x.SegmentFailureMechanismType == null)); + + if (probs.Count() > 0) + return probs.Select(x => x.Probability).Average(); + else + return null; + } + + public override string ToString() + { + StringBuilder sb = new StringBuilder(); + sb.Append(this.Name); + sb.Append(": "); + foreach (FailureMechanismSystemType type in Enum.GetValues(typeof(FailureMechanismSystemType))) + { + sb.Append(type.ToString()); + sb.Append(": "); + foreach (SoilGeometryProbability spp in this.SoilProfileProbabilities.Where(x => x.SegmentFailureMechanismType == null || x.SegmentFailureMechanismType == type)) + { + if (spp.SoilProfile != null) + { + sb.Append(String.Format("(1D) {0} ({1}%) ", spp.SoilProfile.Name, spp.Probability)); + } + else + { + sb.Append(String.Format("(2D) {0} ({1}%) ", spp.SoilGeometry2DName, spp.Probability)); + } + } + } + + return sb.ToString(); + } + + /// + /// Assemble a list of key/value pairs with the relevant parameters for the specified 1d-profile + /// + /// + public Dictionary GetParametersForSoilProfile1DAsNameValuePairs(string soilProfile1DId, FailureMechanismSystemType failureMechanismSystemType) + { + SoilGeometryProbability soilProfileProbability = this.SoilProfileProbabilities.FirstOrDefault(x => (x.SoilProfile != null && + x.SoilProfile.Name.Equals(soilProfile1DId) && + x.SegmentFailureMechanismType == failureMechanismSystemType + )); + if (soilProfileProbability != null) + { + var nameValuePairs = new Dictionary(); + var numberFormatInfo = new NumberFormatInfo(); + numberFormatInfo.NumberDecimalSeparator = "."; + nameValuePairs.Add("Probability", soilProfileProbability.Probability.ToString(numberFormatInfo)); + nameValuePairs.Add("FailureMechanismType", soilProfileProbability.SegmentFailureMechanismType.ToString()); + return nameValuePairs; + } + else + { + return null; + } + } + + /// + /// Assemble a list of key/value pairs with the relevant parameters for the specified 2d-profile + /// + /// + public Dictionary GetParametersForSoilProfile2DAsNameValuePairs(string soilProfile2DId, FailureMechanismSystemType failureMechanismSystemType) + { + SoilGeometryProbability soilProfileProbability = this.SoilProfileProbabilities.FirstOrDefault(x => x.SoilGeometry2DName.Equals(soilProfile2DId) && + x.SegmentFailureMechanismType == failureMechanismSystemType); + if (soilProfileProbability != null) + { + var nameValuePairs = new Dictionary(); + var numberFormatInfo = new NumberFormatInfo(); + numberFormatInfo.NumberDecimalSeparator = "."; + nameValuePairs.Add("Probability", soilProfileProbability.Probability.ToString(numberFormatInfo)); + nameValuePairs.Add("FailureMechanismType", soilProfileProbability.SegmentFailureMechanismType.ToString()); + return nameValuePairs; + } + else + { + return null; + } + } + } + +} \ No newline at end of file Index: dam engine/branches/Initial Source/Deltares.DamEngine.Data/General/Dike.cs =================================================================== diff -u -r278 -r282 --- dam engine/branches/Initial Source/Deltares.DamEngine.Data/General/Dike.cs (.../Dike.cs) (revision 278) +++ dam engine/branches/Initial Source/Deltares.DamEngine.Data/General/Dike.cs (.../Dike.cs) (revision 282) @@ -11,11 +11,10 @@ using System; using System.Collections.Generic; using System.ComponentModel; -using System.IO; using System.Linq; -using System.Xml.Serialization; using Deltares.DamEngine.Data.Design; using Deltares.DamEngine.Data.General.Gauges; +using Deltares.DamEngine.Data.General.NWO; using Deltares.DamEngine.Data.General.PlLines; using Deltares.DamEngine.Data.Geotechnics; using Deltares.DamEngine.Data.Standard; @@ -37,7 +36,7 @@ public const string MapForSoilGeometries2D = "MapForSoilGeometries2D"; } - public class Dike: IDisposable + public class Dike { private string description = ""; public virtual string MapForSoilGeometries2D { get; set; } @@ -62,7 +61,7 @@ this.locations = new List(); this.soilProfiles = new List(); - this.surfaceLines = new DelegatedList { AddMethod = ConvertAddedOldSurfaceLineToNewFormat }; + // this.surfaceLines = new DelegatedList { AddMethod = ConvertAddedOldSurfaceLineToNewFormat }; SurfaceLines2 = new List(); this.pl1Lines = new List(); this.soilList = new SoilList(); @@ -111,9 +110,6 @@ } - [XmlIgnore] - public SoilbaseDB SoilBaseDB { get; set; } - /// /// Gets the locations. /// @@ -216,55 +212,8 @@ } } - public void CreateSoilBase() - { - if (this.SoilDatabaseName == null || !File.Exists(this.SoilDatabaseName)) - { - throw new DikeException(String.Format("The soil database '{0}' cannot be found", this.SoilDatabaseName)); - } - this.SoilBaseDB = SoilbaseDB.Create(this.SoilDatabaseName); - } - + /// - /// Read all the soils and their parameters from the database - /// - public void FillDataBaseSoilListFromSoilBase() - { - using (var geoDatabase = new GeoDatabase(this.SoilDatabaseName)) - { - geoDatabase.ReUseSoils = true; - var newSoilList = geoDatabase.ReadSoils(soilList.Soils); - databaseSoils = newSoilList.Soils; - } - } - - /// - /// Add 1D-soilprofiles from MGeobase database - /// - public void AddSoilProfilesFromDB() - { - if (this.SoilDatabaseName == null || !File.Exists(this.SoilDatabaseName)) - { - throw new DikeException(String.Format("The MGeobase database '{0}' cannot be found", this.SoilDatabaseName)); - } - if (soilList.Soils.Count == 0) - { - FillDataBaseSoilListFromSoilBase(); - soilList.Soils.AddRange(databaseSoils); - } - if (soilList.Soils.Count == 0) - { - throw new DikeException(String.Format("The MGeobase database '{0}' does not contain soils and can not be used.", this.SoilDatabaseName)); - } - MGeobaseDB mgbDB = new MGeobaseDB(soilList); - IList addedSoilProfiles = mgbDB.AddSoilProfiles(this.SoilDatabaseName); - foreach (var addedSoilProfile in addedSoilProfiles) - { - soilProfiles.Add(addedSoilProfile); - } - } - - /// /// Adapt data so it is consistent /// public List MakeDataConsistent() @@ -441,22 +390,10 @@ location.MapForSoilGeometries2D = this.MapForSoilGeometries2D; location.Gauges.Clear(); - location.Gauges.AddRange(this.Gauges); + location.Gauges.AddRange(Gauges); location.GaugePLLines.Clear(); - location.GaugePLLines.AddRange(this.GaugePLLines); - } - - public void Dispose() - { - foreach (var location in Locations) - { - location.Dispose(); - } - foreach (var surfaceLine2 in SurfaceLines2) - { - surfaceLine2.Dispose(); - } - } + location.GaugePLLines.AddRange(GaugePLLines); + } } } \ No newline at end of file Index: dam engine/branches/Initial Source/Deltares.DamEngine.Data/Geotechnics/Soil.cs =================================================================== diff -u -r276 -r282 --- dam engine/branches/Initial Source/Deltares.DamEngine.Data/Geotechnics/Soil.cs (.../Soil.cs) (revision 276) +++ dam engine/branches/Initial Source/Deltares.DamEngine.Data/Geotechnics/Soil.cs (.../Soil.cs) (revision 282) @@ -47,13 +47,15 @@ private double cuBottom = double.NaN; private bool usePop = true; private double strengthIncreaseExponent = double.NaN; + private SoilType soilType; /// /// Initializes a new instance of the class. /// public Soil() { - Name = LocalizationManager.GetTranslatedText(this, "DefaultNameSoilMaterial"); + Name = LocalizationManager.GetTranslatedText(this, "DefaultNameSoilMaterial"); + soilType = SoilType.Sand; } @@ -78,7 +80,28 @@ { Name = name; } - + + /// + /// Gets or sets the type of the soil. + /// + /// + /// The type of the soil. + /// + public virtual SoilType SoilType + { + get + { + return soilType; + } + set + { + if (!soilType.Equals(value)) + { + soilType = value; + } + } + } + #region property Name /// Index: dam engine/branches/Initial Source/Deltares.DamEngine.Data/Geometry/GeometryData.cs =================================================================== diff -u --- dam engine/branches/Initial Source/Deltares.DamEngine.Data/Geometry/GeometryData.cs (revision 0) +++ dam engine/branches/Initial Source/Deltares.DamEngine.Data/Geometry/GeometryData.cs (revision 282) @@ -0,0 +1,797 @@ +// Copyright (C) Stichting Deltares 2017. All rights reserved. +// +// This file is part of the Macro Stability kernel. +// +// The Macro Stability kernel is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero 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 Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero 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 System.Xml.Serialization; +using Deltares.DamEngine.Data.Standard.Language; +using Deltares.DamEngine.Data.Standard.Validation; + +namespace Deltares.DamEngine.Data.Geometry +{ + /// + /// Class containing the geometry data + /// + /// + public class GeometryData : GeometryObject + { + private readonly List curveDataList = new List(); + + private readonly List loopDataList = new List(); + private readonly List pointDataList = new List(); + private readonly List surfaceDataList = new List(); + private readonly GeometryPointString surfaceLine = new GeometryPointString(); + private double bottom = GeometryConstants.DefaultBottomLimitGeometry; + + private double left = GeometryConstants.DefaultLeftLimitGeometry; + + private double right = GeometryConstants.DefaultRightLimitGeometry; + + private bool updatingSurfaceLine; + + #region Repairer Id's and property names + + private const string sameStartAndEndPointRepairerId = "Same start and end point"; + private const string sameStartAndEndPointRepairerPropertyName = "Points"; + private const string noSoilRepairerId = "No Soil"; + private const string noSoilRepairerPropertyName = "None"; + + #endregion + + #region properties + + /// + /// Gets the points. + /// + /// + /// The points. + /// + [XmlArray("Points")] + [Validate] + public IList Points + { + get + { + return pointDataList; + } + } + + /// + /// gets the Curve data list. + /// + /// + /// The curves. + /// + public List Curves + { + get + { + return curveDataList; + } + } + + /// + /// gets the Loop data list. + /// + /// + /// The loops. + /// + public List Loops + { + get + { + return loopDataList; + } + } + + /// + /// gets the Surface data list. + /// + public List Surfaces + { + get + { + return surfaceDataList; + } + } + + /// + /// Gets the minimum geometry points x. + /// + /// + /// The minimum geometry points x. + /// + [XmlIgnore] + public double MinGeometryPointsX + { + get + { + return Points.Select(geometryPoint => geometryPoint.X).Concat(new[] + { + double.MaxValue + }).Min(); + } + } + + /// + /// Gets the minimum geometry points z. + /// + /// + /// The minimum geometry points z. + /// + [XmlIgnore] + public double MinGeometryPointsZ + { + get + { + return Points.Select(geometryPoint => geometryPoint.Z).Concat(new[] + { + double.MaxValue + }).Min(); + } + } + + /// + /// Gets the maximum geometry points x. + /// + /// + /// The maximum geometry points x. + /// + [XmlIgnore] + public double MaxGeometryPointsX + { + get + { + return Points.Select(geometryPoint => geometryPoint.X).Concat(new[] + { + double.MinValue + }).Max(); + } + } + + /// + /// Gets the maximum geometry points z. + /// + /// + /// The maximum geometry points z. + /// + [XmlIgnore] + public double MaxGeometryPointsZ + { + get + { + return Points.Select(geometryPoint => geometryPoint.Z).Concat(new[] + { + double.MinValue + }).Max(); + } + } + + /// + /// Gets or sets the left. + /// + /// + /// The left. + /// + public double Left + { + get + { + return left; + } + set + { + left = value; + } + } + + /// + /// Gets or sets the right. + /// + /// + /// The right. + /// + public double Right + { + get + { + return right; + } + set + { + right = value; + } + } + + /// + /// Gets or sets the bottom. + /// + /// + /// The bottom. + /// + public double Bottom + { + get + { + return bottom; + } + set + { + bottom = value; + } + } + + /// + /// Gets all points on the Left boundary. + /// + /// + private List GetLeftPoints() + { + var geometryPoints = pointDataList.Where(gp => Math.Abs(gp.X - Left) < GeometryConstants.Accuracy).ToList(); + return geometryPoints; + } + + /// + /// Gets all points on the Right boundary. + /// + /// + private List GetRightPoints() + { + var geometryPoints = pointDataList.Where(point => Math.Abs(point.X - Right) < GeometryConstants.Accuracy).ToList(); + return geometryPoints; + } + + /// + /// Gets the geometry bounds. + /// + /// + public override GeometryBounds GetGeometryBounds() + { + return new GeometryBounds(Left, Right, Bottom, + Bottom + Math.Min(Right - Left, 20)); + } + + #endregion + + #region Functions + + #region create functions + + /// + /// Adjust the Geometry Bottom, Left and Right properties to the currently contained surfaces + /// + public void Rebox() + { + double xMin = double.MaxValue; + double xMax = double.MinValue; + double zMin = double.MaxValue; + double zMax = double.MinValue; + + foreach (var point in pointDataList) + { + xMin = Math.Min(point.X, xMin); + xMax = Math.Max(point.X, xMax); + zMin = Math.Min(point.Z, zMin); + zMax = Math.Max(point.Z, zMax); + } + bottom = zMin; + left = xMin; + right = xMax; + } + + #endregion + + #region remove functions + + /// + /// deletes all the Loop from IGeometryLoop. + /// + private void DeleteAllLoops() + { + Loops.Clear(); + } + + #endregion + + #region other functions + + #region calculation function + + /// + /// CheckIfIntersectStricktly + /// Determines if two lines intersect each other stricktly (so no extrapolated points). + /// + /// Line 1 GeometryPoint 1 + /// Line 1 GeometryPoint 2 + /// Line 2 GeometryPoint 1 + /// Line 2 GeometryPoint 2 + /// Intersection coordinates + /// True if lines intersect each other + private static bool CheckIfIntersectStricktly(Point2D beginPoint1, Point2D endPoint1, + Point2D beginPoint2, Point2D endPoint2, + ref Point2D intersect) + { + Point2D ip; + var res = Routines2D.DetermineIf2DLinesIntersectStrickly(beginPoint1.X, beginPoint1.Z, endPoint1.X, endPoint1.Z, beginPoint2.X, + beginPoint2.Z, endPoint2.X, endPoint2.Z, out ip); + if (ip != null) + { + intersect = ip; + } + return res == LineIntersection.Intersects; + } + + /// + /// CheckIfIntersectStricktly + /// Determines if two lines intersect each other stricktly (so no extrapolated points). + /// + /// Line 1 GeometryPoint 1 + /// Line 1 GeometryPoint 2 + /// Line 2 GeometryPoint 1 + /// Line 2 GeometryPoint 2 + /// Intersection coordinates + /// True if lines intersect each other + public static bool CheckIfIntersect(double[] aL1P1, double[] aL1P2, double[] aL2P1, double[] aL2P2, + ref double[] aIntersect) + { + var p1 = new Point2D(aL1P1[0], aL1P1[1]); + var p2 = new Point2D(aL1P2[0], aL1P2[1]); + var p3 = new Point2D(aL2P1[0], aL2P1[1]); + var p4 = new Point2D(aL2P2[0], aL2P2[1]); + var ip = new Point2D(); + var res = CheckIfIntersectStricktly(p1, p2, p3, p4, ref ip); + if (res) + { + aIntersect[0] = ip.X; + aIntersect[1] = ip.Z; + } + return res; + } + + /// + /// Gets the height of the surface(s) intersected at the given x. + /// + /// The x. + /// + public double GetSurfaceHeight(double x) + { + double surfaceHeight = -Double.MaxValue; + double[] intersectionPoints = IntersectLayers(x, -9999); + for (int i = 0; i < intersectionPoints.Length; i++) + { + if (intersectionPoints[i] > surfaceHeight) + { + surfaceHeight = intersectionPoints[i]; + } + } + + return surfaceHeight; + } + + /// + /// All the Intersection of layers in respect with a given vertical are detemined here. + /// + /// Startingpoint of the Vertical (X) + /// Startingpoint of the Vertical (Y) + /// List of Z intersection coordinates + private double[] IntersectLayers(double aXCoord, double aZCoord) + { + if (Surfaces == null) + { + throw new Exception("Empty Surfaces in IntersectLayers"); + } + + var beginPoint2 = new Point2D() + { + X = aXCoord, Z = aZCoord + }; + + var endPoint2 = new Point2D() + { + X = aXCoord, Z = 99999 + }; + + var referencePoint = new Point2D(); + + var intersections = new List(); + + for (int surfaceIndexLocal = 0; surfaceIndexLocal < Surfaces.Count; surfaceIndexLocal++) + { + var outerLoopCurveList = Surfaces[surfaceIndexLocal].OuterLoop.CurveList; + for (int curveIndexLocal = 0; curveIndexLocal < outerLoopCurveList.Count; curveIndexLocal++) + { + //Check for each curve if it intersects with x coordinate + Point2D beginPoint1 = outerLoopCurveList[curveIndexLocal].GetHeadPoint(CurveDirection.Forward); + Point2D endPoint1 = outerLoopCurveList[curveIndexLocal].GetEndPoint(CurveDirection.Forward); + + if (Math.Max(beginPoint1.X, endPoint1.X) >= aXCoord && + Math.Min(beginPoint1.X, endPoint1.X) <= aXCoord) + { + if (CheckIfIntersectStricktly(beginPoint1, endPoint1, beginPoint2, endPoint2, + ref referencePoint)) + { + if (referencePoint.Z > aZCoord && intersections.Contains(referencePoint.Z) == false) + { + intersections.Add(referencePoint.Z); + } + } + } + } + } + + return intersections.ToArray(); + } + + /// + /// Returns a list of boundary curves. These are curves which are used in only one surface so they have to be on a boundary (inner or outer) + /// + /// + private List GetBoundaryCurves() + { + var curves = new List(); + var loops = new List(); + foreach (var surface in Surfaces) + { + loops.Add(surface.OuterLoop); + // Todo Ask Rob/Tom: when a real "doughnut" type surface (so hole in the center) is permitted, adding the innerloops here will + // result in a wrong list of curves (because it will include the inner loop curves defining the hole) for its actual purpose: + // the determination of the surfaceline. When there is always a surface defined within the "dougnut" (so no real hole), + // this code will work and the innerloop must even be added to prevent finding internal boundaries. So this depends on the specs! + loops.AddRange(surface.InnerLoops); + } + + foreach (var loop in loops) + { + foreach (var curve in loop.CurveList) + { + if (curves.Contains(curve)) + { + // Second appearance, remove + curves.Remove(curve); + } + else + { + curves.Add(curve); + } + } + } + return curves; + } + + #endregion + + + #endregion + + #endregion + + /// + /// Ordered list of all geometry points at the surface + /// + public virtual GeometryPointString SurfaceLine + { + get + { + if (surfaceLine.CalcPoints.Count == 0 && pointDataList.Count > 0) + { + UpdateSurfaceLine(); + } + return surfaceLine; + } + } + + /// + /// Checks geometry for loose curves and AutoRegeneration + /// + /// + [Validate] + public ValidationResult[] ValidateGeometry() + { + var validationList = new List(); + { + foreach (var point in Points) + { + foreach (var point1 in Points) + { + if (point != point1) + { + bool isValidated = false; + foreach (var validatedItem in validationList) + { + if (validatedItem.Subject == point) + { + isValidated = true; + } + } + if (!isValidated) + { + if (Math.Abs(point.X - point1.X) < GeometryConstants.Accuracy && + Math.Abs(point.Z - point1.Z) < GeometryConstants.Accuracy) + { + validationList.Add(new ValidationResult(ValidationResultType.Error, + point + " and " + + point1 + " values are same.", + point1, sameStartAndEndPointRepairerPropertyName, + sameStartAndEndPointRepairerId)); + } + } + } + } + } + } + if (Surfaces.Count < 1) + { + validationList.Add(new ValidationResult(ValidationResultType.Error, "No soil surface available.", + this, noSoilRepairerPropertyName, noSoilRepairerId)); + } + return validationList.ToArray(); + } + + /// + /// Updates the line at the top of the geometry + /// + private void UpdateSurfaceLine() + { + if (updatingSurfaceLine) + { + return; + } + + updatingSurfaceLine = true; + + var bCurves = GetBoundaryCurves(); + if (bCurves.Count == 0) + { + surfaceLine.CalcPoints.Clear(); + } + var curvesCopy = GetCurvesCopy(bCurves); + var curves = GetTopCurves(curvesCopy); + CreateSurfaceLinePointString(curves); + + updatingSurfaceLine = false; + } + + /// + /// Removes the boundary curves from the given list of curves. + /// The boundaries themselves are determined from the given geometry + /// + /// The curves. + /// The geometry (as string). + private static void RemoveBoundaryCurves(List curves, GeometryPointString geometry) + { + var minX = geometry.GetMinX(); + var maxX = geometry.GetMaxX(); + var minZ = geometry.GetMinZ(); + foreach (var curve in curves.ToArray()) + { + if (IsBoundaryCurve(curve, minX, maxX, minZ)) + { + curves.Remove(curve); + } + } + } + + /// + /// get all geometrypoints from all geometrycurves + /// + /// + /// + private static GeometryPointString GetAllPointsFromCurveList(List curveList) + { + var result = new GeometryPointString(); + foreach (var curve in curveList) + { + result.CalcPoints.Add(curve.EndPoint); + result.CalcPoints.Add(curve.HeadPoint); + } + return result; + } + + /// + /// Gets next connected top curve in list of curves + /// + /// + /// + /// + /// + private GeometryCurve GetNextTopCurve(GeometryCurve curve, List boundaryCurves, + List excludedCurves) + { + // if current curve ends on right limit then that must have been the last one so stop the search + if (Math.Abs(curve.HeadPoint.X - Right) < GeometryConstants.Accuracy || Math.Abs(curve.EndPoint.X - Right) < GeometryConstants.Accuracy) + { + return null; + } + foreach (var geometryCurve in boundaryCurves) + { + if (geometryCurve != curve && !excludedCurves.Contains(geometryCurve)) + { + if (AreConnected(curve, geometryCurve)) + { + return geometryCurve; + } + } + } + return null; + } + + /// + /// Returns a that represents this instance. + /// + /// + /// A that represents this instance. + /// + public override string ToString() + { + return LocalizationManager.GetTranslatedText(this, "GeometryData"); + } + + /// + /// Synchronizes the loops. + /// + public void SynchronizeLoops() + { + DeleteAllLoops(); + foreach (var surface in Surfaces) + { + // #Bka: as real donuts (or holes in geom) are not allowed, there can be no innerloop that + // is NOT an outerloop for another surface. So no need to sync innerloops. + if (surface.OuterLoop != null && surface.OuterLoop.IsLoop()) + { + loopDataList.Add(surface.OuterLoop); + } + } + } + + /// + /// create a copy of the curves + /// + /// + /// + private List GetCurvesCopy(List bCurves) + { + var outerloopCurvesCopy = new List(bCurves); + return outerloopCurvesCopy; + } + + /// + /// Create a surface line from points in curves + /// Precondition is that the curves start at the left boundary and are connected left to right + /// (not neccesarily neat head-end) + /// + /// + /// + private void CreateSurfaceLinePointString(List curves) + { + surfaceLine.CalcPoints.Clear(); + + if (curves.Count == 0) + { + return; + } + + var reversed = false; + // The headpoint of the first curve must be on the left boundary otherwise the + // surface line will be in the wrong order. So make sure. + if (!(Math.Abs(curves[0].HeadPoint.X - Left) < GeometryConstants.Accuracy)) + { + curves[0].Reverse(); + reversed = true; + } + + foreach (var curve in curves) + { + if (!surfaceLine.CalcPoints.Contains(curve.HeadPoint)) + { + surfaceLine.CalcPoints.Add(curve.HeadPoint); + } + if (!surfaceLine.CalcPoints.Contains(curve.EndPoint)) + { + surfaceLine.CalcPoints.Add(curve.EndPoint); + } + } + + if (reversed) + { + curves[0].Reverse(); + } + } + + /// + /// get curves of the top side of the outerloop, vertical curves are omitted + /// + /// + /// + private List GetTopCurves(List curves) + { + GeometryCurve topCurve; + // Remove all curves on the geometry boundary + if (GetLeftPoints().Count > 0 && GetRightPoints().Count > 0) + { + foreach (var curve in curves.ToArray()) + { + if (IsBoundaryCurve(curve, Left, Right, Bottom)) + { + curves.Remove(curve); + } + } + // Make sure you start with topcurve = curve at the left top position + topCurve = curves.Where(g => Math.Abs(g.HeadPoint.X - Left) < GeometryConstants.Accuracy || + Math.Abs(g.EndPoint.X - Left) < GeometryConstants.Accuracy) + .OrderByDescending(c => c.HeadPoint.Z) + .FirstOrDefault(); + } + else + { + GeometryPointString gString = GetAllPointsFromCurveList(curves); + RemoveBoundaryCurves(curves, gString); + var minX = gString.GetMinX(); + // Make sure you start with topcurve = curve at the left top position + topCurve = + curves.Where(g => Math.Abs(g.HeadPoint.X - minX) < GeometryConstants.Accuracy || + Math.Abs(g.EndPoint.X - minX) < GeometryConstants.Accuracy).OrderByDescending(c => c.HeadPoint.Z).FirstOrDefault(); + } + var topCurvesLocal = new List(); + while (topCurve != null) + { + topCurvesLocal.Add(topCurve); + topCurve = GetNextTopCurve(topCurve, curves, topCurvesLocal); + } + + return topCurvesLocal; + } + + /// + /// Indicates whether a curve is on the boundary of the geometry + /// + /// + /// + /// + /// + /// + private static bool IsBoundaryCurve(GeometryCurve curve, double minX, double maxX, double minZ) + { + if (Math.Abs(curve.HeadPoint.X - minX) < GeometryConstants.Accuracy && Math.Abs(curve.EndPoint.X - minX) < GeometryConstants.Accuracy) + { + return true; + } + + if (Math.Abs(curve.HeadPoint.X - maxX) < GeometryConstants.Accuracy && Math.Abs(curve.EndPoint.X - maxX) < GeometryConstants.Accuracy) + { + return true; + } + + if (Math.Abs(curve.HeadPoint.Z - minZ) < GeometryConstants.Accuracy && Math.Abs(curve.EndPoint.Z - minZ) < GeometryConstants.Accuracy) + { + return true; + } + + return false; + } + + private bool AreConnected(GeometryCurve curve1, GeometryCurve curve2) + { + return (curve1.HeadPoint == curve2.HeadPoint || curve1.HeadPoint == curve2.EndPoint || + curve1.EndPoint == curve2.HeadPoint || curve1.EndPoint == curve2.EndPoint); + } + } +} \ No newline at end of file Index: dam engine/branches/Initial Source/Deltares.DamEngine.Data/Geotechnics/SoilLayer2D.cs =================================================================== diff -u --- dam engine/branches/Initial Source/Deltares.DamEngine.Data/Geotechnics/SoilLayer2D.cs (revision 0) +++ dam engine/branches/Initial Source/Deltares.DamEngine.Data/Geotechnics/SoilLayer2D.cs (revision 282) @@ -0,0 +1,77 @@ +// Copyright (C) Stichting Deltares 2017. All rights reserved. +// +// This file is part of the Macro Stability kernel. +// +// The Macro Stability kernel is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero 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 Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero 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 Deltares.DamEngine.Data.Geometry; +using Deltares.DamEngine.Data.Standard.Language; + +namespace Deltares.DamEngine.Data.Geotechnics +{ + /// + /// 2D Soil Layer Object + /// + [Serializable] + public class SoilLayer2D : SoilLayer + { + // 2 associated objects + private GeometrySurface geometrySurface; + + /// + /// Gets and sets the GeometrySurface + /// + public GeometrySurface GeometrySurface + { + get + { + return geometrySurface; + } + set + { + geometrySurface = value; + } + } + + /// + /// Gets or sets the name. + /// + /// + /// The name. + /// + public override string Name + { + get + { + return Soil != null ? Soil.Name : LocalizationManager.GetTranslatedText(this, "NoSoilAssigned"); + } + set{} // ignore + } + + /// + /// Gets the geometry bounds. + /// + /// the geometry bounds + public override GeometryBounds GetGeometryBounds() + { + return GeometrySurface == null ? + base.GetGeometryBounds() : GeometrySurface.GetGeometryBounds(); + } + } +} \ No newline at end of file Index: dam engine/branches/Initial Source/Deltares.DamEngine.Data/General/NWO/NonWaterRetainingObject.cs =================================================================== diff -u --- dam engine/branches/Initial Source/Deltares.DamEngine.Data/General/NWO/NonWaterRetainingObject.cs (revision 0) +++ dam engine/branches/Initial Source/Deltares.DamEngine.Data/General/NWO/NonWaterRetainingObject.cs (revision 282) @@ -0,0 +1,147 @@ +//----------------------------------------------------------------------- +// +// Copyright (c) 2011 Deltares. All rights reserved. +// +// J. Bokma +// john.bokma@deltares.nl +// 13-10-2011 +// n.a. +//----------------------------------------------------------------------- + +using System; +using Deltares.DamEngine.Data.Geometry; + +namespace Deltares.DamEngine.Data.General.NWO +{ + + public class NonWaterRetainingObjectException : ApplicationException + { + public NonWaterRetainingObjectException(string message) + : base(message) + { + } + } + + public class NonWaterRetainingObject + { + public virtual string NwoId { get; set; } + public virtual NonWaterRetainingObjectCategory Category { get; set; } + public virtual NonWaterRetainingObjectType Type { get; set; } + public virtual PhreaticAdaptionType PhreaticAdaption { get; set; } + public virtual double H1 { get; set; } + public virtual double H2 { get; set; } + public virtual double N1 { get; set; } + public virtual double N2 { get; set; } + public virtual double B { get; set; } + public virtual double StepSizeX { get; set; } + public virtual double MaxDistanceFromToe { get; set; } + + public double Btotal () + { + double bTotal = (H1 * N1) + (Math.Sqrt((B*B - (Math.Pow(H2-H1, 2))))) + (H2 * N2); + return bTotal; + } + + public GeometryPoint Point1 { get; set; } + public GeometryPoint Point2 { get; set; } + public GeometryPoint Point3 { get; set; } + public GeometryPoint Point4 { get; set; } + + /// + /// + /// + /// + public void GetDefaultValuesPerTreeType(NonWaterRetainingObjectType type) + { + + switch (type) + { + case NonWaterRetainingObjectType.Oak: + H1 = 2; + H2 = 2; + N1 = 2; + N2 = 2; + B = 2; + break; + case NonWaterRetainingObjectType.Alder: + H1 = 2; + H2 = 2; + N1 = 2; + N2 = 2; + B = 2; + break; + case NonWaterRetainingObjectType.Poplar: + H1 = 2; + H2 = 2; + N1 = 2; + N2 = 2; + B = 2; + break; + default: + H1 = 2; + H2 = 2; + N1 = 2; + N2 = 2; + B = 2; + break; + } + } + + /// + /// + /// + /// + public void GetDefaultValuesPerMainType(NonWaterRetainingObjectType type) + { + + switch (type) + { + case NonWaterRetainingObjectType.GasMain: + H1 = 2; + H2 = 2; + N1 = 2; + N2 = 2; + B = 2; + break; + case NonWaterRetainingObjectType.WaterMain: + H1 = 2; + H2 = 2; + N1 = 2; + N2 = 2; + B = 2; + break; + default: + H1 = 2; + H2 = 2; + N1 = 2; + N2 = 2; + B = 2; + break; + } + } + + /// + /// + /// + /// + /// + public void GetDefaultValuesPerCategoryAndType(NonWaterRetainingObjectCategory category, NonWaterRetainingObjectType type) + { + switch (category) + { + case NonWaterRetainingObjectCategory.Tree: GetDefaultValuesPerTreeType(type); + break; + case NonWaterRetainingObjectCategory.Main: GetDefaultValuesPerMainType(type); + break; + } + } + + public void Validate() + { + if (Btotal() <= 0) + throw new NonWaterRetainingObjectException("NonWaterReatiningObject is invalid. Its total width is smaller than or equal to 0."); + if (MaxDistanceFromToe <= Btotal()) + throw new NonWaterRetainingObjectException("NonWaterReatiningObject is invalid. The required maximum distance from toe is smaller than or equal to the total width."); + } + } +} Index: dam engine/branches/Initial Source/Deltares.DamEngine.Data/General/Sensors/Group.cs =================================================================== diff -u --- dam engine/branches/Initial Source/Deltares.DamEngine.Data/General/Sensors/Group.cs (revision 0) +++ dam engine/branches/Initial Source/Deltares.DamEngine.Data/General/Sensors/Group.cs (revision 282) @@ -0,0 +1,224 @@ +//----------------------------------------------------------------------- +// +// Copyright (c) 2009 Deltares. All rights reserved. +// +// B. Faassen +// barry.faassen@deltares.nl +// 1-8-2012 +// n.a. +//----------------------------------------------------------------------- + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Xml.Serialization; +using Deltares.DamEngine.Data.Standard.Validation; + +namespace Deltares.DamEngine.Data.General.Sensors +{ + public class Group + { + /// + /// Holds a reference to the set of selected sensors + /// + private readonly HashSet sensors; + private List pickSensors; + private int id; + + /// + /// Holds a reference to a set of relative loctions along the profile + /// + private readonly IDictionary relativeLocationAlongProfileDictionary; + + public Group() + { + sensors = new HashSet(); + relativeLocationAlongProfileDictionary = new Dictionary(); + ID = -1; + } + + /// + /// Gets or sets the ID. + /// + /// + /// The ID value should be unique. + /// + public int ID + { + get { return id; } + set + { + id = value; + } + } + + /// + /// Gets the selected sensors. + /// + [XmlIgnore] + public IEnumerable Selection + { + get { return sensors; } + } + + /// + /// Gets or sets the selection as list for UI (table) purposes. + /// + /// + /// The selection as list. + /// + [XmlIgnore] + public string SelectionAsString + { + get + { + string res = ""; + foreach (var sensor in sensors) + { + res = res + sensor.ID + "; "; + } + return res; + } + set + { + ClearSelection(); + var locSensors = ParseStringToSensorIDs(value); + if (pickSensors != null) + { + foreach (var sensorID in locSensors) + { + var sensor = PickSensors.Find(x => x.ID == sensorID); + if (sensor != null) + { + Add(sensor); + } + } + } + } + } + + private List ParseStringToSensorIDs(string value) + { + value = value.Trim(); + var ids = new List(); + var idsarr = value.Split(new Char [] {';'}, StringSplitOptions.RemoveEmptyEntries); + foreach (var s in idsarr) + { + try + { + var val = Int32.Parse(s); + ids.Add(val); + } + catch (Exception) + { + // surpress errors, just do not use value + } + } + return ids; + } + + /// + /// Persistable sensor array. Only for internal use + /// + public Sensor[] SensorArray + { + get { return sensors.ToArray(); } + set { + ClearSelection(); + foreach (var sensor in value) + { + Add(sensor); + } + } + } + + /// + /// Gets the sensor count. + /// + public int SensorCount + { + get { return sensors.Count; } + } + + [XmlIgnore] + public IEnumerable> SensorRelativeLocations + { + get { return relativeLocationAlongProfileDictionary; } + } + + [XmlIgnore] + public List PickSensors + { + get { return pickSensors; } + set { pickSensors = value; } + } + + /// + /// Determines whether this instance is valid. + /// + /// + public bool IsValid() + { + IEnumerable validationResults = Validator.Validate(this); + return !validationResults.Any(); + } + + /// + /// Determines whether this instance is transient (associated with an invalid ID). + /// + /// + /// true if this instance is transient; otherwise, false. + /// + public bool IsTransient() + { + return ID <= 0; + } + + /// + /// Sets the relative location. + /// + /// The sensor. + /// The value. + public void SetRelativeLocation(Sensor sensor, double value) + { + relativeLocationAlongProfileDictionary[sensor] = value; + } + + /// + /// Adds the specified sensor to the selected sensor list for this group. + /// + /// The sensor to add. + public void Add(Sensor sensor) + { + sensors.Add(sensor); + if (!relativeLocationAlongProfileDictionary.ContainsKey(sensor)) + relativeLocationAlongProfileDictionary.Add(sensor, 0); + + } + + /// + /// Removes the specified sensor from the selected sensor list from this group. + /// + /// The sensor to remove. + public void Remove(Sensor sensor) + { + sensors.Remove(sensor); + if (relativeLocationAlongProfileDictionary.ContainsKey(sensor)) + relativeLocationAlongProfileDictionary.Remove(sensor); + } + + /// + /// Clears the sensor selection + /// + public void ClearSelection() + { + sensors.Clear(); + relativeLocationAlongProfileDictionary.Clear(); + } + + public override string ToString() + { + return ID.ToString(); + } + } +} Index: dam engine/branches/Initial Source/Deltares.DamEngine.Data/General/Sensors/Sensor.cs =================================================================== diff -u --- dam engine/branches/Initial Source/Deltares.DamEngine.Data/General/Sensors/Sensor.cs (revision 0) +++ dam engine/branches/Initial Source/Deltares.DamEngine.Data/General/Sensors/Sensor.cs (revision 282) @@ -0,0 +1,323 @@ +//----------------------------------------------------------------------- +// +// Copyright (c) 2012 Deltares. All rights reserved. +// +// B. Faassen +// barry.faassen@deltares.nl +// 1-8-2012 +// n.a. +//----------------------------------------------------------------------- + +using System; +using System.Collections.Generic; +using System.Linq; +using Deltares.DamEngine.Data.Standard; + +namespace Deltares.DamEngine.Data.General.Sensors +{ + /// + /// This class represents a sensor or monitoring point used in dikes. + /// This entity is created for Dam Live + /// + public class Sensor : IName + { + #region Business Rules + + /// + /// Specication to test if the value of the candidate is valid + /// + internal class ContiansAtLeastOneItem : PredicateSpecification> + { + public ContiansAtLeastOneItem() + : base(x => x.Any()) + { + Description = "The sensor should contain at least one PL Line mapping."; + } + } + + #endregion + + private readonly IGeometry geometry; + private double relativeLocation; + private readonly HashSet plLineTypes; + private int id; + + public Sensor() + { + plLineTypes = new HashSet(); + ID = -1; + geometry = new Point(0,0,0); + } + + public Sensor(Point point) : this() + { + if (point == null) throw new ArgumentNullException("point"); + this.geometry = point; + + } + + public Sensor(double x, double y, double z) : this(new Point(x, y, z)) + { + } + + /// + /// Gets or sets the ID. + /// + /// + /// The ID should be unique. + /// + public int ID + { + get { return id; } + set + { + id = value; + } + } + + /// + /// Gets or sets the name of this sensor. + /// + /// + /// The name string value should not be empty and unique. + /// + [Specification(typeof(NotEmptySpecification))] + public string Name { get; set; } + + /// + /// Gets or sets the depth. + /// + /// + /// The depth. + /// + public double Depth + { + get { return ZRd; } + set + { + ZRd = value; + } + } + + /// + /// Gets or sets the relative location along the profile. + /// + /// + /// The relative location in meter. + /// + public double RelativeLocation + { + get { return relativeLocation; } + set + { + relativeLocation = value; + RelativeLocationSpecified = true; + } + } + + /// + /// Gets or sets the X rd. + /// + /// + /// The X rd. + /// + public double XRd + { + get { return geometry.Coordinate.X; } + set { geometry.Coordinate.X = value; } + } + + /// + /// Gets or sets the Y rd. + /// + /// + /// The Y rd. + /// + public double YRd + { + get { return geometry.Coordinate.Y; } + set { geometry.Coordinate.Y = value; } + } + + /// + /// Gets or sets the Z rd. Same as Depth?? + /// + /// + /// The Z rd. + /// + public double ZRd + { + get { return geometry.Coordinate.Z; } + set { geometry.Coordinate.Z = value; } + } + + /// + /// Gets a value indicating whether the relative location is specified. + /// + /// + /// true if the relative location is specified; otherwise, false. + /// + public bool RelativeLocationSpecified { get; private set; } + + private SensorType type; + + /// + /// Gets or sets the type of this sensor. + /// + /// + /// The type. Default value is PiezoMetricHead. + /// + public SensorType Type + { + get { return type; } + set { type = value; } + } + + /// + /// Gets or sets the PL line array. Used for serialization only. + /// + /// + /// The PL line array. + /// + [Specification(typeof(NotNullSpecification))] + [Specification(typeof(ContiansAtLeastOneItem))] + public PLLineType[] PLLineMappings + { + get { return plLineTypes.ToArray(); } + set + { + ClearPLLines(); + foreach (var lineType in value) + { + Add(lineType); + } + } + } + + public string PLLineMappingsAsString + { + get + { + string res = ""; + foreach (var plLineType in plLineTypes) + { + switch (plLineType) + { + case PLLineType.PL1: res = res + "1; "; break; + case PLLineType.PL2: res = res + "2; "; break; + case PLLineType.PL3: res = res + "3; "; break; + case PLLineType.PL4: res = res + "4; "; break; + } + } + return res; + } + set + { + ClearPLLines(); + var locPlLineTypes = ParseStringToPlLineTypes(value); + foreach (var plLineType in locPlLineTypes) + { + switch (plLineType) + { + case 1: plLineTypes.Add(PLLineType.PL1); break; + case 2: plLineTypes.Add(PLLineType.PL2); break; + case 3: plLineTypes.Add(PLLineType.PL3); break; + case 4: plLineTypes.Add(PLLineType.PL4); break; + } + } + } + } + + private List ParseStringToPlLineTypes(string value) + { + value = value.Trim(); + var ids = new List(); + var idsarr = value.Split(new Char[] { ';' }, StringSplitOptions.RemoveEmptyEntries); + foreach (var s in idsarr) + { + try + { + var val = Int32.Parse(s); + ids.Add(val); + } + catch (Exception) + { + // surpress errors, just do not use value + } + } + return ids; + } + + /// + /// Adds the specified PL line. + /// + /// The PL line. + public void Add(PLLineType plLine) + { + plLineTypes.Add(plLine); + } + + /// + /// Removes the specified PL line. + /// + /// The PL line. + public void Remove(PLLineType plLine) + { + plLineTypes.Remove(plLine); + } + + /// + /// Clears the PL lines list. + /// + public void ClearPLLines() + { + plLineTypes.Clear(); + } + + /// + /// Determines whether this instance is valid. + /// + /// + /// true if this instance is valid; otherwise, false. + /// + public bool IsValid() + { + return !Validator.Validate(this).Any(); + } + + /// + /// Determines whether this instance is transient (associated with a correct ID in the context of the repository). + /// + /// + /// true if this instance is transient; otherwise, false. + /// + public bool IsTransient() + { + return ID < 0; + } + + public override string ToString() + { + var name = string.IsNullOrWhiteSpace(Name) ? "name_not_set" : Name; + + return string.Format("[ID: {0}, Name: {1}, Depth: {2}, Type: {3}, RelativeLocation: {4}]", + ID, name, Depth, Type, RelativeLocation); + } + + public bool IsVisible(string property) + { + switch (property) + { + case "XRd": return false; + case "YRd": return false; + case "ZRd": return false; + default: return true; + } + } + + public bool IsEnabled(string property) + { + return true; + } + } +} Index: dam engine/branches/Initial Source/Deltares.DamEngine.Data/Geotechnics/SoilList.cs =================================================================== diff -u --- dam engine/branches/Initial Source/Deltares.DamEngine.Data/Geotechnics/SoilList.cs (revision 0) +++ dam engine/branches/Initial Source/Deltares.DamEngine.Data/Geotechnics/SoilList.cs (revision 282) @@ -0,0 +1,138 @@ +// Copyright (C) Stichting Deltares 2017. All rights reserved. +// +// This file is part of the Delta Shell Light Library. +// +// The Delta Shell Light Library 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 Deltares.DamEngine.Data.Standard.Validation; + +namespace Deltares.DamEngine.Data.Geotechnics +{ + /// + /// Holds the soils and provides some handy methods for them + /// + public class SoilList + { + private Dictionary aquiferDictionary = new Dictionary(); + private List soils; + + public SoilList() + { + soils = new List(); + } + + /// + /// Gets or sets the soils. + /// + /// + /// The soils. + /// + [Validate] + public virtual List Soils + { + get + { + return soils; + } + set + { + soils = value; + } + } + + /// + /// Gets or sets the aquifer dictionary. + /// This dictionary is used for the backward compatibility issue when aquifers still were part of + /// soil instead of the layer as it is now. + /// + /// + /// The aquifer dictionary. + /// + public Dictionary AquiferDictionary + { + get + { + return aquiferDictionary; + } + set + { + aquiferDictionary = value; + } + } + + /// + /// Gets the index of the soil by its name. + /// + /// Name of the soil. + /// The index when found else -1 + public virtual int GetSoilIndexByName(string soilName) + { + var soil = soils.FirstOrDefault(s => s.Name.Equals( + soilName, StringComparison.InvariantCultureIgnoreCase)); + + return soil == null ? -1 : soils.IndexOf(soil); + } + + /// + /// Gets the soil by its name. + /// + /// Name of the soil. + /// Soil when found else null + public virtual Soil GetSoilByName(string soilName) + { + var soil = soils.FirstOrDefault(s => s.Name.Equals( + soilName, StringComparison.InvariantCultureIgnoreCase)); + + return soil; + } + + /// + /// Adds the specified soil. + /// + /// The soil. + public void Add(Soil soil) + { + Soils.Add(soil); + } + + /// + /// Removes the specified soil. + /// + /// The soil. + public void Remove(Soil soil) + { + Soils.Remove(soil); + if (aquiferDictionary.ContainsKey(soil)) + { + aquiferDictionary.Remove(soil); + } + } + + /// + /// Clears this instance (soils and AquiferDictionary). + /// + public void Clear() + { + Soils.Clear(); + aquiferDictionary.Clear(); + } + } +} \ No newline at end of file Index: dam engine/branches/Initial Source/Deltares.DamEngine.Data/Geotechnics/SoilTypes.cs =================================================================== diff -u --- dam engine/branches/Initial Source/Deltares.DamEngine.Data/Geotechnics/SoilTypes.cs (revision 0) +++ dam engine/branches/Initial Source/Deltares.DamEngine.Data/Geotechnics/SoilTypes.cs (revision 282) @@ -0,0 +1,35 @@ +// Copyright (C) Stichting Deltares 2017. All rights reserved. +// +// This file is part of the Delta Shell Light Library. +// +// The Delta Shell Light Library 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. + +namespace Deltares.DamEngine.Data.Geotechnics +{ + /// + /// Enumerator for commonly used major soil types (Sand, Peat, Loam, Clay, Gravel) + /// + public enum SoilType + { + Sand, + Peat, + Loam, + Clay, + Gravel + } +} \ No newline at end of file Index: dam engine/branches/Initial Source/Deltares.DamEngine.Data/Geometry/GeometrySurface.cs =================================================================== diff -u --- dam engine/branches/Initial Source/Deltares.DamEngine.Data/Geometry/GeometrySurface.cs (revision 0) +++ dam engine/branches/Initial Source/Deltares.DamEngine.Data/Geometry/GeometrySurface.cs (revision 282) @@ -0,0 +1,185 @@ +// Copyright (C) Stichting Deltares 2017. All rights reserved. +// +// This file is part of the Macro Stability kernel. +// +// The Macro Stability kernel is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero 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 Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero 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; + +namespace Deltares.DamEngine.Data.Geometry +{ + /// + /// Class for geometry surfaces. + /// + /// + [Serializable] + public class GeometrySurface : GeometryObject + { + private readonly List innerLoops = new List(); + private GeometryLoop outerLoop = new GeometryLoop(); + + /// + /// Empty constructor + /// + public GeometrySurface() { } + + /// + /// Initializes a new instance of the class. + /// + /// The loop. + public GeometrySurface(GeometryLoop loop) + { + outerLoop = loop; + } + + /// + /// The circumference of the surface. + /// + public GeometryLoop OuterLoop + { + get + { + return outerLoop; + } + set + { + outerLoop = value; + } + } + + /// + /// All internal loops encompassed by . + /// + public List InnerLoops + { + get + { + return innerLoops; + } + } + + /// + /// determine top of geometry surface outerloop as GeometryPointString + /// + /// + public GeometryPointString DetermineTopGeometrySurface() + { + return DetermineTopCurves(); + } + + /// + /// determine bottom of geometry surface outerloop as GeometryPointString + /// + /// + public GeometryPointString DetermineBottomGeometrySurface() + { + return DetermineBottomCurves(); + } + + /// + /// Gets the geometry bounds. + /// + /// + public override GeometryBounds GetGeometryBounds() + { + return OuterLoop.GetGeometryBounds(); + } + + /// + /// Determine points at the top side of the geometry surface + /// + /// + private GeometryPointString DetermineTopCurves() + { + //TODO: Lot of similar code to DetermineBottomCurves; Refactoring recommended. + var minXPoints = OuterLoop.GetPointsAtX(OuterLoop.GetMinX()); + var maxXPoints = OuterLoop.GetPointsAtX(OuterLoop.GetMaxX()); + + //verticals at start are omitted + Point2D startTopPoint = minXPoints.OrderByDescending(p => p.Z).First(); + + //verticals at end are omitted + Point2D endTopPoint = maxXPoints.OrderByDescending(p => p.Z).First(); + + var topPoints = new GeometryPointString(); + + int currentIndex = OuterLoop.CalcPoints.IndexOf(startTopPoint); + + while (!topPoints.CalcPoints.Contains(endTopPoint)) + { + topPoints.CalcPoints.Add(OuterLoop.CalcPoints[currentIndex++]); + if (currentIndex >= OuterLoop.CalcPoints.Count) + { + currentIndex = 0; + } + } + + // Replace the points by clones + for (int i = 0; i < topPoints.CalcPoints.Count; i++) + { + topPoints.CalcPoints[i] = new Point2D(topPoints.CalcPoints[i].X, topPoints.CalcPoints[i].Z); + } + + return topPoints; + } + + /// + /// determine curves at the bottom side of the geometry surface + /// + /// + private GeometryPointString DetermineBottomCurves() + { + //TODO: Lot of similar code to DetermineTopCurves; Refactoring recommended. + //create copy, leave original + var minXPoints = OuterLoop.GetPointsAtX(OuterLoop.GetMinX()); + var maxXPoints = OuterLoop.GetPointsAtX(OuterLoop.GetMaxX()); + + //verticals at start are omitted + var startBottomPoint = minXPoints.OrderBy(p => p.Z).First(); + + //verticals at end are omitted + var endBottomPoint = maxXPoints.OrderBy(p => p.Z).First(); + + var bottomPoints = new GeometryPointString(); + + int currentIndex = OuterLoop.CalcPoints.IndexOf(endBottomPoint); + + while (!bottomPoints.CalcPoints.Contains(startBottomPoint)) + { + bottomPoints.CalcPoints.Add(OuterLoop.CalcPoints[currentIndex++]); + if (currentIndex >= OuterLoop.CalcPoints.Count) + { + currentIndex = 0; + } + } + + // Replace the points by clones + for (int i = 0; i < bottomPoints.CalcPoints.Count; i++) + { + bottomPoints.CalcPoints[i] = new Point2D(bottomPoints.CalcPoints[i].X, bottomPoints.CalcPoints[i].Z); + } + + // As the curves are sorted clockwise, the bottomcurves are always orientated from right to left + // while this result of this method must be from left to right so reverse the curves + bottomPoints.CalcPoints.Reverse(); + return bottomPoints; + } + } +} \ No newline at end of file Index: dam engine/branches/Initial Source/Deltares.DamEngine.Data/Standard/ComputeDoubles.cs =================================================================== diff -u --- dam engine/branches/Initial Source/Deltares.DamEngine.Data/Standard/ComputeDoubles.cs (revision 0) +++ dam engine/branches/Initial Source/Deltares.DamEngine.Data/Standard/ComputeDoubles.cs (revision 282) @@ -0,0 +1,100 @@ +// Copyright (C) Stichting Deltares 2017. All rights reserved. +// +// This file is part of the Macro Stability kernel. +// +// The Macro Stability kernel is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero 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 Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero 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; + +namespace Deltares.DamEngine.Data.Standard +{ + /// + /// Static helper class ComputeDoubles with static helper methods + /// + public static class ComputeDoubles + { + private const double cEpsilon = 1.0e-3; + + /// + /// Determines whether two values are nearly the same. + /// + /// Uses a tolerance of 1e-3. + public static bool IsNearEqual(this double aValue1, double aValue2) + { + return aValue1.IsNearEqual(aValue2, cEpsilon); + } + + /// + /// Determines whether the specified value is significantly greater than another value. + /// + /// Uses a tolerance of 1e-3. + private static bool IsGreaterThan(this double aValue1, double aValue2) + { + if (aValue1 - aValue2 > cEpsilon) + { + return true; + } + + return false; + } + + /// + /// Determines whether the specified value is nearly equal to or is greater than + /// another value. + /// + /// Uses a tolerance of 1e-3. + public static bool IsGreaterThanOrEqualTo(this double aValue1, double aValue2) + { + if (aValue1 - aValue2 > -cEpsilon) + { + return true; + } + + return false; + } + + /// + /// Determines whether a value is significantly less than another value. + /// + /// Uses a tolerance of 1e-3. + public static bool IsLessThan(this double aValue1, double aValue2) + { + return !IsGreaterThanOrEqualTo(aValue1, aValue2); + } + + /// + /// Determines whether a value is insignificantly greater than, is equal to or is + /// less than another value. + /// + /// Uses a tolerance of 1e-3. + public static bool IsLessThanOrEqualTo(this double aValue1, double aValue2) + { + return !IsGreaterThan(aValue1, aValue2); + } + + private static bool IsNearEqual(this double aValue1, double aValue2, double aTolerance) + { + if (Math.Abs(aValue1 - aValue2) < aTolerance) + { + return true; + } + + return false; + } + } +} \ No newline at end of file Index: dam engine/branches/Initial Source/Deltares.DamEngine.Data/Geotechnics/CharacteristicPointSet.cs =================================================================== diff -u -r278 -r282 --- dam engine/branches/Initial Source/Deltares.DamEngine.Data/Geotechnics/CharacteristicPointSet.cs (.../CharacteristicPointSet.cs) (revision 278) +++ dam engine/branches/Initial Source/Deltares.DamEngine.Data/Geotechnics/CharacteristicPointSet.cs (.../CharacteristicPointSet.cs) (revision 282) @@ -566,6 +566,6 @@ // Set new annotation definition: typeCache[item.CharacteristicPointType] = item.GeometryPoint; } - } + } } } \ No newline at end of file Index: dam engine/branches/Initial Source/Deltares.DamEngine.Data/Geotechnics/SurfaceLine2.cs =================================================================== diff -u -r278 -r282 --- dam engine/branches/Initial Source/Deltares.DamEngine.Data/Geotechnics/SurfaceLine2.cs (.../SurfaceLine2.cs) (revision 278) +++ dam engine/branches/Initial Source/Deltares.DamEngine.Data/Geotechnics/SurfaceLine2.cs (.../SurfaceLine2.cs) (revision 282) @@ -19,6 +19,7 @@ // 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 Deltares.DamEngine.Data.Geometry;