View Javadoc
1   package org.opentrafficsim.core.geometry;
2   
3   import java.util.List;
4   
5   import org.djutils.draw.line.PolyLine2d;
6   import org.djutils.draw.line.Ray2d;
7   import org.djutils.draw.point.OrientedPoint2d;
8   import org.djutils.draw.point.Point2d;
9   import org.djutils.exceptions.Throw;
10  import org.opentrafficsim.base.geometry.OtsGeometryUtil;
11  import org.opentrafficsim.base.geometry.OtsLine2d;
12  
13  /**
14   * Continuous definition of a PolyLine. Naive approaches are applied for offsets, since polylines have no exact information for
15   * this.
16   * <p>
17   * Copyright (c) 2023-2024 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved. <br>
18   * BSD-style license. See <a href="https://opentrafficsim.org/docs/license.html">OpenTrafficSim License</a>.
19   * </p>
20   * @author <a href="https://github.com/wjschakel">Wouter Schakel</a>
21   */
22  public class ContinuousPolyLine implements ContinuousLine
23  {
24  
25      /** Line. */
26      private final PolyLine2d line;
27  
28      /** Start point. */
29      private final OrientedPoint2d startPoint;
30  
31      /** End points. */
32      private final OrientedPoint2d endPoint;
33  
34      /**
35       * Define continuous line from polyline. Start and end point direction are derived from the line.
36       * @param line line.
37       */
38      public ContinuousPolyLine(final PolyLine2d line)
39      {
40          Throw.whenNull(line, "Line may not be null.");
41          this.line = line;
42          Ray2d startRay = line.getLocationFractionExtended(0.0);
43          Ray2d endRay = line.getLocationFractionExtended(1.0);
44          this.startPoint = new OrientedPoint2d(startRay.x, startRay.y, startRay.phi);
45          this.endPoint = new OrientedPoint2d(endRay.x, endRay.y, endRay.phi);
46      }
47  
48      /**
49       * Define continuous line from polyline. Start and end point are given and may alter the direction at the endpoints
50       * (slightly).
51       * @param line line.
52       * @param startPoint start point.
53       * @param endPoint end point.
54       */
55      public ContinuousPolyLine(final PolyLine2d line, final OrientedPoint2d startPoint, final OrientedPoint2d endPoint)
56      {
57          Throw.whenNull(line, "Line may not be null.");
58          this.line = line;
59          this.startPoint = startPoint;
60          this.endPoint = endPoint;
61      }
62  
63      @Override
64      public OrientedPoint2d getStartPoint()
65      {
66          return this.startPoint;
67      }
68  
69      @Override
70      public OrientedPoint2d getEndPoint()
71      {
72          return this.endPoint;
73      }
74  
75      @Override
76      public double getStartCurvature()
77      {
78          return 1.0 / getStartRadius();
79      }
80  
81      @Override
82      public double getEndCurvature()
83      {
84          return 1.0 / getEndRadius();
85      }
86  
87      @Override
88      public double getStartRadius()
89      {
90          return new OtsLine2d(this.line).getProjectedRadius(0.0).si;
91      }
92  
93      @Override
94      public double getEndRadius()
95      {
96          return new OtsLine2d(this.line).getProjectedRadius(1.0).si;
97      }
98  
99      /**
100      * Polyline from continuous line. Returns the line as is.
101      * @return polyline.
102      */
103     public PolyLine2d flatten()
104     {
105         return this.line;
106     }
107 
108     /**
109      * Returns the line as is. Flattener is ignored.
110      * @param flattener flattener (ignored).
111      * @return flattened line.
112      */
113     @Override
114     public PolyLine2d flatten(final Flattener flattener)
115     {
116         return this.line;
117     }
118 
119     /**
120      * Returns an offset line. This is a regular offset line, with start and end points moved to be perpendicular to end point
121      * directions.
122      * @param offset offset data.
123      * @return flattened line.
124      */
125     public PolyLine2d offset(final ContinuousDoubleFunction offset)
126     {
127         Throw.whenNull(offset, "Offsets may not be null.");
128         double[] knots = offset.getKnots();
129         double[] knotOffset = new double[knots.length];
130         for (int i = 0; i < knots.length; i++)
131         {
132             knotOffset[i] = offset.apply(knots[i]);
133         }
134         PolyLine2d offsetLine =
135                 OtsGeometryUtil.offsetLine(this.line, knots, knotOffset);
136         Point2d start = OtsGeometryUtil.offsetPoint(this.startPoint, offset.apply(0.0));
137         Point2d end = OtsGeometryUtil.offsetPoint(this.endPoint, offset.apply(1.0));
138         List<Point2d> points = offsetLine.getPointList();
139         points.set(0, start);
140         points.set(points.size() - 1, end);
141         return new PolyLine2d(points);
142     }
143 
144     /**
145      * Returns the regular offset. Flattener is ignored.
146      * @param offset offset data.
147      * @param flattener flattener (ignored).
148      * @return flattened line.
149      */
150     @Override
151     public PolyLine2d flattenOffset(final ContinuousDoubleFunction offset, final Flattener flattener)
152     {
153         return offset(offset);
154     }
155 
156     @Override
157     public double getLength()
158     {
159         return this.line.getLength();
160     }
161 
162     @Override
163     public String toString()
164     {
165         return "ContinuousPolyLine [startPoint=" + this.startPoint + ", endPoint=" + this.endPoint + "]";
166     }
167 
168 }