View Javadoc
1   package org.opentrafficsim.base.geometry;
2   
3   import java.util.List;
4   
5   import org.djunits.value.vdouble.scalar.Direction;
6   import org.djutils.draw.line.PolyLine2d;
7   import org.djutils.draw.line.Ray2d;
8   import org.djutils.draw.point.DirectedPoint2d;
9   import org.djutils.draw.point.Point2d;
10  import org.djutils.exceptions.Throw;
11  
12  /**
13   * Adds a direction at the start and end point relative to its super class {@code OtsLine2d}, as the first and last segment may
14   * not have the same direction as a theoretical line the segments are a numerical approach of. These directions are used in a
15   * few methods which alter the result from the super class. The most notable addition of this class is
16   * {@code directionalOffsetLine}.
17   */
18  public class DirectionalPolyLine extends OtsLine2d
19  {
20      /** Start direction. */
21      private final Direction startDirection;
22  
23      /** End direction. */
24      private final Direction endDirection;
25  
26      /**
27       * Constructor.
28       * @param line base line
29       * @param startDirection start direction
30       * @param endDirection end direction
31       */
32      public DirectionalPolyLine(final PolyLine2d line, final Direction startDirection, final Direction endDirection)
33      {
34          super(line);
35          Throw.whenNull(startDirection, "startDirection");
36          Throw.whenNull(endDirection, "endDirection");
37          this.startDirection = startDirection;
38          this.endDirection = endDirection;
39      }
40  
41      /**
42       * Returns line at a fixed offset, adhering to end-point directions.
43       * @param offset offset
44       * @return offset line
45       */
46      public DirectionalPolyLine directionalOffsetLine(final double offset)
47      {
48          PolyLine2d offsetLine = offsetLine(offset);
49          DirectedPoint2d start = new DirectedPoint2d(getFirst().x, getFirst().y, this.startDirection.si);
50          DirectedPoint2d end = new DirectedPoint2d(getLast().x, getLast().y, this.endDirection.si);
51          List<Point2d> points = offsetLine.getPointList();
52          points.set(0, OtsGeometryUtil.offsetPoint(start, offset));
53          points.set(points.size() - 1, OtsGeometryUtil.offsetPoint(end, offset));
54          return new DirectionalPolyLine(new PolyLine2d(points), this.startDirection, this.endDirection);
55      }
56  
57      /**
58       * Returns line at a fixed offset, adhering to end-point directions.
59       * @param startOffset offset at start
60       * @param endOffset offset at end
61       * @return offset line
62       */
63      public DirectionalPolyLine directionalOffsetLine(final double startOffset, final double endOffset)
64      {
65          PolyLine2d start = directionalOffsetLine(startOffset);
66          PolyLine2d end = directionalOffsetLine(endOffset);
67          return new DirectionalPolyLine(start.transitionLine(end, (f) -> f), this.startDirection, this.endDirection);
68      }
69  
70      @Override
71      public DirectionalPolyLine extractFractional(final double start, final double end)
72      {
73          return new DirectionalPolyLine(super.extractFractional(start, end), Direction.ofSI(getLocationFraction(start).dirZ),
74                  Direction.ofSI(getLocationFraction(end).dirZ));
75      }
76  
77      @Override
78      public Ray2d getLocationFraction(final double fraction)
79      {
80          Ray2d ray = new Ray2d(super.getLocationFraction(fraction));
81          if (fraction == 0.0)
82          {
83              ray = new Ray2d(ray, this.startDirection.si);
84          }
85          else if (fraction == 1.0)
86          {
87              ray = new Ray2d(ray, this.endDirection.si);
88          }
89          return ray;
90      }
91  
92      /**
93       * Fractional projection applied with the internal start and end direction.
94       * @param x x-coordinate
95       * @param y y-coordinate
96       * @param fallback fallback method
97       * @return fraction along line which it the projection of the given coordinate
98       */
99      public double projectFractional(final double x, final double y, final FractionalFallback fallback)
100     {
101         return projectFractional(this.startDirection, this.endDirection, x, y, fallback);
102     }
103 
104     /**
105      * Returns the start direction.
106      * @return start direction
107      */
108     public Direction getStartDirection()
109     {
110         return this.startDirection;
111     }
112 
113     /**
114      * Returns the end direction.
115      * @return end direction
116      */
117     public Direction getEndDirection()
118     {
119         return this.endDirection;
120     }
121 }