View Javadoc
1   package org.opentrafficsim.core.compatibility;
2   
3   import java.util.LinkedHashMap;
4   import java.util.Map;
5   import java.util.Objects;
6   
7   import org.djutils.exceptions.Throw;
8   import org.opentrafficsim.base.HierarchicalType;
9   import org.opentrafficsim.base.OtsRuntimeException;
10  import org.opentrafficsim.core.gtu.GtuType;
11  
12  /**
13   * Compatibility between a GtuType and a certain type of infrastructure. Infrastructure can be any hierarchical structure: a
14   * LinkType, a LaneType, a SensorType, etc.
15   * <p>
16   * Copyright (c) 2013-2024 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved. <br>
17   * BSD-style license. See <a href="https://opentrafficsim.org/docs/license.html">OpenTrafficSim License</a>.
18   * </p>
19   * @author <a href="https://github.com/averbraeck">Alexander Verbraeck</a>
20   * @author <a href="https://github.com/peter-knoppers">Peter Knoppers</a>
21   * @author <a href="https://github.com/wjschakel">Wouter Schakel</a>
22   * @param <T> infrastructure type, e.g. LinkType or LaneType, or water way type
23   */
24  public class GtuCompatibility<T extends HierarchicalType<T, ?> & Compatibility<GtuType, T>> implements Compatibility<GtuType, T>
25  {
26      /** The map of GtuTypes that define on this infrastructure level what GtuTypes are compatible or not. */
27      private final Map<GtuType, Boolean> levelCompatibilityMap = new LinkedHashMap<>();
28  
29      /** The cached map of GtuTypes that have been resolved. */
30      private final Map<GtuType, Boolean> cachedCompatibilityMap = new LinkedHashMap<>();
31  
32      /** Infrastructure for which this compatibility definition holds, e.g. a LinkType, a LaneType, or a SensorType. */
33      private final T infrastructure;
34  
35      /**
36       * Construct a new Compatibility object with empty compatible and forbidden sets.
37       * @param infrastructure the infrastructure type, e.g. LinkType, LaneType, SensorType.
38       */
39      public GtuCompatibility(final T infrastructure)
40      {
41          Throw.whenNull(infrastructure, "infrastructure cannot be null");
42          this.infrastructure = infrastructure;
43      }
44  
45      /**
46       * Construct a new Compatibility and deep copy the compatible and forbidden sets from an existing Compatibility.
47       * @param original the Compatibility from which the compatible and forbidden sets will be copied
48       */
49      public GtuCompatibility(final GtuCompatibility<T> original)
50      {
51          this.infrastructure = original.infrastructure;
52          this.levelCompatibilityMap.putAll(original.levelCompatibilityMap);
53      }
54  
55      /**
56       * Determine if this Compatibility allows or denies a particular GtuType.
57       * @param gtuType the GtuType to check
58       * @return true if the GtuType is compatible; false if the GtuType is not compatible
59       */
60      @Override
61      public boolean isCompatible(final GtuType gtuType)
62      {
63          if (!this.cachedCompatibilityMap.containsKey(gtuType))
64          {
65              boolean foundTrue = false;
66              boolean foundFalse = false;
67              T infra = this.infrastructure;
68              while (infra != null)
69              {
70                  GtuType gType = gtuType;
71                  while (gType != null)
72                  {
73                      if (infra.isCompatibleOnInfraLevel(gType) != null)
74                      {
75                          if (infra.isCompatibleOnInfraLevel(gType))
76                          {
77                              foundTrue = true;
78                          }
79                          else
80                          {
81                              foundFalse = true;
82                          }
83                      }
84                      gType = gType.getParent();
85                  }
86                  infra = infra.getParent();
87              }
88              if (foundFalse)
89              {
90                  this.cachedCompatibilityMap.put(gtuType, false);
91              }
92              else if (foundTrue)
93              {
94                  this.cachedCompatibilityMap.put(gtuType, true);
95              }
96              else
97              {
98                  this.cachedCompatibilityMap.put(gtuType, false);
99              }
100         }
101         return this.cachedCompatibilityMap.get(gtuType);
102     }
103 
104     @Override
105     public Boolean isCompatibleOnInfraLevel(final GtuType gtuType)
106     {
107         return this.levelCompatibilityMap.get(gtuType);
108     }
109 
110     /**
111      * Add an compatible GtuType to this GtuCompatibility.
112      * @param gtuType the GtuType to add to the compatible set of this Compatibility
113      * @return this GtuCompatibility for method call chaining
114      * @throws NullPointerException when <code>gtuType</code> is null
115      * @throws OtsRuntimeException when changes are made to compatibility after results have been cached
116      */
117     public final GtuCompatibility<T> addCompatibleGtuType(final GtuType gtuType) throws NullPointerException
118     {
119         Throw.whenNull(gtuType, "gtuType may not be null");
120         clearCompatibilityCache();
121         this.levelCompatibilityMap.put(gtuType, true);
122         return this;
123     }
124 
125     /**
126      * Add a incompatible GtuType to this GtuCompatibility.
127      * @param gtuType the GtuType to add to the incompatible set of this Compatibility
128      * @return this GtuCompatibility for method call chaining
129      * @throws NullPointerException when <code>gtuType</code> is null
130      * @throws OtsRuntimeException when changes are made to compatibility after results have been cached
131      */
132     public final GtuCompatibility<T> addIncompatibleGtuType(final GtuType gtuType) throws NullPointerException
133     {
134         Throw.whenNull(gtuType, "gtuType may not be null");
135         clearCompatibilityCache();
136         this.levelCompatibilityMap.put(gtuType, false);
137         return this;
138     }
139 
140     @Override
141     public T getInfrastructure()
142     {
143         return this.infrastructure;
144     }
145 
146     @Override
147     public void clearCompatibilityCache()
148     {
149         this.cachedCompatibilityMap.clear();
150         for (T infra : getInfrastructure().getChildren())
151         {
152             infra.clearCompatibilityCache();
153         }
154     }
155 
156     @Override
157     public int hashCode()
158     {
159         return Objects.hash(this.infrastructure, this.levelCompatibilityMap);
160     }
161 
162     @Override
163     @SuppressWarnings("checkstyle:needbraces")
164     public boolean equals(final Object obj)
165     {
166         if (this == obj)
167             return true;
168         if (obj == null)
169             return false;
170         if (getClass() != obj.getClass())
171             return false;
172         GtuCompatibility<?> other = (GtuCompatibility<?>) obj;
173         return Objects.equals(this.infrastructure, other.infrastructure)
174                 && Objects.equals(this.levelCompatibilityMap, other.levelCompatibilityMap);
175     }
176 
177     @Override
178     public final String toString()
179     {
180         return "GtuCompatibility [levelCompatibilityMap=" + this.levelCompatibilityMap + "]";
181     }
182 
183 }