1   package org.opentrafficsim.road.network.lane;
2   
3   import java.math.BigInteger;
4   import java.util.ArrayList;
5   import java.util.Collection;
6   import java.util.LinkedHashMap;
7   import java.util.LinkedHashSet;
8   import java.util.List;
9   import java.util.Map;
10  import java.util.Set;
11  
12  import org.djunits.value.vdouble.scalar.Length;
13  import org.djutils.exceptions.Throw;
14  import org.opentrafficsim.base.StripeElement;
15  import org.opentrafficsim.base.StripeElement.StripeLateralSync;
16  import org.opentrafficsim.core.gtu.GtuType;
17  import org.opentrafficsim.core.network.LateralDirectionality;
18  
19  
20  
21  
22  
23  
24  
25  
26  
27  public class StripeData
28  {
29  
30      
31      private List<StripeElement> elements;
32  
33      
34      private final boolean left;
35  
36      
37      private final boolean right;
38  
39      
40      private final Map<GtuType, Set<LateralDirectionality>> permeabilityMap = new LinkedHashMap<>();
41  
42      
43      private StripeLateralSync lateralSync = StripeLateralSync.LINK;
44  
45      
46      private StripePhaseSync phaseSync = StripePhaseSync.NONE;
47  
48      
49      private Double period;
50  
51      
52  
53  
54  
55  
56  
57      public StripeData(final List<StripeElement> elements, final boolean left, final boolean right)
58      {
59          this.elements = elements;
60          this.left = left;
61          this.right = right;
62      }
63  
64      
65  
66  
67  
68      public List<StripeElement> getElements()
69      {
70          return this.elements;
71      }
72      
73      
74  
75  
76  
77      public void setElements(final List<StripeElement> elements)
78      {
79          this.elements = elements;
80          this.period = null;
81      }
82  
83      
84  
85  
86  
87  
88  
89  
90      public void addPermeability(final GtuType gtuType, final LateralDirectionality lateralDirection)
91      {
92          if (!this.permeabilityMap.containsKey(gtuType))
93          {
94              this.permeabilityMap.put(gtuType, new LinkedHashSet<LateralDirectionality>(2));
95          }
96          this.permeabilityMap.get(gtuType).add(lateralDirection);
97      }
98  
99      
100 
101 
102 
103 
104 
105     public final boolean isPermeable(final GtuType gtuType, final LateralDirectionality lateralDirection)
106     {
107         Throw.when(lateralDirection.isNone(), RuntimeException.class,
108                 "May not request NONE lateral direction for permeability.");
109         for (GtuType testGtuType = gtuType; null != testGtuType; testGtuType = testGtuType.getParent())
110         {
111             Set<LateralDirectionality> set = this.permeabilityMap.get(testGtuType);
112             if (null != set)
113             {
114                 return set.contains(lateralDirection);
115             }
116         }
117         return lateralDirection.isLeft() ? this.left : this.right;
118     }
119 
120     
121 
122 
123 
124     public void setLateralSync(final StripeLateralSync lateralSync)
125     {
126         this.lateralSync = lateralSync;
127     }
128 
129     
130 
131 
132 
133     public StripeLateralSync getLateralSync()
134     {
135         return this.lateralSync;
136     }
137 
138     
139 
140 
141 
142     public void setPhaseSync(final StripePhaseSync phaseSync)
143     {
144         this.phaseSync = phaseSync;
145     }
146 
147     
148 
149 
150 
151     public StripePhaseSync getPhaseSync()
152     {
153         return this.phaseSync;
154     }
155 
156     
157 
158 
159 
160     public double getPeriod()
161     {
162         if (this.period == null)
163         {
164             this.period = getPeriod(this.elements);
165         }
166         return this.period;
167     }
168     
169     
170 
171 
172 
173 
174 
175     public static double getPeriod(final List<StripeElement> elements)
176     {
177         List<Double> lineLengths = new ArrayList<>();
178         for (StripeElement element : elements)
179         {
180             if (element.dashes() != null)
181             {
182                 double length = 0.0;
183                 for (Length gapDash : element.dashes())
184                 {
185                     length += gapDash.si;
186                 }
187                 lineLengths.add(length);
188             }
189         }
190         return getPeriod(lineLengths);
191     }
192 
193     
194 
195 
196 
197 
198 
199     private static double getPeriod(final Collection<Double> lineLengths)
200     {
201         Set<Double> set = new LinkedHashSet<>(lineLengths);
202         if (lineLengths.isEmpty())
203         {
204             return -1.0;
205         }
206         else if (set.size() == 1)
207         {
208             return ((long) (lineLengths.iterator().next() * 10000)) / 10000.0;
209         }
210         long gcd = 1L;
211         for (double length : set)
212         {
213             gcd = BigInteger.valueOf(gcd).gcd(BigInteger.valueOf((long) (length * 10000))).longValue();
214         }
215         return gcd / 10000.0;
216     }
217     
218     
219 
220 
221 
222     public Length getWidth()
223     {
224         Length width = Length.ZERO;
225         for (StripeElement element : getElements())
226         {
227             width = width.plus(element.width());
228         }
229         return width;
230     }
231 
232     
233 
234 
235     public enum StripePhaseSync
236     {
237         
238         NONE(false),
239 
240         
241         UPSTREAM(true),
242 
243         
244         DOWNSTREAM(true);
245 
246         
247         private final boolean sync;
248 
249         
250 
251 
252 
253         StripePhaseSync(final boolean sync)
254         {
255             this.sync = sync;
256         }
257 
258         
259 
260 
261 
262         public boolean isSync()
263         {
264             return this.sync;
265         }
266     }
267 
268 }