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