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