// Copyright (C) Stichting Deltares 2016. All rights reserved.
//
// This file is part of Ringtoets.
//
// Ringtoets is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see .
//
// All names, logos, and references to "Deltares" are registered trademarks of
// Stichting Deltares and remain full property of Stichting Deltares at all times.
// All rights reserved.
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using Core.Common.Base.Data;
using Core.Common.Base.Geometry;
using Core.Common.Base.Storage;
using Ringtoets.Piping.Primitives.Exceptions;
using Ringtoets.Piping.Primitives.Properties;
namespace Ringtoets.Piping.Primitives
{
///
/// Definition of a surfaceline for piping.
///
public class RingtoetsPipingSurfaceLine : IStorable
{
private Point3D[] geometryPoints;
///
/// Initializes a new instance of the class.
///
public RingtoetsPipingSurfaceLine()
{
Name = string.Empty;
geometryPoints = new Point3D[0];
}
///
/// Gets or sets the name of the surfaceline.
///
public string Name { get; set; }
///
/// Gets the 3D points describing its geometry.
///
public Point3D[] Points
{
get
{
return geometryPoints;
}
}
///
/// Gets or sets the first 3D geometry point defining the surfaceline in world coordinates.
///
public Point3D StartingWorldPoint { get; private set; }
///
/// Gets or sets the last 3D geometry point defining the surfaceline in world coordinates.
///
public Point3D EndingWorldPoint { get; private set; }
///
/// Gets the point which characterizes the ditch at polder side.
///
public Point3D DitchPolderSide { get; private set; }
///
/// Gets the point which characterizes the bottom of the ditch at polder side.
///
public Point3D BottomDitchPolderSide { get; private set; }
///
/// Gets the point which characterizes the bottom of the ditch at dike side.
///
public Point3D BottomDitchDikeSide { get; private set; }
///
/// Gets the point which characterizes the ditch at dike side.
///
public Point3D DitchDikeSide { get; private set; }
///
/// Gets the point which characterizes the dike toe at river side.
///
public Point3D DikeToeAtRiver { get; private set; }
///
/// Gets the point which characterizes the dike toe at polder side.
///
public Point3D DikeToeAtPolder { get; private set; }
///
/// Gets or sets the reference line intersection point in world coordinates.
///
public Point2D ReferenceLineIntersectionWorldPoint { get; set; }
public long StorageId { get; set; }
///
/// Sets the geometry of the surfaceline.
///
/// The collection of points defining the surfaceline geometry.
/// Thrown when is null.
/// Thrown when any element of is null.
public void SetGeometry(IEnumerable points)
{
if (points == null)
{
throw new ArgumentNullException("points", Resources.RingtoetsPipingSurfaceLine_Collection_of_points_for_geometry_is_null);
}
if (points.Any(p => p == null))
{
throw new ArgumentException(Resources.RingtoetsPipingSurfaceLine_A_point_in_the_collection_was_null);
}
geometryPoints = points.ToArray();
if (geometryPoints.Length > 0)
{
StartingWorldPoint = geometryPoints[0];
EndingWorldPoint = geometryPoints[geometryPoints.Length - 1];
}
}
///
/// Sets the at the given point.
///
/// The location as a which to set as the .
/// Thrown when doesn't contain a at
/// .
/// is null.
public void SetDitchPolderSideAt(Point3D point)
{
var geometryPoint = GetPointFromGeometry(point);
if (geometryPoint == null)
{
throw CreatePointNotInGeometryException(point, Resources.CharacteristicPoint_DitchPolderSide);
}
DitchPolderSide = geometryPoint;
}
///
/// Sets the at the given point.
///
/// The location as a which to set as the .
/// Thrown when doesn't contain a at
/// .
/// is null.
public void SetBottomDitchPolderSideAt(Point3D point)
{
var geometryPoint = GetPointFromGeometry(point);
if (geometryPoint == null)
{
throw CreatePointNotInGeometryException(point, Resources.CharacteristicPoint_BottomDitchPolderSide);
}
BottomDitchPolderSide = geometryPoint;
}
///
/// Sets the at the given point.
///
/// The location as a which to set as the .
/// Thrown when doesn't contain a at
/// .
/// is null.
public void SetBottomDitchDikeSideAt(Point3D point)
{
var geometryPoint = GetPointFromGeometry(point);
if (geometryPoint == null)
{
throw CreatePointNotInGeometryException(point, Resources.CharacteristicPoint_BottomDitchDikeSide);
}
BottomDitchDikeSide = geometryPoint;
}
///
/// Sets the at the given point.
///
/// The location as a which to set as the .
/// Thrown when doesn't contain a at
/// .
/// is null.
public void SetDitchDikeSideAt(Point3D point)
{
var geometryPoint = GetPointFromGeometry(point);
if (geometryPoint == null)
{
throw CreatePointNotInGeometryException(point, Resources.CharacteristicPoint_DitchDikeSide);
}
DitchDikeSide = geometryPoint;
}
///
/// Sets the at the given point.
///
/// The location as a which to set as the .
/// Thrown when doesn't contain a at
/// .
/// is null.
public void SetDikeToeAtRiverAt(Point3D point)
{
var geometryPoint = GetPointFromGeometry(point);
if (geometryPoint == null)
{
throw CreatePointNotInGeometryException(point, Resources.CharacteristicPoint_DikeToeAtRiver);
}
DikeToeAtRiver = geometryPoint;
}
///
/// Sets the at the given point.
///
/// The location as a which to set as the .
/// Thrown when doesn't contain a at
/// .
/// is null.
public void SetDikeToeAtPolderAt(Point3D point)
{
var geometryPoint = GetPointFromGeometry(point);
if (geometryPoint == null)
{
throw CreatePointNotInGeometryException(point, Resources.CharacteristicPoint_DikeToeAtPolder);
}
DikeToeAtPolder = geometryPoint;
}
///
/// Gets the height of the projected at a L=.
///
/// The L coordinate from where to take the height of the .
/// The height of the at L=.
/// Thrown when the
/// intersection point at have a significant difference in their y coordinate.
/// is not in range of the LZ-projected .
/// is empty.
public double GetZAtL(double l)
{
ValidateHasPoints();
Point2D[] pointsInLocalCoordinates = ProjectGeometryToLZ().ToArray();
ValidateInRange(l, pointsInLocalCoordinates);
var segments = new Collection();
for (int i = 1; i < pointsInLocalCoordinates.Length; i++)
{
segments.Add(new Segment2D(pointsInLocalCoordinates[i - 1], pointsInLocalCoordinates[i]));
}
IEnumerable intersectionPoints = Math2D.SegmentsIntersectionWithVerticalLine(segments, l).OrderBy(p => p.Y).ToArray();
const double intersectionTolerance = 1e-6;
bool equalIntersections = Math.Abs(intersectionPoints.First().Y - intersectionPoints.Last().Y) < intersectionTolerance;
if (equalIntersections)
{
return intersectionPoints.First().Y;
}
var message = string.Format(Resources.RingtoetsPipingSurfaceLine_Cannot_determine_reliable_z_when_surface_line_is_vertical_in_l, l);
throw new RingtoetsPipingSurfaceLineException(message);
}
///
/// Projects the points in to localized coordinate (LZ-plane) system.
/// Z-values are retained, and the first point is put a L=0.
///
/// Collection of 2D points in the LZ-plane.
public RoundedPoint2DCollection ProjectGeometryToLZ()
{
var numberOfDecimalPlaces = 2;
var count = geometryPoints.Length;
if (count == 0)
{
return new RoundedPoint2DCollection(numberOfDecimalPlaces, Enumerable.Empty());
}
Point3D first = Points.First();
if (count == 1)
{
return new RoundedPoint2DCollection(numberOfDecimalPlaces, new[] { new Point2D(0.0, first.Z)});
}
Point3D last = Points.Last();
Point2D firstPoint = new Point2D(first.X, first.Y);
Point2D lastPoint = new Point2D(last.X, last.Y);
return new RoundedPoint2DCollection(numberOfDecimalPlaces, Points.Select(p => p.ProjectIntoLocalCoordinates(firstPoint, lastPoint)));
}
public override string ToString()
{
return Name;
}
///
/// Finds a point from which is at the same position as .
///
/// The location of a point from .
/// The from at the same location as .
/// is null.
private Point3D GetPointFromGeometry(Point3D point)
{
if (point == null)
{
throw new ArgumentNullException("point", "Cannot find a point in geometry using a null point.");
}
return Points.FirstOrDefault(p => p.Equals(point));
}
private static ArgumentException CreatePointNotInGeometryException(Point3D point, string characteristicPointDescription)
{
var message = string.Format(Resources.RingtoetsPipingSurfaceLine_SetCharacteristicPointAt_Geometry_does_not_contain_point_at_0_to_assign_as_characteristic_point_1_,
point,
characteristicPointDescription);
return new ArgumentException(message);
}
///
/// Checks whether the current collection is not empty.
///
/// is empty.
private void ValidateHasPoints()
{
if (!Points.Any())
{
throw new InvalidOperationException(Resources.RingtoetsPipingSurfaceLine_SurfaceLine_has_no_Geometry);
}
}
///
/// Checks whether is in range of the .
///
/// The value to check for.
/// Geometry projected in local coordinate system where the points are ordered on the
/// L-coordinate being monotonically non-decreasing
/// falls outside the L-coordiante span
/// defined by .
public void ValidateInRange(double localCoordinateL, Point2D[] geometryInLocalCoordinates)
{
Point2D firstLocalPoint = geometryInLocalCoordinates.First();
Point2D lastLocalPoint = geometryInLocalCoordinates.Last();
if (firstLocalPoint.X > localCoordinateL || lastLocalPoint.X < localCoordinateL)
{
var outOfRangeMessage = string.Format(Resources.RingtoetsPipingSurfaceLine_0_L_needs_to_be_in_1_2_range,
Resources.RingtoetsPipingSurfaceLine_GetZAtL_Cannot_determine_height,
firstLocalPoint.X,
lastLocalPoint.X);
throw new ArgumentOutOfRangeException(null, outOfRangeMessage);
}
}
}
}