View Javadoc
1   package org.opentrafficsim.road.network.lane.object;
2   
3   import org.djunits.value.vdouble.scalar.Length;
4   import org.djutils.draw.line.PolyLine2d;
5   import org.djutils.draw.line.Polygon2d;
6   import org.djutils.draw.point.DirectedPoint2d;
7   import org.djutils.exceptions.Throw;
8   import org.opentrafficsim.base.OtsRuntimeException;
9   import org.opentrafficsim.core.network.NetworkException;
10  import org.opentrafficsim.core.object.StaticObject;
11  import org.opentrafficsim.road.network.lane.Lane;
12  import org.opentrafficsim.road.network.lane.object.detector.LaneDetector;
13  
14  /**
15   * An abstract implementation of the LaneBasedObject interface with the required fields being initialized and getters for those
16   * fields. All StaticObjects are EventProducers, allowing them to provide state changes to subscribers.<br>
17   * <br>
18   * Note that extending classes must use a create(...) factory method that calls init() after fully constructing the object to
19   * avoid "half constructed" objects to be registered in the network.
20   * <p>
21   * Copyright (c) 2013-2024 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved. <br>
22   * BSD-style license. See <a href="https://opentrafficsim.org/docs/license.html">OpenTrafficSim License</a>.
23   * </p>
24   * @author <a href="https://github.com/averbraeck">Alexander Verbraeck</a>
25   * @author <a href="https://github.com/peter-knoppers">Peter Knoppers</a>
26   * @author <a href="https://github.com/wjschakel">Wouter Schakel</a>
27   */
28  public abstract class AbstractLaneBasedObject extends StaticObject implements LaneBasedObject
29  {
30      /** The lane for which this is a sensor. */
31      private final Lane lane;
32  
33      /** The position (between 0.0 and the length of the Lane) of the sensor on the design line of the lane. */
34      private final Length longitudinalPosition;
35  
36      /** Line. */
37      private final PolyLine2d line;
38  
39      /**
40       * Construct a new AbstractLanebasedObject with the required fields.
41       * @param id the id of the new object
42       * @param lane The lane on which the new object resides. If the new object is a Sensor; it is automatically registered on
43       *            the lane
44       * @param longitudinalPosition The position (between 0.0 and the length of the Lane) of the sensor on the design line of the
45       *            lane
46       * @param line the line of the object on the lane, which provides its location and bounds as well
47       * @param height the height of the object, in case it is a 3D object
48       * @throws NetworkException when the position on the lane is out of bounds
49       */
50      protected AbstractLaneBasedObject(final String id, final Lane lane, final Length longitudinalPosition,
51              final PolyLine2d line, final Length height) throws NetworkException
52      {
53          this(id, lane, longitudinalPosition, line, new Polygon2d(PolyLine2d.concatenate(line, line.reverse()).getPointList()),
54                  height);
55      }
56  
57      /**
58       * Construct a new AbstractLanebasedObject with the required fields.
59       * @param id the id of the new object
60       * @param lane The lane on which the new object resides. If the new object is a Sensor; it is automatically registered on
61       *            the lane
62       * @param longitudinalPosition The position (between 0.0 and the length of the Lane) of the sensor on the design line of the
63       *            lane
64       * @param line the line of the object on the lane
65       * @param contour contour of the object, which provides its location and bounds as well
66       * @param height the height of the object, in case it is a 3D object
67       * @throws NetworkException when the position on the lane is out of bounds
68       */
69      protected AbstractLaneBasedObject(final String id, final Lane lane, final Length longitudinalPosition,
70              final PolyLine2d line, final Polygon2d contour, final Length height) throws NetworkException
71      {
72          super(id, getPoint(lane, longitudinalPosition), contour, height);
73  
74          Throw.when((line instanceof Polygon2d), OtsRuntimeException.class, "Nope");
75          Throw.whenNull(lane, "lane is null");
76          Throw.whenNull(longitudinalPosition, "longitudinal position is null");
77          Throw.when(longitudinalPosition.si < 0.0 || longitudinalPosition.si > lane.getCenterLine().getLength(),
78                  NetworkException.class, "Position of the object on the lane is out of bounds");
79  
80          this.lane = lane;
81          this.longitudinalPosition = longitudinalPosition;
82          this.line = line;
83      }
84  
85      /**
86       * Construct a new LaneBasedObject with the required fields.
87       * @param id the id of the new AbstractLaneBasedObject
88       * @param lane The lane for which this is a sensor
89       * @param longitudinalPosition The position (between 0.0 and the length of the Lane) of the sensor on the design line of the
90       *            lane
91       * @param line the line of the object on the lane, which provides its location and bounds as well
92       * @throws NetworkException when the position on the lane is out of bounds
93       */
94      protected AbstractLaneBasedObject(final String id, final Lane lane, final Length longitudinalPosition,
95              final PolyLine2d line) throws NetworkException
96      {
97          this(id, lane, longitudinalPosition, line, Length.ZERO);
98      }
99  
100     /**
101      * Construct a new LaneBasedObject with the required fields.
102      * @param id the id of the new AbstractLaneBasedObject
103      * @param lane The lane for which this is a sensor
104      * @param longitudinalPosition The position (between 0.0 and the length of the Lane) of the sensor on the design line of the
105      *            lane
106      * @param line the line of the object on the lane
107      * @param contour contour of the object, which provides its location and bounds as well
108      * @throws NetworkException when the position on the lane is out of bounds
109      */
110     protected AbstractLaneBasedObject(final String id, final Lane lane, final Length longitudinalPosition,
111             final PolyLine2d line, final Polygon2d contour) throws NetworkException
112     {
113         this(id, lane, longitudinalPosition, line, contour, Length.ZERO);
114     }
115 
116     /**
117      * Returns the oriented point of the position on a lane.
118      * @param lane lane.
119      * @param longitudinalPosition longitudinal position.
120      * @return oriented point of the position on a lane.
121      */
122     private static DirectedPoint2d getPoint(final Lane lane, final Length longitudinalPosition)
123     {
124         return lane.getCenterLine().getLocationExtended(longitudinalPosition);
125     }
126 
127     @Override
128     protected void init() throws NetworkException
129     {
130         super.init();
131 
132         // OTS-218: detectors register themselves.
133         if (!(this instanceof LaneDetector))
134         {
135             this.lane.addLaneBasedObject(this); // implements OTS-218
136         }
137     }
138 
139     @Override
140     public final String getFullId()
141     {
142         return getLane().getFullId() + "." + super.getId();
143     }
144 
145     @Override
146     public final Lane getLane()
147     {
148         return this.lane;
149     }
150 
151     @Override
152     public final Length getLongitudinalPosition()
153     {
154         return this.longitudinalPosition;
155     }
156 
157     /**
158      * Returns the line.
159      * @return line.
160      */
161     @Override
162     public PolyLine2d getLine()
163     {
164         return this.line;
165     }
166 
167     @Override
168     @SuppressWarnings("checkstyle:designforextension")
169     public String toString()
170     {
171         return "LaneBasedObject[" + getId() + "]";
172     }
173 
174 }