View Javadoc
1   package org.opentrafficsim.road.network.lane.conflict;
2   
3   import java.util.UUID;
4   
5   import org.djunits.value.vdouble.scalar.Length;
6   import org.opentrafficsim.core.dsol.OTSDEVSSimulatorInterface;
7   import org.opentrafficsim.core.dsol.OTSSimulatorInterface;
8   import org.opentrafficsim.core.geometry.OTSLine3D;
9   import org.opentrafficsim.core.network.NetworkException;
10  import org.opentrafficsim.road.network.lane.CrossSectionElement;
11  import org.opentrafficsim.road.network.lane.Lane;
12  import org.opentrafficsim.road.network.lane.object.AbstractLaneBasedObject;
13  
14  import nl.tudelft.simulation.language.Throw;
15  
16  /**
17   * Conflicts deal with traffic on different links/roads that need to consider each other as their paths may be in conflict
18   * spatially. A single {@code Conflict} represents the one-sided consideration of a conflicting situation. I.e., what is
19   * considered <i>a single conflict in traffic theory, is represented by two {@code Conflict}s</i>, one on each of the
20   * conflicting {@code Lane}s.
21   * <p>
22   * Copyright (c) 2013-2016 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved. <br>
23   * BSD-style license. See <a href="http://opentrafficsim.org/docs/current/license.html">OpenTrafficSim License</a>.
24   * <p>
25   * @version $Revision$, $LastChangedDate$, by $Author$, initial version Sep 7, 2016 <br>
26   * @author <a href="http://www.tbm.tudelft.nl/averbraeck">Alexander Verbraeck</a>
27   * @author <a href="http://www.tudelft.nl/pknoppers">Peter Knoppers</a>
28   * @author <a href="http://www.transport.citg.tudelft.nl">Wouter Schakel</a>
29   */
30  public final class Conflict extends AbstractLaneBasedObject
31  {
32  
33      /** */
34      private static final long serialVersionUID = 20160915L;
35  
36      /** Conflict type, i.e. crossing, merge or split. */
37      private final ConflictType conflictType;
38  
39      /** Conflict rule, i.e. priority, give way, stop or all-stop. */
40      private final ConflictRule conflictRule;
41  
42      /** Accompanying other conflict. */
43      private Conflict otherConflict;
44      
45      /** the length of the conflict along the lane centerline. */
46      private final Length length;
47  
48      /**
49       * @param lane lane where this conflict starts
50       * @param longitudinalPosition position of start of conflict on lane
51       * @param length length of the conflict along the lane centerline
52       * @param geometry geometry of conflict
53       * @param conflictRule conflict rule, i.e. priority, give way, stop or all-stop
54       * @param conflictType conflict type, i.e. crossing, merge or split
55       * @throws NetworkException when the position on the lane is out of bounds
56       */
57      private Conflict(final Lane lane, final Length longitudinalPosition, final Length length, final OTSLine3D geometry,
58              final ConflictType conflictType, final ConflictRule conflictRule) throws NetworkException
59      {
60          super(UUID.randomUUID().toString(), lane, longitudinalPosition, geometry);
61          this.length = length;
62          this.conflictType = conflictType;
63          this.conflictRule = conflictRule;
64      }
65  
66      /**
67       * @return conflictType.
68       */
69      public ConflictType getConflictType()
70      {
71          return this.conflictType;
72      }
73  
74      /**
75       * @return conflictRule.
76       */
77      public ConflictRule getConflictRule()
78      {
79          return this.conflictRule;
80      }
81  
82      /**
83       * Creates a pair of conflicts.
84       * @param conflictType conflict type, i.e. crossing, merge or split
85       * @param lane1 lane of conflict 1
86       * @param longitudinalPosition1 longitudinal position of conflict 1
87       * @param length1 {@code Length} of conflict 1
88       * @param geometry1 geometry of conflict 1
89       * @param conflictRule1 conflict rule of conflict 1
90       * @param lane2 lane of conflict 2
91       * @param longitudinalPosition2 longitudinal position of conflict 2
92       * @param length2 {@code Length} of conflict 2
93       * @param geometry2 geometry of conflict 1
94       * @param conflictRule2 conflict rule of conflict 2
95       * @throws NetworkException if the combination of conflict type and both conflict rules is not correct
96       */
97      @SuppressWarnings("checkstyle:parameternumber")
98      public static void generateConflictPair(final ConflictType conflictType, final Lane lane1,
99              final Length longitudinalPosition1, final Length length1, final OTSLine3D geometry1,
100             final ConflictRule conflictRule1, final Lane lane2, final Length longitudinalPosition2, final Length length2,
101             final OTSLine3D geometry2, final ConflictRule conflictRule2) throws NetworkException
102     {
103         // lane, longitudinalPosition, length and geometry are checked in AbstractLaneBasedObject
104         Throw.whenNull(conflictType, "Conflict type may not be null.");
105         Throw.whenNull(conflictRule1, "Conflict rule may not be null.");
106         Throw.whenNull(conflictRule2, "Conflict rule may not be null.");
107         if (conflictType.equals(ConflictType.SPLIT))
108         {
109             // Split with split (on split)
110             Throw.when(!conflictRule1.equals(ConflictRule.SPLIT) || !conflictRule2.equals(ConflictRule.SPLIT),
111                     NetworkException.class, "Both conflict rules should be split for conflict type split.");
112         }
113         else
114         {
115             // Priority with give-way/stop
116             boolean check1 = conflictRule1.equals(ConflictRule.PRIORITY) && !conflictRule2.equals(ConflictRule.GIVE_WAY)
117                     && !conflictRule2.equals(ConflictRule.STOP);
118             boolean check2 = conflictRule2.equals(ConflictRule.PRIORITY) && !conflictRule1.equals(ConflictRule.GIVE_WAY)
119                     && !conflictRule1.equals(ConflictRule.STOP);
120             boolean check3 = conflictRule1.equals(ConflictRule.GIVE_WAY) && !conflictRule2.equals(ConflictRule.PRIORITY);
121             boolean check4 = conflictRule2.equals(ConflictRule.GIVE_WAY) && !conflictRule1.equals(ConflictRule.PRIORITY);
122             boolean check5 = conflictRule1.equals(ConflictRule.STOP) && !conflictRule2.equals(ConflictRule.PRIORITY);
123             boolean check6 = conflictRule2.equals(ConflictRule.STOP) && !conflictRule1.equals(ConflictRule.PRIORITY);
124             Throw.when(check1 || check2 || check3 || check4 || check5 || check6, NetworkException.class,
125                     "Conflict rules need to be a combination of 'PRIORITY' and 'GIVE_WAY' or 'STOP', "
126                             + "if any of these types is used.");
127             // All-stop with all-stop
128             boolean check7 = conflictRule1.equals(ConflictRule.ALL_STOP) && !conflictRule2.equals(ConflictRule.ALL_STOP);
129             boolean check8 = conflictRule2.equals(ConflictRule.ALL_STOP) && !conflictRule1.equals(ConflictRule.ALL_STOP);
130             Throw.when(check7 || check8, NetworkException.class,
131                     "Conflict rule 'ALL_STOP' can only be combined with a conflict rule 'ALL_STOP'.");
132             // No split
133             Throw.when(conflictRule1.equals(ConflictRule.SPLIT) || conflictRule2.equals(ConflictRule.SPLIT),
134                     NetworkException.class, "Conflict rule 'SPLIT' may only be used on conflicts of type SPLIT.");
135         }
136         Conflict conf1 = new Conflict(lane1, longitudinalPosition1, length1, geometry1, conflictType, conflictRule1);
137         Conflict conf2 = new Conflict(lane2, longitudinalPosition2, length2, geometry2, conflictType, conflictRule2);
138         conf1.otherConflict = conf2;
139         conf2.otherConflict = conf1;
140     }
141 
142     /** {@inheritDoc} */
143     @Override
144     public String toString()
145     {
146         return "Conflict [conflictType=" + this.conflictType + ", conflictRule=" + this.conflictRule + ", otherConflict="
147                 + this.otherConflict + "]";
148     }
149 
150     /** {@inheritDoc} */
151     @Override
152     public Conflict clone(final CrossSectionElement newCSE, final OTSSimulatorInterface newSimulator, final boolean animation)
153             throws NetworkException
154     {
155         Throw.when(!(newCSE instanceof Lane), NetworkException.class, "sensors can only be cloned for Lanes");
156         Throw.when(!(newSimulator instanceof OTSDEVSSimulatorInterface), NetworkException.class,
157                 "simulator should be a DEVSSimulator");
158         // TODO conflict needs to be connected to the other cloned conflict
159         return new Conflict((Lane) newCSE, getLongitudinalPosition(), this.length, getGeometry(), this.conflictType,
160                 this.conflictRule);
161     }
162 
163 }