View Javadoc
1   package org.opentrafficsim.road.gtu;
2   
3   import java.util.Iterator;
4   
5   import org.djunits.value.vdouble.scalar.Angle;
6   import org.djunits.value.vdouble.scalar.Length;
7   import org.djunits.value.vdouble.scalar.Speed;
8   import org.djutils.event.EventListenerMap;
9   import org.djutils.event.EventProducer;
10  import org.djutils.event.EventType;
11  import org.djutils.math.AngleUtil;
12  import org.djutils.metadata.MetaData;
13  import org.djutils.metadata.ObjectDescriptor;
14  import org.opentrafficsim.base.DistancedObject;
15  import org.opentrafficsim.base.logger.Logger;
16  import org.opentrafficsim.core.gtu.Gtu;
17  import org.opentrafficsim.core.gtu.GtuException;
18  import org.opentrafficsim.core.gtu.plan.operational.OperationalPlanException;
19  import org.opentrafficsim.core.network.Network;
20  import org.opentrafficsim.road.gtu.perception.PerceptionCollectable;
21  import org.opentrafficsim.road.gtu.perception.RelativeLane;
22  import org.opentrafficsim.road.gtu.perception.categories.neighbors.NeighborsPerception;
23  import org.opentrafficsim.road.gtu.perception.object.PerceivedGtu;
24  import org.opentrafficsim.road.network.object.LaneBasedObject;
25  
26  /**
27   * Checks for collisions.
28   * <p>
29   * Copyright (c) 2013-2026 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved. <br>
30   * BSD-style license. See <a href="https://opentrafficsim.org/docs/license.html">OpenTrafficSim License</a>.
31   * </p>
32   * @author Alexander Verbraeck
33   * @author Peter Knoppers
34   * @author Wouter Schakel
35   */
36  public class CollisionDetector extends AbstractLaneBasedMoveChecker implements EventProducer
37  {
38  
39      /** Collision event. */
40      public static final EventType COLLISION = new EventType(new MetaData("COLLISION",
41              "Event when a GTU collides into an object", new ObjectDescriptor("GTU", "Colliding GTU", LaneBasedGtu.class),
42              new ObjectDescriptor("Object", "Object that is collided into", LaneBasedObject.class)));
43  
44      /** Listener map. */
45      private final EventListenerMap listenerMap = new EventListenerMap();
46  
47      /**
48       * Constructor.
49       * @param network network
50       */
51      public CollisionDetector(final Network network)
52      {
53          super(network);
54      }
55  
56      @Override
57      public void checkMove(final LaneBasedGtu gtu) throws Exception
58      {
59          try
60          {
61              NeighborsPerception neighbors =
62                      gtu.getTacticalPlanner().getPerception().getPerceptionCategory(NeighborsPerception.class);
63              PerceptionCollectable<PerceivedGtu, LaneBasedGtu> leaders = neighbors.getLeaders(RelativeLane.CURRENT);
64              Iterator<DistancedObject<LaneBasedGtu>> gtus = leaders.underlyingWithDistance();
65              if (!gtus.hasNext())
66              {
67                  return;
68              }
69              DistancedObject<LaneBasedGtu> leader = gtus.next();
70              if (leader.distance().lt0())
71              {
72                  fireEvent(COLLISION, new Object[] {gtu, leader.object()});
73  
74                  // throw new CollisionException("GTU " + gtu.getId() + " collided with GTU " + leader.object().getId());
75              }
76          }
77          catch (OperationalPlanException exception)
78          {
79              throw new GtuException(exception);
80          }
81      }
82  
83      @Override
84      public EventListenerMap getEventListenerMap()
85      {
86          return this.listenerMap;
87      }
88  
89      /**
90       * Logs collision with distance, speed difference and angle at info level.
91       * @return this collision detector for method chaining
92       */
93      public CollisionDetector logCollisions()
94      {
95          addListener((e) ->
96          {
97              Object[] payload = (Object[]) e.getContent();
98              LaneBasedGtu gtu = (LaneBasedGtu) payload[0];
99              LaneBasedObject object = (LaneBasedObject) payload[1];
100             Speed objectSpeed = object instanceof Gtu otherGtu ? otherGtu.getSpeed() : Speed.ZERO;
101             Speed dv = gtu.getSpeed().minus(objectSpeed);
102             Length distance = Length.ofSI(gtu.getLocation().distance(object.getLocation()));
103             Angle angle = Angle.ofSI(AngleUtil.normalizeAroundZero(object.getDirZ() - gtu.getDirZ()));
104             Logger.ots().info("GTU " + gtu.getId() + " collided with " + object.getId() + " at a point distance of " + distance
105                     + " with a speed difference of " + dv + " and and angle of " + angle + ".");
106         }, COLLISION);
107         return this;
108     }
109 
110     /**
111      * Stops the GTU and the object if it is a GTU.
112      * @return this collision detector for method chaining
113      */
114     public CollisionDetector stopCollided()
115     {
116         addListener((e) ->
117         {
118             Object[] payload = (Object[]) e.getContent();
119             LaneBasedGtu gtu = (LaneBasedGtu) payload[0];
120             LaneBasedObject object = (LaneBasedObject) payload[1];
121             gtu.stop();
122             if (object instanceof LaneBasedGtu otherGtu)
123             {
124                 otherGtu.stop();
125             }
126         }, COLLISION);
127         return this;
128     }
129 
130     /**
131      * Throws an exception upon a collision.
132      * @return this collision detector for method chaining
133      */
134     public CollisionDetector throwException()
135     {
136         addListener((e) ->
137         {
138             Object[] payload = (Object[]) e.getContent();
139             LaneBasedGtu gtu = (LaneBasedGtu) payload[0];
140             LaneBasedObject object = (LaneBasedObject) payload[1];
141             throw new CollisionException("GTU " + gtu.getId() + " collided with " + object.getId());
142         }, COLLISION);
143         return this;
144     }
145 
146     /**
147      * Destroys the GTU upon a collision.
148      * @return this collision detector for method chaining
149      */
150     public CollisionDetector destroyGtu()
151     {
152         addListener((e) -> ((LaneBasedGtu) ((Object[]) e.getContent())[0]).destroy(), COLLISION);
153         return this;
154     }
155 
156 }