// Copyright (C) Stichting Deltares 2017. All rights reserved. // // This file is part of the Dam Engine. // // The Dam Engine 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]); } } } } }