View Javadoc
1   package org.opentrafficsim.editor.extensions.map;
2   
3   import java.util.LinkedHashSet;
4   import java.util.Optional;
5   import java.util.Set;
6   
7   import org.djunits.value.vdouble.scalar.Length;
8   import org.opentrafficsim.editor.XsdTreeNode;
9   import org.opentrafficsim.road.network.factory.xml.utils.StripeSynchronization.SynchronizableStripe;
10  import org.opentrafficsim.road.network.lane.Lane;
11  import org.opentrafficsim.road.network.lane.StripeData;
12  import org.opentrafficsim.road.network.lane.StripeData.StripePhaseSync;
13  
14  /**
15   * Representation of a stripe that can be synchronized as used within the editor.
16   * <p>
17   * Copyright (c) 2024-2024 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved. <br>
18   * BSD-style license. See <a href="https://opentrafficsim.org/docs/license.html">OpenTrafficSim License</a>.
19   * </p>
20   * @author <a href="https://github.com/wjschakel">Wouter Schakel</a>
21   */
22  public class SynchronizableMapStripe implements SynchronizableStripe<MapStripeData>
23  {
24      /** Link data. */
25      private final MapLinkData linkData;
26  
27      /** Stripe data. */
28      private final MapStripeData data;
29  
30      /** Synchronization. */
31      private final StripePhaseSync phaseSync;
32  
33      /** Cached period. */
34      private Double period = null;
35  
36      /**
37       * Constructor.
38       * @param linkData link data
39       * @param data stripe data
40       * @param phaseSync synchronization
41       */
42      public SynchronizableMapStripe(final MapLinkData linkData, final MapStripeData data, final StripePhaseSync phaseSync)
43      {
44          this.linkData = linkData;
45          this.data = data;
46          this.phaseSync = phaseSync;
47      }
48  
49      @Override
50      public double getStartPhase()
51      {
52          if (getPeriod() < 0.0)
53          {
54              return 0.0;
55          }
56          return (this.data.getDashOffset().si % getPeriod()) / getPeriod();
57      }
58  
59      @Override
60      public double getEndPhase()
61      {
62          if (getPeriod() < 0.0)
63          {
64              return 0.0;
65          }
66          return ((this.data.getCenterLine().getLength() + this.data.getDashOffset().si) % getPeriod()) / getPeriod();
67      }
68  
69      @Override
70      public double getPeriod()
71      {
72          if (this.period == null)
73          {
74              this.period = StripeData.getPeriod(this.data.getElements());
75          }
76          return this.period;
77      }
78  
79      @Override
80      public MapStripeData getObject()
81      {
82          return this.data;
83      }
84  
85      @Override
86      public Optional<MapStripeData> getUpstreamStripe()
87      {
88          Optional<XsdTreeNode> fromNode = this.linkData.getNode().getCoupledNodeAttribute("NodeStart");
89          if (fromNode.isEmpty())
90          {
91              return Optional.empty();
92          }
93          for (XsdTreeNode networkChild : this.linkData.getNode().getParent().getChildren())
94          {
95              if (networkChild.getNodeName().equals("Link")
96                      && fromNode.get().equals(networkChild.getCoupledNodeAttribute("NodeEnd").orElse(null)))
97              {
98                  Optional<MapData> otherLink = this.linkData.getMap().getData(networkChild);
99                  if (otherLink.isEmpty())
100                 {
101                     return Optional.empty();
102                 }
103                 for (MapStripeData otherStripe : ((MapLinkData) otherLink.get()).getStripeData())
104                 {
105                     if (otherStripe.getCenterLine().getLast().distance(this.data.getCenterLine().getFirst()) < Lane.MARGIN.si)
106                     {
107                         return Optional.of(otherStripe);
108                     }
109                 }
110             }
111         }
112         return Optional.empty();
113     }
114 
115     @Override
116     public Optional<MapStripeData> getDownstreamStripe()
117     {
118         Optional<XsdTreeNode> fromNode = this.linkData.getNode().getCoupledNodeAttribute("NodeEnd");
119         if (fromNode.isEmpty())
120         {
121             return Optional.empty();
122         }
123         for (XsdTreeNode networkChild : this.linkData.getNode().getParent().getChildren())
124         {
125             if (networkChild.getNodeName().equals("Link")
126                     && fromNode.get().equals(networkChild.getCoupledNodeAttribute("NodeStart").orElse(null)))
127             {
128                 Optional<MapData> otherLink = this.linkData.getMap().getData(networkChild);
129                 if (otherLink.isEmpty())
130                 {
131                     return Optional.empty();
132                 }
133                 for (MapStripeData otherStripe : ((MapLinkData) otherLink.get()).getStripeData())
134                 {
135                     if (otherStripe.getCenterLine().getFirst().distance(this.data.getCenterLine().getLast()) < Lane.MARGIN.si)
136                     {
137                         return Optional.of(otherStripe);
138                     }
139                 }
140             }
141         }
142         return Optional.empty();
143     }
144 
145     @Override
146     public Set<MapStripeData> getCommonPhaseStripes()
147     {
148         Set<MapStripeData> out = new LinkedHashSet<>();
149         for (MapStripeData stripe : this.linkData.getStripeData())
150         {
151             SynchronizableMapStripe otherStripe = this.linkData.getMap().getSynchronizableStripes().get(stripe);
152             if (otherStripe != null && !otherStripe.equals(this))
153             {
154                 boolean equalPhaseSync = getSynchronization().equals(otherStripe.getSynchronization());
155                 boolean bothSyncUpOrDown = getSynchronization().isSync();
156                 boolean samePeriod = getPeriod() == otherStripe.getPeriod();
157                 boolean bothLatSyncToLink = this.data.getLateralSync().isLinkBased() && stripe.getLateralSync().isLinkBased();
158                 if (equalPhaseSync && bothSyncUpOrDown && samePeriod && bothLatSyncToLink)
159                 {
160                     out.add(stripe);
161                 }
162             }
163         }
164         return out;
165     }
166 
167     @Override
168     public StripePhaseSync getSynchronization()
169     {
170         return this.phaseSync;
171     }
172 
173     @Override
174     public void setStartPhase(final double phase)
175     {
176         this.data.setDashOffset(Length.ofSI(phase * getPeriod()));
177     }
178 
179     @Override
180     public void setEndPhase(final double phase)
181     {
182         double len = getPeriod() - ((this.data.getCenterLine().getLength() - phase * getPeriod()) % getPeriod());
183         this.data.setDashOffset(Length.ofSI(len));
184     }
185 
186 }