1 package org.opentrafficsim.road.network.lane.object.sensor;
2
3 import org.djunits.value.vdouble.scalar.Length;
4 import org.djutils.exceptions.Throw;
5 import org.opentrafficsim.core.compatibility.Compatible;
6 import org.opentrafficsim.core.geometry.OTSGeometryException;
7 import org.opentrafficsim.core.geometry.OTSLine3D;
8 import org.opentrafficsim.core.geometry.OTSPoint3D;
9 import org.opentrafficsim.core.gtu.GTUDirectionality;
10 import org.opentrafficsim.core.gtu.GTUType;
11 import org.opentrafficsim.core.gtu.RelativePosition;
12 import org.opentrafficsim.core.network.NetworkException;
13 import org.opentrafficsim.road.gtu.lane.LaneBasedGTU;
14 import org.opentrafficsim.road.network.lane.CrossSectionElement;
15 import org.opentrafficsim.road.network.lane.Lane;
16 import org.opentrafficsim.road.network.lane.object.AbstractLaneBasedObject;
17
18 import nl.tudelft.simulation.dsol.simulators.DEVSSimulatorInterface;
19 import nl.tudelft.simulation.dsol.simulators.SimulatorInterface;
20 import nl.tudelft.simulation.language.d3.DirectedPoint;
21
22
23
24
25
26
27
28
29
30
31
32 public abstract class AbstractSensor extends AbstractLaneBasedObject implements SingleSensor
33 {
34
35 private static final long serialVersionUID = 20141231L;
36
37
38 private final RelativePosition.TYPE positionType;
39
40
41 private final DEVSSimulatorInterface.TimeDoubleUnit simulator;
42
43
44 private final Compatible detectedGTUTypes;
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60 @SuppressWarnings("checkstyle:parameternumber")
61 public AbstractSensor(final String id, final Lane lane, final Length longitudinalPosition,
62 final RelativePosition.TYPE positionType, final DEVSSimulatorInterface.TimeDoubleUnit simulator,
63 final OTSLine3D geometry, final Length elevation, final Compatible detectedGTUTypes) throws NetworkException
64 {
65 super(id, lane, longitudinalPosition, geometry, elevation);
66 Throw.when(simulator == null, NullPointerException.class, "simulator is null");
67 Throw.when(positionType == null, NullPointerException.class, "positionType is null");
68 Throw.when(id == null, NullPointerException.class, "id is null");
69 this.positionType = positionType;
70 this.simulator = simulator;
71 this.detectedGTUTypes = detectedGTUTypes;
72 getLane().addSensor(this);
73 }
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88 public AbstractSensor(final String id, final Lane lane, final Length longitudinalPosition,
89 final RelativePosition.TYPE positionType, final DEVSSimulatorInterface.TimeDoubleUnit simulator,
90 final OTSLine3D geometry, final Compatible detectedGTUTypes) throws NetworkException
91 {
92 this(id, lane, longitudinalPosition, positionType, simulator, geometry, DEFAULT_SENSOR_ELEVATION, detectedGTUTypes);
93 }
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108 public AbstractSensor(final String id, final Lane lane, final Length longitudinalPosition,
109 final RelativePosition.TYPE positionType, final DEVSSimulatorInterface.TimeDoubleUnit simulator,
110 final Compatible detectedGTUTypes) throws NetworkException
111 {
112 this(id, lane, longitudinalPosition, positionType, simulator, makeGeometry(lane, longitudinalPosition),
113 detectedGTUTypes);
114 }
115
116
117
118
119
120
121
122
123 private static OTSLine3D makeGeometry(final Lane lane, final Length longitudinalPosition) throws NetworkException
124 {
125 try
126 {
127 double w45 = lane.getWidth(longitudinalPosition).si * 0.45;
128 DirectedPoint c = lane.getCenterLine().getLocation(longitudinalPosition);
129 double a = c.getRotZ();
130 OTSPoint3D p1 = new OTSPoint3D(c.x + w45 * Math.cos(a + Math.PI / 2), c.y - w45 * Math.sin(a + Math.PI / 2), c.z);
131 OTSPoint3D p2 = new OTSPoint3D(c.x - w45 * Math.cos(a + Math.PI / 2), c.y + w45 * Math.sin(a + Math.PI / 2), c.z);
132 return new OTSLine3D(p1, p2);
133 }
134 catch (OTSGeometryException exception)
135 {
136 throw new NetworkException(exception);
137 }
138 }
139
140
141 @Override
142 public final void trigger(final LaneBasedGTU gtu)
143 {
144 fireTimedEvent(SingleSensor.SENSOR_TRIGGER_EVENT, new Object[] {getId(), this, gtu, this.positionType},
145 getSimulator().getSimulatorTime());
146 triggerResponse(gtu);
147 }
148
149
150
151
152
153 protected abstract void triggerResponse(final LaneBasedGTU gtu);
154
155
156 @Override
157 public final RelativePosition.TYPE getPositionType()
158 {
159 return this.positionType;
160 }
161
162
163 @Override
164 public final DEVSSimulatorInterface.TimeDoubleUnit getSimulator()
165 {
166 return this.simulator;
167 }
168
169
170 @SuppressWarnings("checkstyle:designforextension")
171 @Override
172 public int hashCode()
173 {
174 final int prime = 31;
175 int result = 1;
176 result = prime * result + ((getLane() == null) ? 0 : getLane().hashCode());
177 long temp;
178 temp = Double.doubleToLongBits(getLongitudinalPosition().si);
179 result = prime * result + (int) (temp ^ (temp >>> 32));
180 result = prime * result + ((this.positionType == null) ? 0 : this.positionType.hashCode());
181 return result;
182 }
183
184
185 @SuppressWarnings({"checkstyle:needbraces", "checkstyle:designforextension"})
186 @Override
187 public boolean equals(final Object obj)
188 {
189 if (this == obj)
190 return true;
191 if (obj == null)
192 return false;
193 if (getClass() != obj.getClass())
194 return false;
195 AbstractSensor other = (AbstractSensor) obj;
196 if (this.getLane() == null)
197 {
198 if (other.getLane() != null)
199 return false;
200 }
201 else if (!this.getLane().equals(other.getLane()))
202 return false;
203 if (Double.doubleToLongBits(this.getLongitudinalPosition().si) != Double
204 .doubleToLongBits(other.getLongitudinalPosition().si))
205 return false;
206 if (this.positionType == null)
207 {
208 if (other.positionType != null)
209 return false;
210 }
211 else if (!this.positionType.equals(other.positionType))
212 return false;
213 return true;
214 }
215
216
217 @SuppressWarnings("checkstyle:designforextension")
218 @Override
219 public int compareTo(final SingleSensor o)
220 {
221 if (this.getLane() != o.getLane())
222 {
223 return this.getLane().hashCode() < o.getLane().hashCode() ? -1 : 1;
224 }
225 if (this.getLongitudinalPosition().si != o.getLongitudinalPosition().si)
226 {
227 return this.getLongitudinalPosition().si < o.getLongitudinalPosition().si ? -1 : 1;
228 }
229 if (!this.positionType.equals(o.getPositionType()))
230 {
231 return this.positionType.hashCode() < o.getPositionType().hashCode() ? -1 : 1;
232 }
233 if (!this.equals(o))
234 {
235 return this.hashCode() < o.hashCode() ? -1 : 1;
236 }
237 return 0;
238 }
239
240
241 @Override
242 @SuppressWarnings("checkstyle:designforextension")
243 public String toString()
244 {
245 return "Sensor[" + getId() + "]";
246 }
247
248
249 @Override
250 public abstract AbstractSensor clone(CrossSectionElement newCSE, SimulatorInterface.TimeDoubleUnit newSimulator)
251 throws NetworkException;
252
253
254 @Override
255 public final boolean isCompatible(final GTUType gtuType, final GTUDirectionality directionality)
256 {
257 return this.detectedGTUTypes.isCompatible(gtuType, directionality);
258 }
259
260
261
262
263
264 public final Compatible getDetectedGTUTypes()
265 {
266 return this.detectedGTUTypes;
267 }
268
269 }