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.OrientedPoint2d;
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      /** */
21      private static final long serialVersionUID = 20241130L;
22  
23      /** Start direction. */
24      private final Direction startDirection;
25  
26      /** End direction. */
27      private final Direction endDirection;
28  
29      /**
30       * Constructor.
31       * @param line base line
32       * @param startDirection start direction
33       * @param endDirection end direction
34       */
35      public DirectionalPolyLine(final PolyLine2d line, final Direction startDirection, final Direction endDirection)
36      {
37          super(line);
38          Throw.whenNull(startDirection, "startDirection");
39          Throw.whenNull(endDirection, "endDirection");
40          this.startDirection = startDirection;
41          this.endDirection = endDirection;
42      }
43  
44      /**
45       * Returns line at a fixed offset, adhering to end-point directions.
46       * @param offset offset
47       * @return offset line
48       */
49      public DirectionalPolyLine directionalOffsetLine(final double offset)
50      {
51          PolyLine2d offsetLine = offsetLine(offset);
52          OrientedPoint2d start = new OrientedPoint2d(getFirst().x, getFirst().y, this.startDirection.si);
53          OrientedPoint2d end = new OrientedPoint2d(getLast().x, getLast().y, this.endDirection.si);
54          List<Point2d> points = offsetLine.getPointList();
55          points.set(0, OtsGeometryUtil.offsetPoint(start, offset));
56          points.set(points.size() - 1, OtsGeometryUtil.offsetPoint(end, offset));
57          return new DirectionalPolyLine(new PolyLine2d(points), this.startDirection, this.endDirection);
58      }
59  
60      /**
61       * Returns line at a fixed offset, adhering to end-point directions.
62       * @param startOffset offset at start
63       * @param endOffset offset at end
64       * @return offset line
65       */
66      public DirectionalPolyLine directionalOffsetLine(final double startOffset, final double endOffset)
67      {
68          PolyLine2d start = directionalOffsetLine(startOffset);
69          PolyLine2d end = directionalOffsetLine(endOffset);
70          return new DirectionalPolyLine(start.transitionLine(end, (f) -> f), this.startDirection, this.endDirection);
71      }
72  
73      @Override
74      public DirectionalPolyLine extractFractional(final double start, final double end)
75      {
76          return new DirectionalPolyLine(super.extractFractional(start, end),
77                  Direction.instantiateSI(getLocationFraction(start).phi), Direction.instantiateSI(getLocationFraction(end).phi));
78      }
79  
80      @Override
81      public Ray2d getLocationFraction(final double fraction)
82      {
83          Ray2d ray = super.getLocationFraction(fraction);
84          if (fraction == 0.0)
85          {
86              ray = new Ray2d(ray, this.startDirection.si);
87          }
88          else if (fraction == 1.0)
89          {
90              ray = new Ray2d(ray, this.endDirection.si);
91          }
92          return ray;
93      }
94  
95      /**
96       * Fractional projection applied with the internal start and end direction.
97       * @param x x-coordinate
98       * @param y y-coordinate
99       * @param fallback fallback method
100      * @return fraction along line which it the projection of the given coordinate
101      */
102     public double projectFractional(final double x, final double y, final FractionalFallback fallback)
103     {
104         return projectFractional(this.startDirection, this.endDirection, x, y, fallback);
105     }
106 
107     /**
108      * Returns the start direction.
109      * @return start direction
110      */
111     public Direction getStartDirection()
112     {
113         return this.startDirection;
114     }
115 
116     /**
117      * Returns the end direction.
118      * @return end direction
119      */
120     public Direction getEndDirection()
121     {
122         return this.endDirection;
123     }
124 }