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://tudelft.nl/staff/p.knoppers-1">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 I; 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 GtuCompatibility&lt;I&gt;; 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 GtuType; the GtuType to check
58       * @return boolean; 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     /** {@inheritDoc} */
105     @Override
106     public Boolean isCompatibleOnInfraLevel(final GtuType gtuType)
107     {
108         return this.levelCompatibilityMap.get(gtuType);
109     }
110 
111     /**
112      * Add an compatible GtuType to this GtuCompatibility.
113      * @param gtuType GtuType; the GtuType to add to the compatible set of this Compatibility
114      * @return GTUCompatibility&lt;I&gt;; this GtuCompatibility for method call chaining
115      * @throws NullPointerException when <code>gtuType</code> is null
116      * @throws OtsRuntimeException when changes are made to compatibility after results have been cached
117      */
118     public final GtuCompatibility<T> addCompatibleGtuType(final GtuType gtuType) throws NullPointerException
119     {
120         Throw.whenNull(gtuType, "gtuType may not be null");
121         clearCompatibilityCache();
122         this.levelCompatibilityMap.put(gtuType, true);
123         return this;
124     }
125 
126     /**
127      * Add a incompatible GtuType to this GtuCompatibility.
128      * @param gtuType GtuType; the GtuType to add to the incompatible set of this Compatibility
129      * @return GTUCompatibility&lt;I&gt;; this GtuCompatibility for method call chaining
130      * @throws NullPointerException when <code>gtuType</code> is null
131      * @throws OtsRuntimeException when changes are made to compatibility after results have been cached
132      */
133     public final GtuCompatibility<T> addIncompatibleGtuType(final GtuType gtuType) throws NullPointerException
134     {
135         Throw.whenNull(gtuType, "gtuType may not be null");
136         clearCompatibilityCache();
137         this.levelCompatibilityMap.put(gtuType, false);
138         return this;
139     }
140 
141     /** {@inheritDoc} */
142     @Override
143     public T getInfrastructure()
144     {
145         return this.infrastructure;
146     }
147 
148     /** {@inheritDoc} */
149     @Override
150     public void clearCompatibilityCache()
151     {
152         this.cachedCompatibilityMap.clear();
153         for (T infra: getInfrastructure().getChildren())
154         {
155             infra.clearCompatibilityCache();
156         }
157     }
158 
159     /** {@inheritDoc} */
160     @Override
161     public int hashCode()
162     {
163         return Objects.hash(this.infrastructure, this.levelCompatibilityMap);
164     }
165 
166     /** {@inheritDoc} */
167     @Override
168     @SuppressWarnings("checkstyle:needbraces")
169     public boolean equals(final Object obj)
170     {
171         if (this == obj)
172             return true;
173         if (obj == null)
174             return false;
175         if (getClass() != obj.getClass())
176             return false;
177         GtuCompatibility<?> other = (GtuCompatibility<?>) obj;
178         return Objects.equals(this.infrastructure, other.infrastructure)
179                 && Objects.equals(this.levelCompatibilityMap, other.levelCompatibilityMap);
180     }
181 
182     /** {@inheritDoc} */
183     @Override
184     public final String toString()
185     {
186         return "GtuCompatibility [levelCompatibilityMap=" + this.levelCompatibilityMap + "]";
187     }
188 
189 }