// 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]);
}
}
}
}
}