/// <summary> /// Gets the next point. /// </summary> /// <param name="points">The points.</param> /// <param name="currentPoint">The current point.</param> /// <returns></returns> internal static LRSPoint GetNextPoint(ref List <LRSPoint> points, LRSPoint currentPoint) { var index = points.IndexOf(currentPoint); // return null if index is -1 or last index return(index >= 0 && index < points.Count - 1 ? points[index + 1] : null); }
/// <summary> /// Gets the previous point. /// </summary> /// <param name="points">The points.</param> /// <param name="currentPoint">The current point.</param> /// <returns></returns> internal static LRSPoint GetPreviousPoint(ref List <LRSPoint> points, LRSPoint currentPoint) { var index = points.IndexOf(currentPoint); // return null if index is -1; null for first point return(index > 0 ? points[index - 1] : null); }
/// <summary> /// Sets the offset bearing. /// </summary> /// <param name="nextPoint">The next point.</param> internal void SetOffsetBearing(LRSPoint nextPoint) { if (nextPoint != null) { OffsetBearing = CalculateOffsetBearing(nextPoint); } }
/// <summary> /// Calculates the offset angle. /// </summary> /// <param name="previousPoint">The current point.</param> /// <param name="isNegativeOffset">Is Offset is Negative</param> private double CalculateOffsetAngle(LRSPoint previousPoint, bool isNegativeOffset) { double offsetAngle = 0; var previousPointOffsetBearing = previousPoint?.OffsetBearing; // Left if (!isNegativeOffset) { if (OffsetBearing == null) { if (previousPointOffsetBearing != null) { offsetAngle = (double)previousPointOffsetBearing - 90; } } else if (previousPointOffsetBearing == null) { offsetAngle = (double)OffsetBearing - 90; } else { //(360 + b1.OffsetBearing - ((360 - ((b2.OffsetBearing + 180) - b1.OffsetBearing)) / 2)) % 360 offsetAngle = ( 360 + (double)OffsetBearing - ( ( 360 - ( ((double)previousPointOffsetBearing + 180) - (double)OffsetBearing ) ) / 2 ) ) % 360; } } // Right else { if (OffsetBearing == null) { if (previousPointOffsetBearing != null) { offsetAngle = (double)previousPointOffsetBearing + 90; } } else if (previousPointOffsetBearing == null) { offsetAngle = (double)OffsetBearing + 90; } else { // (b1.OffsetBearing + ((((b2.OffsetBearing + 180) - b1.OffsetBearing)) / 2)) % 360 offsetAngle = ((double)OffsetBearing + (((((double)previousPointOffsetBearing + 180) - (double)OffsetBearing)) / 2)) % 360; } } return(offsetAngle); }
/// <summary> /// Gets the second point radian. /// </summary> /// <param name="nextPoint">The next point.</param> /// <param name="middlePoint">The middle point.</param> /// <returns></returns> private double GetSecondPointRadian(LRSPoint nextPoint, LRSPoint middlePoint) { var atan = GetAtanInDegree(middlePoint, nextPoint); atan = 90 - atan; atan = atan <= 0 ? 360 + atan : atan; return(SpatialUtil.ToRadians(180 - atan)); }
/// <summary> /// Gets the first point radian. /// </summary> /// <param name="previousPoint">The previous point.</param> /// <param name="middlePoint">The middle point.</param> /// <returns></returns> private double GetFirstPointRadian(LRSPoint previousPoint, LRSPoint middlePoint) { var atan = GetAtanInDegree(middlePoint, previousPoint); atan = 90 - atan; atan = atan <= 0 ? 360 + atan : atan; return(SpatialUtil.ToRadians(360 - atan)); }
/// <summary> /// Updates the length. /// </summary> /// <param name="currentPoint">The current point.</param> private void UpdateLength(LRSPoint currentPoint) { if (!_points.Any() || _points.Count <= 0) { return; } var previousPoint = _points.Last(); Length += previousPoint.GetDistance(currentPoint); }
/// <summary> /// Locates the point. /// </summary> /// <param name="measure">The measure.</param> /// <param name="firstPoint"></param> /// <returns></returns> internal LRSPoint LocatePoint(double measure, LRSPoint firstPoint = null) { var startPoint = firstPoint ?? GetStartPoint(); var endPoint = GetEndPoint(); if (startPoint.M == null || endPoint.M == null) { return(null); } var fraction = (measure - startPoint.M.Value) / (endPoint.M.Value - startPoint.M.Value); var newX = (startPoint.X * (1 - fraction)) + (endPoint.X * fraction); var newY = (startPoint.Y * (1 - fraction)) + (endPoint.Y * fraction); return(new LRSPoint(newX, newY, null, measure, SRID)); }
/// <summary> /// Calculates the slope. /// </summary> /// <param name="nextLRSPoint">The next LRS point.</param> /// <param name="slopeValue"></param> internal double?GetSlope(LRSPoint nextLRSPoint, out SlopeValue slopeValue) { slopeValue = SlopeValue.None; var xDifference = nextLRSPoint.X - X; var yDifference = nextLRSPoint.Y - Y; if (xDifference.EqualsTo(0)) { slopeValue = yDifference > 0 ? SlopeValue.PositiveInfinity : SlopeValue.NegativeInfinity; return(null); } else if (yDifference.EqualsTo(0)) { slopeValue = xDifference > 0 ? SlopeValue.PositiveZero : SlopeValue.NegativeZero; return(null); } return(yDifference / xDifference); }
/// <summary> /// Gets the deviation angle of 3 points. /// </summary> /// <param name="pointA">The point a.</param> /// <param name="pointO">The point o.</param> /// <param name="pointB">The point b.</param> /// <param name="isNegativeOffset">if set to <c>true</c> [is negative offset].</param> /// <returns></returns> private double GetAOBAngle(LRSPoint pointA, LRSPoint pointO, LRSPoint pointB, bool isNegativeOffset) { const double angleCorrection = Math.PI / 2; const double angleConversion = 2 * Math.PI; var atanAo = pointA.GetAtanInRadian(pointO) + angleCorrection; var atanBo = pointB.GetAtanInRadian(pointO) + angleCorrection; // angle conversion atanAo = SpatialUtil.ToDegrees(atanAo <= 0 ? angleConversion + atanAo : atanAo); atanBo = SpatialUtil.ToDegrees(atanBo <= 0 ? angleConversion + atanBo : atanBo); var deviationAngle = 360 - (atanAo > atanBo ? 360 - (atanAo - atanBo) : atanBo - atanAo); // for positive offset; offset curve will be to the left of input geom; // so for positive deviation angle the computed angle should be subtracted from 360 // for negative offset; offset curve will be to the right of input geom return(isNegativeOffset ? deviationAngle : 360 - deviationAngle); }
/// <summary> /// Gets the distance from point. /// </summary> /// <param name="nextPoint">The next point.</param> /// <returns>Offset Point.</returns> internal double GetDistance(LRSPoint nextPoint) { return(SpatialExtensions.GetDistance(X, Y, nextPoint.X, nextPoint.Y)); }
/// <summary> /// Calculates the slope. /// </summary> /// <param name="nextLRSPoint">The next LRS point.</param> internal void CalculateSlope(LRSPoint nextLRSPoint) { Slope = GetSlope(nextLRSPoint, out SlopeType); }
/// <summary> /// Compute and populate parallel points on bend lines. /// </summary> /// <param name="offset">The offset.</param> /// <param name="points">The points.</param> /// <param name="tolerance"></param> /// <returns>Point parallel to the current point.</returns> internal List <LRSPoint> GetAndPopulateParallelPoints(double offset, double tolerance, ref List <LRSPoint> points) { // list to capture additional vertices. var lrsPoints = new List <LRSPoint>(); // parallel point to the current point var parallelPoint = GetParallelPoint(); // get previous and next point var previousPoint = GetPreviousPoint(ref points, this); var nextPoint = GetNextPoint(ref points, this); // offset distance between parallel point and input point var diffInDistance = Math.Round(parallelPoint.GetDistance(this), 5); // offset distance difference between parallel point and input point var offsetDiff = Math.Abs(Math.Abs(diffInDistance) - Math.Abs(offset)); if (offsetDiff <= tolerance || previousPoint == null || nextPoint == null) { lrsPoints.Add(parallelPoint); } else { var negativeOffset = offset < 0; var deviationAngle = GetAOBAngle(previousPoint, this, nextPoint, negativeOffset); if (deviationAngle <= 90) { var firsPointRadian = GetFirstPointRadian(previousPoint, this); var nextPointRadian = GetSecondPointRadian(nextPoint, this); // first point var firstPointX = X + (offset * Math.Cos(firsPointRadian)); var firstPointY = Y + (offset * Math.Sin(firsPointRadian)); var firstPoint = new LRSPoint(firstPointX, firstPointY, null, M, _srid); // second point var secondPointX = X + (offset * Math.Cos(nextPointRadian)); var secondPointY = Y + (offset * Math.Sin(nextPointRadian)); var secondPoint = new LRSPoint(secondPointX, secondPointY, null, M, _srid); // if computed first point is within tolerance of second point then add only first point if (firstPoint.GetDistance(secondPoint) <= tolerance) { lrsPoints.Add(firstPoint); } else { // add first point lrsPoints.Add(firstPoint); // compute middle point var fraction = Math.Abs(offset / OffsetDistance); var middleX = (X * (1 - fraction)) + (parallelPoint.X * fraction); var middleY = (Y * (1 - fraction)) + (parallelPoint.Y * fraction); var middlePoint = new LRSPoint(middleX, middleY, null, M, _srid); // if not within tolerance add middle point if (firstPoint.GetDistance(middlePoint) > tolerance) { lrsPoints.Add(middlePoint); } // add second point lrsPoints.Add(secondPoint); } } else { lrsPoints.Add(parallelPoint); } } return(lrsPoints); }
/// <summary> /// Gets the offset point. /// </summary> /// <param name="nextPoint">The next point.</param> /// <returns>Offset Point.</returns> private LRSPoint GetOffsetPoint(LRSPoint nextPoint) { return(this - nextPoint); }
/// <summary> /// Sets the offset angle. /// </summary> /// <param name="previousPoint">The current point.</param> /// <param name="isNegativeOffset">Is Offset is Negative</param> internal void SetOffsetAngle(LRSPoint previousPoint, bool isNegativeOffset) { _offsetAngle = CalculateOffsetAngle(previousPoint, isNegativeOffset); }
/// <summary> /// Calculates the offset bearing. /// </summary> /// <param name="nextPoint">The next point.</param> private double CalculateOffsetBearing(LRSPoint nextPoint) { _angle = SpatialUtil.ToDegrees(GetAtanInRadian(nextPoint)); return((90 - _angle + 360) % 360); }
/// <summary> /// Re calculate the measure. /// </summary> /// <param name="previousPoint">The previous point.</param> /// <param name="currentLength"></param> /// <param name="totalLength">The total length.</param> /// <param name="startMeasure">The start measure.</param> /// <param name="endMeasure">The end measure.</param> internal void ReCalculateMeasure(LRSPoint previousPoint, ref double currentLength, double totalLength, double startMeasure, double endMeasure) { currentLength += GetDistance(previousPoint); M = startMeasure + (currentLength / totalLength) * (endMeasure - startMeasure); }
/// <summary> /// Gets the arc to tangent. /// </summary> /// <param name="nextPoint">The next point.</param> /// <returns>In Radian</returns> private double GetAtanInRadian(LRSPoint nextPoint) { var offsetPoint = GetOffsetPoint(nextPoint); return(Math.Atan2(offsetPoint.Y, offsetPoint.X)); }
/// <summary> /// Gets the atan2 in degrees. /// This does angle correct when atan2 value is negative /// </summary> /// <param name="point1">The point1.</param> /// <param name="point2">The point2.</param> /// <returns>Atan2 in degrees</returns> private double GetAtanInDegree(LRSPoint point1, LRSPoint point2) { var atan = point1.GetAtanInRadian(point2); return(SpatialUtil.ToDegrees(atan <= 0 ? (2 * Math.PI) + atan : atan)); }
/// <summary> /// Adds the point. /// </summary> /// <param name="lrsPoint">The l rs point.</param> internal void AddPoint(LRSPoint lrsPoint) { UpdateLength(lrsPoint); _points.Add(lrsPoint); }
/// <summary> /// Determines whether X, Y co-ordinates of current and second point is within tolerance /// </summary> /// <param name="secondPoint">The second point.</param> /// <param name="tolerance">The tolerance.</param> /// <returns> /// <c>true</c> if X, Y co-ordinates of current and second point is within tolerance; otherwise, <c>false</c>. /// </returns> internal bool IsXYWithinTolerance(LRSPoint secondPoint, double tolerance) { return(Math.Abs(X - secondPoint.X) <= tolerance && Math.Abs(Y - secondPoint.Y) <= tolerance); }