View Javadoc
1   package org.opentrafficsim.road.network.lane.conflict;
2   
3   import java.rmi.RemoteException;
4   import java.util.UUID;
5   
6   import javax.naming.NamingException;
7   
8   import org.djunits.unit.LengthUnit;
9   import org.djunits.value.vdouble.scalar.Length;
10  import org.opentrafficsim.core.dsol.OTSDEVSSimulatorInterface;
11  import org.opentrafficsim.core.dsol.OTSSimulatorInterface;
12  import org.opentrafficsim.core.geometry.OTSGeometryException;
13  import org.opentrafficsim.core.geometry.OTSLine3D;
14  import org.opentrafficsim.core.geometry.OTSPoint3D;
15  import org.opentrafficsim.core.gtu.GTUDirectionality;
16  import org.opentrafficsim.core.gtu.GTUType;
17  import org.opentrafficsim.core.network.LongitudinalDirectionality;
18  import org.opentrafficsim.core.network.NetworkException;
19  import org.opentrafficsim.road.network.animation.ConflictAnimation;
20  import org.opentrafficsim.road.network.lane.CrossSectionElement;
21  import org.opentrafficsim.road.network.lane.Lane;
22  import org.opentrafficsim.road.network.lane.object.AbstractLaneBasedObject;
23  
24  import nl.tudelft.simulation.language.Throw;
25  
26  /**
27   * Conflicts deal with traffic on different links/roads that need to consider each other as their paths may be in conflict
28   * spatially. A single {@code Conflict} represents the one-sided consideration of a conflicting situation. I.e., what is
29   * considered <i>a single conflict in traffic theory, is represented by two {@code Conflict}s</i>, one on each of the
30   * conflicting {@code Lane}s.
31   * <p>
32   * Copyright (c) 2013-2016 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved. <br>
33   * BSD-style license. See <a href="http://opentrafficsim.org/docs/current/license.html">OpenTrafficSim License</a>.
34   * <p>
35   * @version $Revision$, $LastChangedDate$, by $Author$, initial version Sep 7, 2016 <br>
36   * @author <a href="http://www.tbm.tudelft.nl/averbraeck">Alexander Verbraeck</a>
37   * @author <a href="http://www.tudelft.nl/pknoppers">Peter Knoppers</a>
38   * @author <a href="http://www.transport.citg.tudelft.nl">Wouter Schakel</a>
39   */
40  public final class Conflict extends AbstractLaneBasedObject
41  {
42  
43      /** */
44      private static final long serialVersionUID = 20160915L;
45  
46      /** Conflict type, i.e. crossing, merge or split. */
47      private final ConflictType conflictType;
48  
49      /** Conflict rule, i.e. priority, give way, stop or all-stop. */
50      private final ConflictRule conflictRule;
51  
52      /** Accompanying other conflict. */
53      private Conflict otherConflict;
54  
55      /** The length of the conflict along the lane centerline. */
56      private final Length length;
57  
58      /** GTU direction. */
59      private final GTUDirectionality direction;
60  
61      /** Simulator for animation and timed events. */
62      private final OTSDEVSSimulatorInterface simulator;
63  
64      /** GTU type. */
65      private final GTUType gtuType;
66  
67      /** Whether the conflict is a permitted conflict in traffic light control. */
68      private final boolean permitted;
69  
70      /** Lock object for cloning a pair of conflicts. */
71      private final Object cloneLock;
72  
73      /**
74       * @param lane lane where this conflict starts
75       * @param longitudinalPosition position of start of conflict on lane
76       * @param length length of the conflict along the lane centerline
77       * @param direction GTU direction
78       * @param geometry geometry of conflict
79       * @param conflictRule conflict rule, i.e. priority, give way, stop or all-stop
80       * @param conflictType conflict type, i.e. crossing, merge or split
81       * @param simulator the simulator for animation and timed events
82       * @param permitted whether the conflict is permitted in traffic light control
83       * @param gtuType gtu type
84       * @param cloneLock lock object for cloning a pair of conflicts
85       * @throws NetworkException when the position on the lane is out of bounds
86       */
87      @SuppressWarnings("checkstyle:parameternumber")
88      private Conflict(final Lane lane, final Length longitudinalPosition, final Length length, final GTUDirectionality direction,
89              final OTSLine3D geometry, final ConflictType conflictType, final ConflictRule conflictRule,
90              final OTSDEVSSimulatorInterface simulator, final GTUType gtuType, final boolean permitted, final Object cloneLock)
91              throws NetworkException
92      {
93          super(UUID.randomUUID().toString(), lane, Throw.whenNull(direction, "Direction may not be null.").isPlus()
94                  ? LongitudinalDirectionality.DIR_PLUS : LongitudinalDirectionality.DIR_MINUS, longitudinalPosition, geometry);
95          this.length = length;
96          this.direction = direction;
97          this.conflictType = conflictType;
98          this.conflictRule = conflictRule;
99          this.simulator = simulator;
100         this.gtuType = gtuType;
101         this.permitted = permitted;
102         this.cloneLock = cloneLock;
103 
104         try
105         {
106             new ConflictAnimation(this, simulator);
107         }
108         catch (RemoteException | NamingException exception)
109         {
110             throw new NetworkException(exception);
111         }
112 
113         // Create conflict end
114         if (conflictType.equals(ConflictType.SPLIT) || conflictType.equals(ConflictType.MERGE))
115         {
116             Length position =
117                     conflictType.equals(ConflictType.SPLIT) ? (direction.isPlus() ? length : lane.getLength().minus(length))
118                             : (direction.isPlus() ? lane.getLength() : Length.ZERO);
119             try
120             {
121                 new ConflictEnd(this, lane,
122                         direction.isPlus() ? LongitudinalDirectionality.DIR_PLUS : LongitudinalDirectionality.DIR_MINUS,
123                         position);
124             }
125             catch (OTSGeometryException exception)
126             {
127                 // does not happen
128                 throw new RuntimeException("Could not create dummy geometry for ConflictEnd.", exception);
129             }
130         }
131     }
132 
133     /**
134      * @return conflictType.
135      */
136     public ConflictType getConflictType()
137     {
138         return this.conflictType;
139     }
140 
141     /**
142      * @return conflictRule.
143      */
144     public ConflictRule getConflictRule()
145     {
146         return this.conflictRule;
147     }
148 
149     /**
150      * @return length.
151      */
152     public Length getLength()
153     {
154         return this.length;
155     }
156 
157     /**
158      * @return otherConflict.
159      */
160     public Conflict getOtherConflict()
161     {
162         return this.otherConflict;
163     }
164 
165     /**
166      * @return gtuType.
167      */
168     public GTUType getGtuType()
169     {
170         return this.gtuType;
171     }
172 
173     /**
174      * If permitted, traffic upstream of traffic lights may not be ignored, as these can have green light.
175      * @return permitted.
176      */
177     public boolean isPermitted()
178     {
179         return this.permitted;
180     }
181 
182     /**
183      * Creates a pair of conflicts.
184      * @param conflictType conflict type, i.e. crossing, merge or split
185      * @param permitted whether the conflict is permitted in traffic light control
186      * @param lane1 lane of conflict 1
187      * @param longitudinalPosition1 longitudinal position of conflict 1
188      * @param length1 {@code Length} of conflict 1
189      * @param direction1 GTU direction of conflict 1
190      * @param geometry1 geometry of conflict 1
191      * @param conflictRule1 conflict rule of conflict 1
192      * @param gtuType1 gtu type of conflict 1
193      * @param lane2 lane of conflict 2
194      * @param longitudinalPosition2 longitudinal position of conflict 2
195      * @param length2 {@code Length} of conflict 2
196      * @param direction2 GTU direction of conflict 2
197      * @param geometry2 geometry of conflict 2
198      * @param conflictRule2 conflict rule of conflict 2
199      * @param gtuType2 gtu type of conflict 2
200      * @param simulator the simulator for animation and timed events
201      * @throws NetworkException if the combination of conflict type and both conflict rules is not correct
202      */
203     @SuppressWarnings("checkstyle:parameternumber")
204     public static void generateConflictPair(final ConflictType conflictType, final boolean permitted, final Lane lane1,
205             final Length longitudinalPosition1, final Length length1, final GTUDirectionality direction1,
206             final OTSLine3D geometry1, final ConflictRule conflictRule1, final GTUType gtuType1, final Lane lane2,
207             final Length longitudinalPosition2, final Length length2, final GTUDirectionality direction2,
208             final OTSLine3D geometry2, final ConflictRule conflictRule2, final GTUType gtuType2,
209             final OTSDEVSSimulatorInterface simulator) throws NetworkException
210     {
211         // lane, longitudinalPosition, length and geometry are checked in AbstractLaneBasedObject
212         Throw.whenNull(conflictType, "Conflict type may not be null.");
213         Throw.whenNull(conflictRule1, "Conflict rule may not be null.");
214         Throw.whenNull(conflictRule2, "Conflict rule may not be null.");
215         if (conflictType.equals(ConflictType.SPLIT))
216         {
217             // Split with split (on split)
218             Throw.when(!conflictRule1.equals(ConflictRule.SPLIT) || !conflictRule2.equals(ConflictRule.SPLIT),
219                     NetworkException.class, "Both conflict rules should be split for conflict type split.");
220         }
221         else
222         {
223             // Priority with give-way/stop
224             boolean check1 = conflictRule1.equals(ConflictRule.PRIORITY) && !conflictRule2.equals(ConflictRule.GIVE_WAY)
225                     && !conflictRule2.equals(ConflictRule.STOP);
226             boolean check2 = conflictRule2.equals(ConflictRule.PRIORITY) && !conflictRule1.equals(ConflictRule.GIVE_WAY)
227                     && !conflictRule1.equals(ConflictRule.STOP);
228             boolean check3 = conflictRule1.equals(ConflictRule.GIVE_WAY) && !conflictRule2.equals(ConflictRule.PRIORITY);
229             boolean check4 = conflictRule2.equals(ConflictRule.GIVE_WAY) && !conflictRule1.equals(ConflictRule.PRIORITY);
230             boolean check5 = conflictRule1.equals(ConflictRule.STOP) && !conflictRule2.equals(ConflictRule.PRIORITY);
231             boolean check6 = conflictRule2.equals(ConflictRule.STOP) && !conflictRule1.equals(ConflictRule.PRIORITY);
232             Throw.when(check1 || check2 || check3 || check4 || check5 || check6, NetworkException.class,
233                     "Conflict rules need to be a combination of 'PRIORITY' and 'GIVE_WAY' or 'STOP', "
234                             + "if any of these types is used.");
235             // All-stop with all-stop
236             boolean check7 = conflictRule1.equals(ConflictRule.ALL_STOP) && !conflictRule2.equals(ConflictRule.ALL_STOP);
237             boolean check8 = conflictRule2.equals(ConflictRule.ALL_STOP) && !conflictRule1.equals(ConflictRule.ALL_STOP);
238             Throw.when(check7 || check8, NetworkException.class,
239                     "Conflict rule 'ALL_STOP' can only be combined with a conflict rule 'ALL_STOP'.");
240             // No split
241             Throw.when(conflictRule1.equals(ConflictRule.SPLIT) || conflictRule2.equals(ConflictRule.SPLIT),
242                     NetworkException.class, "Conflict rule 'SPLIT' may only be used on conflicts of type SPLIT.");
243         }
244         Object cloneLock = new Object();
245         Conflict conf1 = new Conflict(lane1, longitudinalPosition1, length1, direction1, geometry1, conflictType, conflictRule1,
246                 simulator, gtuType1, permitted, cloneLock);
247         Conflict conf2 = new Conflict(lane2, longitudinalPosition2, length2, direction2, geometry2, conflictType, conflictRule2,
248                 simulator, gtuType2, permitted, cloneLock);
249         conf1.otherConflict = conf2;
250         conf2.otherConflict = conf1;
251     }
252 
253     /** {@inheritDoc} */
254     @Override
255     public String toString()
256     {
257         return "Conflict [conflictType=" + this.conflictType + ", conflictRule=" + this.conflictRule + "]";
258     }
259 
260     /**
261      * Clone of other conflict.
262      */
263     private Conflict otherClone;
264 
265     /** {@inheritDoc} */
266     @Override
267     public Conflict clone(final CrossSectionElement newCSE, final OTSSimulatorInterface newSimulator, final boolean animation)
268             throws NetworkException
269     {
270         Throw.when(!(newCSE instanceof Lane), NetworkException.class, "sensors can only be cloned for Lanes");
271         Throw.when(!(newSimulator instanceof OTSDEVSSimulatorInterface), NetworkException.class,
272                 "simulator should be a DEVSSimulator");
273         Conflict out = new Conflict((Lane) newCSE, getLongitudinalPosition(), this.length, this.direction, getGeometry(),
274                 this.conflictType, this.conflictRule, this.simulator, this.gtuType, this.permitted, this.cloneLock);
275         synchronized (this.cloneLock)
276         {
277             // couple both clones
278             if (this.otherClone == null || this.otherClone.simulator != newSimulator)
279             {
280                 // other clone will do it
281                 this.otherConflict.otherClone = out;
282             }
283             else
284             {
285                 out.otherConflict = this.otherClone;
286                 this.otherClone.otherConflict = out;
287             }
288             // reset successful clone of pair, or remove otherClone from other simulator (or was already null)
289             this.otherClone = null;
290         }
291         return out;
292     }
293 
294     /**
295      * <p>
296      * Copyright (c) 2013-2016 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved.
297      * <br>
298      * BSD-style license. See <a href="http://opentrafficsim.org/node/13">OpenTrafficSim License</a>.
299      * <p>
300      * @version $Revision$, $LastChangedDate$, by $Author$, initial version 14 dec. 2016 <br>
301      * @author <a href="http://www.tbm.tudelft.nl/averbraeck">Alexander Verbraeck</a>
302      * @author <a href="http://www.tudelft.nl/pknoppers">Peter Knoppers</a>
303      * @author <a href="http://www.transport.citg.tudelft.nl">Wouter Schakel</a>
304      */
305     public class ConflictEnd extends AbstractLaneBasedObject
306     {
307 
308         /** */
309         private static final long serialVersionUID = 20161214L;
310 
311         /** Conflict. */
312         private final Conflict conflict;
313 
314         /**
315          * @param conflict conflict
316          * @param lane lane
317          * @param direction valid direction
318          * @param longitudinalPosition position
319          * @throws NetworkException on network exception
320          * @throws OTSGeometryException does not happen
321          */
322         ConflictEnd(final Conflict conflict, final Lane lane, final LongitudinalDirectionality direction,
323                 final Length longitudinalPosition) throws NetworkException, OTSGeometryException
324         {
325             super(conflict.getId() + "End", lane, direction, longitudinalPosition,
326                     new OTSLine3D(new OTSPoint3D(0, 0, 0), new OTSPoint3D(1, 0, 0)));
327             this.conflict = conflict;
328         }
329 
330         /**
331          * @return conflict
332          */
333         public final Conflict getConflict()
334         {
335             return this.conflict;
336         }
337 
338         /** {@inheritDoc} */
339         @Override
340         public final AbstractLaneBasedObject clone(final CrossSectionElement newCSE, final OTSSimulatorInterface newSimulator,
341                 final boolean animation) throws NetworkException
342         {
343             // Constructor of Conflict creates these.
344             return null;
345         }
346 
347     }
348 
349 }