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