1 package org.opentrafficsim.core.gtu;
2
3 import nl.tudelft.simulation.dsol.SimRuntimeException;
4 import nl.tudelft.simulation.dsol.formalisms.eventscheduling.SimEvent;
5 import nl.tudelft.simulation.language.d3.DirectedPoint;
6
7 import org.djunits.unit.TimeUnit;
8 import org.djunits.value.vdouble.scalar.Acceleration;
9 import org.djunits.value.vdouble.scalar.Length;
10 import org.djunits.value.vdouble.scalar.Speed;
11 import org.djunits.value.vdouble.scalar.Time;
12 import org.opentrafficsim.core.dsol.OTSDEVSSimulatorInterface;
13 import org.opentrafficsim.core.dsol.OTSSimTimeDouble;
14 import org.opentrafficsim.core.geometry.OTSGeometryException;
15 import org.opentrafficsim.core.geometry.OTSLine3D;
16 import org.opentrafficsim.core.geometry.OTSPoint3D;
17 import org.opentrafficsim.core.gtu.perception.Perception;
18 import org.opentrafficsim.core.gtu.plan.operational.OperationalPlan;
19 import org.opentrafficsim.core.gtu.plan.operational.OperationalPlanBuilder;
20 import org.opentrafficsim.core.gtu.plan.operational.OperationalPlanException;
21 import org.opentrafficsim.core.gtu.plan.strategical.StrategicalPlanner;
22 import org.opentrafficsim.core.gtu.plan.tactical.TacticalPlanner;
23 import org.opentrafficsim.core.idgenerator.IdGenerator;
24 import org.opentrafficsim.core.network.NetworkException;
25 import org.opentrafficsim.core.perception.PerceivableContext;
26
27
28
29
30
31
32
33
34
35
36
37
38 public abstract class AbstractGTU implements GTU
39 {
40
41 private static final long serialVersionUID = 20140822L;
42
43
44 private final String id;
45
46
47 private final GTUType gtuType;
48
49
50 private final OTSDEVSSimulatorInterface simulator;
51
52
53 private Acceleration maximumAcceleration;
54
55
56 private Acceleration maximumDeceleration;
57
58
59
60
61
62
63 private Length.Rel odometer;
64
65
66 private StrategicalPlanner strategicalPlanner;
67
68
69 private TacticalPlanner tacticalPlanner = null;
70
71
72 private OperationalPlan operationalPlan = null;
73
74
75 private SimEvent<OTSSimTimeDouble> nextMoveEvent;
76
77
78 private Perception perception;
79
80
81 private PerceivableContext perceivableContext;
82
83
84 private TurnIndicatorStatus turnIndicatorStatus = TurnIndicatorStatus.NOTPRESENT;
85
86
87 private boolean destroyed = false;
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103 @SuppressWarnings("checkstyle:parameternumber")
104 public AbstractGTU(final String id, final GTUType gtuType, final OTSDEVSSimulatorInterface simulator,
105 final StrategicalPlanner strategicalPlanner, final Perception perception, final DirectedPoint initialLocation,
106 final Speed initialSpeed, final PerceivableContext perceivableContext) throws SimRuntimeException, GTUException
107 {
108 GTUException.failIf(id == null, "id is null");
109 GTUException.failIf(gtuType == null, "gtuType is null");
110 GTUException.failIf(gtuType.equals(GTUType.NONE), "gtuType of an actual GTU cannot be GTUType.NONE");
111 GTUException.failIf(gtuType.equals(GTUType.ALL), "gtuType of an actual GTU cannot be GTUType.ALL");
112 GTUException.failIf(perceivableContext == null, "perceivableContext is null for GTU with id " + id);
113 GTUException.failIf(perceivableContext.containsGtuId(id), "GTU with id " + id
114 + " already registered in perceivableContext " + perceivableContext.getId());
115 GTUException.failIf(simulator == null, "simulator is null for GTU with id " + id);
116 GTUException.failIf(strategicalPlanner == null, "strategicalPlanner is null for GTU with id " + id);
117 GTUException.failIf(perception == null, "perception is null for GTU with id " + id);
118 GTUException.failIf(initialLocation == null | Double.isNaN(initialLocation.x) | Double.isNaN(initialLocation.y)
119 | Double.isNaN(initialLocation.z), "initialLocation " + initialLocation + " invalid for GTU with id " + id);
120 GTUException.failIf(initialSpeed == null, "initialSpeed is null for GTU with id " + id);
121
122 this.id = id;
123 this.gtuType = gtuType;
124 this.simulator = simulator;
125 this.strategicalPlanner = strategicalPlanner;
126 this.perception = perception;
127 this.odometer = Length.Rel.ZERO;
128 this.perceivableContext = perceivableContext;
129 this.perceivableContext.addGTU(this);
130 Time.Abs now = this.simulator.getSimulatorTime().getTime();
131
132 if (initialLocation != null)
133 {
134
135
136 this.nextMoveEvent =
137 new SimEvent<>(new OTSSimTimeDouble(now), this, this, "move", new Object[]{initialLocation});
138 this.simulator.scheduleEvent(this.nextMoveEvent);
139 }
140
141
142 DirectedPoint p = initialLocation == null ? new DirectedPoint() : initialLocation;
143 try
144 {
145 if (initialSpeed.si < OperationalPlan.DRIFTING_SPEED_SI)
146 {
147 this.operationalPlan = new OperationalPlan(this, p, now, new Time.Rel(1.0e-6, TimeUnit.SECOND));
148 }
149 else
150 {
151 OTSPoint3D p2 =
152 new OTSPoint3D(p.x + 1E-6 * Math.cos(p.getRotZ()), p.y + 1E-6 * Math.sin(p.getRotZ()), p.z);
153 OTSLine3D path = new OTSLine3D(new OTSPoint3D(p), p2);
154 this.operationalPlan = OperationalPlanBuilder.buildConstantSpeedPlan(this, path, now, initialSpeed);
155 }
156 }
157 catch (OperationalPlanException | OTSGeometryException exception)
158 {
159 throw new GTUException("Failed to create OperationalPlan for GTU " + this.id, exception);
160 }
161 }
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177 @SuppressWarnings("checkstyle:parameternumber")
178 public AbstractGTU(final IdGenerator idGenerator, final GTUType gtuType, final OTSDEVSSimulatorInterface simulator,
179 final StrategicalPlanner strategicalPlanner, final Perception perception, final DirectedPoint initialLocation,
180 final Speed initialSpeed, final PerceivableContext perceivableContext) throws SimRuntimeException, GTUException
181 {
182 this(generateId(idGenerator), gtuType, simulator, strategicalPlanner, perception, initialLocation,
183 initialSpeed, perceivableContext);
184 }
185
186
187
188
189
190
191
192 private static String generateId(final IdGenerator idGenerator) throws GTUException
193 {
194 GTUException.failIf(idGenerator == null, "AbstractGTU.<init>: idGenerator is null");
195 return idGenerator.nextId();
196 }
197
198
199
200
201 @SuppressWarnings("checkstyle:designforextension")
202 public void destroy()
203 {
204 this.perceivableContext.removeGTU(this);
205
206
207 if (this.nextMoveEvent != null)
208 {
209 this.simulator.cancelEvent(this.nextMoveEvent);
210 this.nextMoveEvent = null;
211 }
212
213 this.destroyed = true;
214 }
215
216
217
218
219
220
221
222
223
224
225
226
227
228 @SuppressWarnings("checkstyle:designforextension")
229 protected void move(final DirectedPoint fromLocation) throws SimRuntimeException, OperationalPlanException,
230 GTUException, NetworkException
231 {
232 Time.Abs now = this.simulator.getSimulatorTime().getTime();
233
234
235
236 if (this.operationalPlan != null)
237 {
238 this.odometer = this.odometer.plus(this.operationalPlan.getTraveledDistance(now));
239 }
240
241
242 if (this.tacticalPlanner == null)
243 {
244
245 this.tacticalPlanner = this.strategicalPlanner.generateTacticalPlanner(this);
246 }
247 this.operationalPlan = this.tacticalPlanner.generateOperationalPlan(this, now, fromLocation);
248
249
250
251 this.nextMoveEvent =
252 new SimEvent<>(new OTSSimTimeDouble(now.plus(this.operationalPlan.getTotalDuration())), this, this, "move",
253 new Object[]{this.operationalPlan.getEndLocation()});
254 this.simulator.scheduleEvent(this.nextMoveEvent);
255 }
256
257
258
259
260
261
262
263
264
265
266 @SuppressWarnings("checkstyle:designforextension")
267 protected void interruptMove() throws SimRuntimeException, OperationalPlanException, GTUException, NetworkException
268 {
269 this.simulator.cancelEvent(this.nextMoveEvent);
270 move(this.operationalPlan.getLocation(this.simulator.getSimulatorTime().getTime()));
271 }
272
273
274 @Override
275 public final String getId()
276 {
277 return this.id;
278 }
279
280
281 @SuppressWarnings("checkstyle:designforextension")
282 @Override
283 public GTUType getGTUType()
284 {
285 return this.gtuType;
286 }
287
288
289 @Override
290 public final RelativePosition getReference()
291 {
292 return RelativePosition.REFERENCE_POSITION;
293 }
294
295
296
297
298 public final OTSDEVSSimulatorInterface getSimulator()
299 {
300 return this.simulator;
301 }
302
303
304
305
306
307 @SuppressWarnings("checkstyle:designforextension")
308 public StrategicalPlanner getStrategicalPlanner()
309 {
310 return this.strategicalPlanner;
311 }
312
313
314
315
316 public final TacticalPlanner getTacticalPlanner()
317 {
318 return this.tacticalPlanner;
319 }
320
321
322
323
324 public final OperationalPlan getOperationalPlan()
325 {
326 return this.operationalPlan;
327 }
328
329
330 @Override
331 @SuppressWarnings("checkstyle:designforextension")
332 public Perception getPerception()
333 {
334 return this.perception;
335 }
336
337
338 @Override
339 public final Length.Rel getOdometer()
340 {
341 if (this.operationalPlan == null)
342 {
343 return this.odometer;
344 }
345 try
346 {
347 return this.odometer.plus(this.operationalPlan.getTraveledDistance(this.simulator.getSimulatorTime()
348 .getTime()));
349 }
350 catch (OperationalPlanException ope)
351 {
352 return this.odometer;
353 }
354 }
355
356
357 @Override
358 public final Speed getVelocity(final Time.Abs time)
359 {
360 if (this.operationalPlan == null)
361 {
362 return Speed.ZERO;
363 }
364 try
365 {
366 return this.operationalPlan.getVelocity(time);
367 }
368 catch (OperationalPlanException ope)
369 {
370
371 try
372 {
373 return this.operationalPlan.getVelocity(this.operationalPlan.getTotalDuration());
374 }
375 catch (OperationalPlanException ope2)
376 {
377
378 throw new RuntimeException(
379 "getVelocity() could not derive a valid velocity for the current operationalPlan", ope2);
380 }
381 }
382 }
383
384
385 @Override
386 public final Speed getVelocity()
387 {
388 return getVelocity(this.simulator.getSimulatorTime().getTime());
389 }
390
391
392 @Override
393 public final Acceleration getAcceleration(final Time.Abs time)
394 {
395 if (this.operationalPlan == null)
396 {
397 return Acceleration.ZERO;
398 }
399 try
400 {
401 return this.operationalPlan.getAcceleration(time);
402 }
403 catch (OperationalPlanException ope)
404 {
405
406 try
407 {
408 return this.operationalPlan.getAcceleration(this.operationalPlan.getTotalDuration());
409 }
410 catch (OperationalPlanException ope2)
411 {
412
413 throw new RuntimeException(
414 "getAcceleration() could not derive a valid acceleration for the current operationalPlan", ope2);
415 }
416 }
417 }
418
419
420
421
422 public final Acceleration getMaximumAcceleration()
423 {
424 return this.maximumAcceleration;
425 }
426
427
428
429
430 public final void setMaximumAcceleration(final Acceleration maximumAcceleration)
431 {
432 if (maximumAcceleration.le(Acceleration.ZERO))
433 {
434 throw new RuntimeException("Maximum acceleration of GTU " + this.id + " set to value <= 0");
435 }
436 this.maximumAcceleration = maximumAcceleration;
437 }
438
439
440
441
442 public final Acceleration getMaximumDeceleration()
443 {
444 return this.maximumDeceleration;
445 }
446
447
448
449
450 public final void setMaximumDeceleration(final Acceleration maximumDeceleration)
451 {
452 if (maximumDeceleration.ge(Acceleration.ZERO))
453 {
454 throw new RuntimeException("Maximum deceleration of GTU " + this.id + " set to value >= 0");
455 }
456 this.maximumDeceleration = maximumDeceleration;
457 }
458
459
460 @Override
461 public final Acceleration getAcceleration()
462 {
463 return getAcceleration(this.simulator.getSimulatorTime().getTime());
464 }
465
466
467 @Override
468 @SuppressWarnings("checkstyle:designforextension")
469 public DirectedPoint getLocation()
470 {
471 if (this.operationalPlan == null)
472 {
473 System.err.println("No operational plan");
474 return new DirectedPoint(0, 0, 0);
475 }
476 try
477 {
478 return this.operationalPlan.getLocation(this.simulator.getSimulatorTime().getTime());
479 }
480 catch (OperationalPlanException exception)
481 {
482 return new DirectedPoint(0, 0, 0);
483 }
484 }
485
486
487 @Override
488 public final TurnIndicatorStatus getTurnIndicatorStatus()
489 {
490 if (!getGTUType().hasTurnIndicator())
491 {
492 return TurnIndicatorStatus.NOTPRESENT;
493 }
494 return this.turnIndicatorStatus;
495 }
496
497
498 @Override
499 public final void setTurnIndicatorStatus(final TurnIndicatorStatus turnIndicatorStatus) throws GTUException
500 {
501 if (!getGTUType().hasTurnIndicator())
502 {
503 throw new GTUException("trying to set the TurnIndicatorStatus on GTU: " + getId() + ", but GTUType "
504 + getGTUType().getId() + " has no TurnIndicator");
505 }
506 this.turnIndicatorStatus = turnIndicatorStatus;
507 }
508
509
510
511
512 public final boolean isDestroyed()
513 {
514 return this.destroyed;
515 }
516
517
518
519
520 public final PerceivableContext getPerceivableContext()
521 {
522 return this.perceivableContext;
523 }
524
525 }