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 }