// Copyright (C) Stichting Deltares 2017. All rights reserved.
//
// This file is part of Ringtoets.
//
// Ringtoets is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see .
//
// All names, logos, and references to "Deltares" are registered trademarks of
// Stichting Deltares and remain full property of Stichting Deltares at all times.
// All rights reserved.
using System;
using System.Collections.Generic;
using System.Linq;
using Core.Common.Base.Geometry;
using Ringtoets.Common.Data.AssessmentSection;
using Ringtoets.Common.IO.Properties;
namespace Ringtoets.Common.IO.SurfaceLines
{
///
/// Extension methods for the .
///
public static class SurfaceLineExtensions
{
///
/// The type of the intersection possible with a reference line.
///
public enum ReferenceLineIntersectionsResult
{
NoIntersections,
OneIntersection,
MultipleIntersectionsOrOverlap
}
///
/// Finds out if there is an intersection of the and
/// the .
///
/// The surface line.
/// The reference line.
/// A new with a type of intersection and
/// possibly an intersection point, if there was only one found.
/// Thrown when any parameter is null.
/// Thrown when the surface line:
///
/// - has no intersections with the reference line;
/// - has more than one intersection with the reference line.
///
///
public static Point2D GetSingleReferenceLineInterSection(this SurfaceLine surfaceLine, ReferenceLine referenceLine)
{
if (surfaceLine == null)
{
throw new ArgumentNullException(nameof(surfaceLine));
}
if (referenceLine == null)
{
throw new ArgumentNullException(nameof(referenceLine));
}
ReferenceLineIntersectionResult result = GetReferenceLineIntersections(referenceLine, surfaceLine);
if (result.TypeOfIntersection == ReferenceLineIntersectionsResult.NoIntersections)
{
string message = string.Format(Resources.SurfaceLineExtensions_GetSingleReferenceLineInterSection_SurfaceLine_0_does_not_correspond_to_current_referenceline_1_,
surfaceLine.Name,
Resources.SurfaceLineExtensions_GetSingleReferenceLineInterSection_This_could_be_caused_coordinates_being_local_coordinate_system);
throw new SurfaceLineTransformException(message);
}
if (result.TypeOfIntersection == ReferenceLineIntersectionsResult.MultipleIntersectionsOrOverlap)
{
string message = string.Format(Resources.SurfaceLineExtensions_GetSingleReferenceLineInterSection_SurfaceLine_0_does_not_correspond_to_current_referenceline, surfaceLine.Name);
throw new SurfaceLineTransformException(message);
}
return result.IntersectionPoint;
}
private static ReferenceLineIntersectionResult GetReferenceLineIntersections(ReferenceLine referenceLine, SurfaceLine surfaceLine)
{
IEnumerable surfaceLineSegments = Math2D.ConvertLinePointsToLineSegments(surfaceLine.Points.Select(p => new Point2D(p.X, p.Y)));
Segment2D[] referenceLineSegments = Math2D.ConvertLinePointsToLineSegments(referenceLine.Points).ToArray();
return GetReferenceLineIntersectionsResult(surfaceLineSegments, referenceLineSegments);
}
private static ReferenceLineIntersectionResult GetReferenceLineIntersectionsResult(IEnumerable surfaceLineSegments, Segment2D[] referenceLineSegments)
{
Point2D intersectionPoint = null;
foreach (Segment2D surfaceLineSegment in surfaceLineSegments)
{
foreach (Segment2D referenceLineSegment in referenceLineSegments)
{
Segment2DIntersectSegment2DResult result = Math2D.GetIntersectionBetweenSegments(surfaceLineSegment, referenceLineSegment);
if (result.IntersectionType == Intersection2DType.Intersects)
{
Point2D resultIntersectionPoint = result.IntersectionPoints[0];
if (intersectionPoint != null && !intersectionPoint.Equals(resultIntersectionPoint))
{
// Early exit as multiple intersections is a return result:
return ReferenceLineIntersectionResult.CreateMultipleIntersectionsOrOverlapResult();
}
intersectionPoint = resultIntersectionPoint;
}
if (result.IntersectionType == Intersection2DType.Overlaps)
{
// Early exit as overlap is a return result:
return ReferenceLineIntersectionResult.CreateMultipleIntersectionsOrOverlapResult();
}
}
}
return intersectionPoint != null
? ReferenceLineIntersectionResult.CreateIntersectionResult(intersectionPoint)
: ReferenceLineIntersectionResult.CreateNoSingleIntersectionResult();
}
///
/// Result of finding the intersections of a surface line and a reference line.
///
public class ReferenceLineIntersectionResult
{
private ReferenceLineIntersectionResult(ReferenceLineIntersectionsResult typeOfIntersection, Point2D intersectionPoint)
{
TypeOfIntersection = typeOfIntersection;
IntersectionPoint = intersectionPoint;
}
///
/// Gets the type of intersection that was found.
///
public ReferenceLineIntersectionsResult TypeOfIntersection { get; }
///
/// Gets the intersection point of the surface line and the reference line if
/// there was only one found; or null otherwise.
///
public Point2D IntersectionPoint { get; }
public static ReferenceLineIntersectionResult CreateNoSingleIntersectionResult()
{
return new ReferenceLineIntersectionResult(ReferenceLineIntersectionsResult.NoIntersections, null);
}
public static ReferenceLineIntersectionResult CreateIntersectionResult(Point2D point)
{
return new ReferenceLineIntersectionResult(ReferenceLineIntersectionsResult.OneIntersection, point);
}
public static ReferenceLineIntersectionResult CreateMultipleIntersectionsOrOverlapResult()
{
return new ReferenceLineIntersectionResult(ReferenceLineIntersectionsResult.MultipleIntersectionsOrOverlap, null);
}
}
}
}