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
16
17
18
19
20
21
22 public class SynchronizableMapStripe implements SynchronizableStripe<MapStripeData>
23 {
24
25 private final MapLinkData linkData;
26
27
28 private final MapStripeData data;
29
30
31 private final StripePhaseSync phaseSync;
32
33
34 private Double period = null;
35
36
37
38
39
40
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 }