1 package org.opentrafficsim.road.network.factory.xml.parser;
2
3 import java.lang.reflect.Constructor;
4 import java.lang.reflect.InvocationTargetException;
5 import java.util.ArrayList;
6 import java.util.LinkedHashMap;
7 import java.util.List;
8 import java.util.Map;
9 import java.util.UUID;
10
11 import javax.vecmath.Point3d;
12
13 import org.djunits.unit.DirectionUnit;
14 import org.djunits.unit.LengthUnit;
15 import org.djunits.value.vdouble.scalar.Direction;
16 import org.djunits.value.vdouble.scalar.Length;
17 import org.djunits.value.vdouble.scalar.Speed;
18 import org.djutils.reflection.ClassUtil;
19 import org.opentrafficsim.core.dsol.OTSSimulatorInterface;
20 import org.opentrafficsim.core.geometry.Bezier;
21 import org.opentrafficsim.core.geometry.OTSGeometryException;
22 import org.opentrafficsim.core.geometry.OTSLine3D;
23 import org.opentrafficsim.core.geometry.OTSPoint3D;
24 import org.opentrafficsim.core.gtu.GTUException;
25 import org.opentrafficsim.core.gtu.GTUType;
26 import org.opentrafficsim.core.network.LinkType;
27 import org.opentrafficsim.core.network.NetworkException;
28 import org.opentrafficsim.road.network.OTSRoadNetwork;
29 import org.opentrafficsim.road.network.factory.xml.XmlParserException;
30 import org.opentrafficsim.road.network.factory.xml.utils.Cloner;
31 import org.opentrafficsim.road.network.factory.xml.utils.ParseUtil;
32 import org.opentrafficsim.road.network.factory.xml.utils.Transformer;
33 import org.opentrafficsim.road.network.lane.CrossSectionElement;
34 import org.opentrafficsim.road.network.lane.CrossSectionLink;
35 import org.opentrafficsim.road.network.lane.CrossSectionLink.Priority;
36 import org.opentrafficsim.road.network.lane.Lane;
37 import org.opentrafficsim.road.network.lane.LaneType;
38 import org.opentrafficsim.road.network.lane.NoTrafficLane;
39 import org.opentrafficsim.road.network.lane.OTSRoadNode;
40 import org.opentrafficsim.road.network.lane.Shoulder;
41 import org.opentrafficsim.road.network.lane.Stripe;
42 import org.opentrafficsim.road.network.lane.Stripe.Permeable;
43 import org.opentrafficsim.road.network.lane.changing.LaneKeepingPolicy;
44 import org.opentrafficsim.xml.bindings.types.ArcDirection;
45 import org.opentrafficsim.xml.generated.BASICROADLAYOUT;
46 import org.opentrafficsim.xml.generated.CONNECTOR;
47 import org.opentrafficsim.xml.generated.CROSSSECTIONELEMENT;
48 import org.opentrafficsim.xml.generated.CSELANE;
49 import org.opentrafficsim.xml.generated.CSENOTRAFFICLANE;
50 import org.opentrafficsim.xml.generated.CSESHOULDER;
51 import org.opentrafficsim.xml.generated.CSESTRIPE;
52 import org.opentrafficsim.xml.generated.LINK;
53 import org.opentrafficsim.xml.generated.LINK.LANEOVERRIDE;
54 import org.opentrafficsim.xml.generated.NETWORK;
55 import org.opentrafficsim.xml.generated.NODE;
56 import org.opentrafficsim.xml.generated.ROADLAYOUT;
57 import org.opentrafficsim.xml.generated.SPEEDLIMIT;
58 import org.opentrafficsim.xml.generated.TRAFFICLIGHTTYPE;
59
60 import nl.tudelft.simulation.dsol.SimRuntimeException;
61 import nl.tudelft.simulation.dsol.simulators.DEVSSimulatorInterface;
62 import nl.tudelft.simulation.language.d3.DirectedPoint;
63
64
65
66
67
68
69
70
71
72 public final class NetworkParser
73 {
74
75 private NetworkParser()
76 {
77
78 }
79
80
81
82
83
84
85
86
87 public static void parseNodes(final OTSRoadNetwork otsNetwork, final NETWORK network,
88 final Map<String, Direction> nodeDirections) throws NetworkException
89 {
90 for (NODE xmlNode : ParseUtil.getObjectsOfType(network.getIncludeOrNODEOrCONNECTOR(), NODE.class))
91 {
92 new OTSRoadNode(otsNetwork, xmlNode.getID(),
93 new OTSPoint3D(xmlNode.getCOORDINATE().x, xmlNode.getCOORDINATE().y, xmlNode.getCOORDINATE().z),
94 nodeDirections.get(xmlNode.getID()));
95 }
96 }
97
98
99
100
101
102
103
104
105 public static Map<String, Direction> calculateNodeAngles(final OTSRoadNetwork otsNetwork, final NETWORK network)
106 {
107 Map<String, Direction> nodeDirections = new LinkedHashMap<>();
108 Map<String, Point3d> points = new LinkedHashMap<>();
109 for (NODE xmlNode : ParseUtil.getObjectsOfType(network.getIncludeOrNODEOrCONNECTOR(), NODE.class))
110 {
111 if (xmlNode.getDIRECTION() != null)
112 {
113 nodeDirections.put(xmlNode.getID(), xmlNode.getDIRECTION());
114 }
115 points.put(xmlNode.getID(), xmlNode.getCOORDINATE());
116 }
117
118 for (LINK xmlLink : ParseUtil.getObjectsOfType(network.getIncludeOrNODEOrCONNECTOR(), LINK.class))
119 {
120 if (xmlLink.getSTRAIGHT() != null)
121 {
122 Point3d startPoint = points.get(xmlLink.getNODESTART());
123 Point3d endPoint = points.get(xmlLink.getNODEEND());
124 double direction = Math.atan2(endPoint.y - startPoint.y, endPoint.x - startPoint.x);
125 if (!nodeDirections.containsKey(xmlLink.getNODESTART()))
126 {
127 nodeDirections.put(xmlLink.getNODESTART(), new Direction(direction, DirectionUnit.EAST_RADIAN));
128 }
129 if (!nodeDirections.containsKey(xmlLink.getNODEEND()))
130 {
131 nodeDirections.put(xmlLink.getNODEEND(), new Direction(direction, DirectionUnit.EAST_RADIAN));
132 }
133 }
134 }
135
136 for (NODE xmlNode : ParseUtil.getObjectsOfType(network.getIncludeOrNODEOrCONNECTOR(), NODE.class))
137 {
138 if (!nodeDirections.containsKey(xmlNode.getID()))
139 {
140 System.err.println("Warning: Node " + xmlNode.getID() + " does not have a (calculated) direction");
141 }
142 }
143
144 return nodeDirections;
145 }
146
147
148
149
150
151
152
153
154
155
156 static void parseLinks(final OTSRoadNetwork otsNetwork, final NETWORK network, final Map<String, Direction> nodeDirections,
157 final OTSSimulatorInterface simulator) throws NetworkException, OTSGeometryException
158 {
159 for (CONNECTOR xmlConnector : ParseUtil.getObjectsOfType(network.getIncludeOrNODEOrCONNECTOR(), CONNECTOR.class))
160 {
161 OTSRoadNode startNode = (OTSRoadNode) otsNetwork.getNode(xmlConnector.getNODESTART());
162 if (null == startNode)
163 {
164 simulator.getLogger().always()
165 .debug("No start node (" + xmlConnector.getNODESTART() + ") for CONNECTOR " + xmlConnector.getID());
166 }
167 OTSRoadNode endNode = (OTSRoadNode) otsNetwork.getNode(xmlConnector.getNODEEND());
168 if (null == endNode)
169 {
170 simulator.getLogger().always()
171 .debug("No end node (" + xmlConnector.getNODEEND() + ")for CONNECTOR " + xmlConnector.getID());
172 }
173 String id = xmlConnector.getID();
174 double demandWeight = xmlConnector.getDEMANDWEIGHT();
175 OTSLine3D designLine = new OTSLine3D(startNode.getPoint(), endNode.getPoint());
176 CrossSectionLink link = new CrossSectionLink(otsNetwork, id, startNode, endNode,
177 otsNetwork.getLinkType(LinkType.DEFAULTS.CONNECTOR), designLine, null);
178 link.setDemandWeight(demandWeight);
179 }
180
181 for (LINK xmlLink : ParseUtil.getObjectsOfType(network.getIncludeOrNODEOrCONNECTOR(), LINK.class))
182 {
183 OTSRoadNode startNode = (OTSRoadNode) otsNetwork.getNode(xmlLink.getNODESTART());
184 OTSRoadNode endNode = (OTSRoadNode) otsNetwork.getNode(xmlLink.getNODEEND());
185 double startDirection =
186 nodeDirections.containsKey(startNode.getId()) ? nodeDirections.get(startNode.getId()).getSI() : 0.0;
187 double endDirection =
188 nodeDirections.containsKey(endNode.getId()) ? nodeDirections.get(endNode.getId()).getSI() : 0.0;
189 OTSPoint3D startPoint = new OTSPoint3D(startNode.getPoint());
190 OTSPoint3D endPoint = new OTSPoint3D(endNode.getPoint());
191 OTSPoint3D[] coordinates = null;
192
193 if (xmlLink.getSTRAIGHT() != null)
194 {
195 coordinates = new OTSPoint3D[2];
196 coordinates[0] = startPoint;
197 coordinates[1] = endPoint;
198 }
199
200 else if (xmlLink.getPOLYLINE() != null)
201 {
202 int intermediatePoints = xmlLink.getPOLYLINE().getCOORDINATE().size();
203 coordinates = new OTSPoint3D[intermediatePoints + 2];
204 coordinates[0] = startPoint;
205 coordinates[intermediatePoints + 1] = endPoint;
206 for (int p = 0; p < intermediatePoints; p++)
207 {
208 coordinates[p + 1] = new OTSPoint3D(xmlLink.getPOLYLINE().getCOORDINATE().get(p));
209 }
210
211 }
212 else if (xmlLink.getARC() != null)
213 {
214
215 double radiusSI = xmlLink.getARC().getRADIUS().getSI();
216 double offsetStart = 0.0;
217 if (xmlLink.getOFFSETSTART() != null)
218 {
219 offsetStart = xmlLink.getOFFSETSTART().si;
220 }
221 double offsetEnd = 0.0;
222 if (xmlLink.getOFFSETEND() != null)
223 {
224 offsetEnd = xmlLink.getOFFSETEND().si;
225 }
226 List<OTSPoint3D> centerList = OTSPoint3D.circleIntersections(startNode.getPoint(), radiusSI + offsetStart,
227 endNode.getPoint(), radiusSI + offsetEnd);
228 OTSPoint3D center =
229 (xmlLink.getARC().getDIRECTION().equals(ArcDirection.RIGHT)) ? centerList.get(0) : centerList.get(1);
230
231
232 double sa = Math.atan2(startNode.getPoint().y - center.y, startNode.getPoint().x - center.x);
233 double ea = Math.atan2(endNode.getPoint().y - center.y, endNode.getPoint().x - center.x);
234 if (xmlLink.getARC().getDIRECTION().equals(ArcDirection.RIGHT))
235 {
236
237 ea = (sa < ea) ? ea + Math.PI * 2.0 : ea;
238 }
239 else
240 {
241
242 ea = (ea < sa) ? ea + Math.PI * 2.0 : ea;
243 }
244
245 int numSegments = xmlLink.getARC().getNUMSEGMENTS().intValue();
246 coordinates = new OTSPoint3D[numSegments];
247 coordinates[0] = new OTSPoint3D(startNode.getPoint().x + Math.cos(sa) * offsetStart,
248 startNode.getPoint().y + Math.sin(sa) * offsetStart, startNode.getPoint().z);
249 coordinates[coordinates.length - 1] = new OTSPoint3D(endNode.getPoint().x + Math.cos(ea) * offsetEnd,
250 endNode.getPoint().y + Math.sin(ea) * offsetEnd, endNode.getPoint().z);
251 double angleStep = Math.abs((ea - sa)) / numSegments;
252 double slopeStep = (endNode.getPoint().z - startNode.getPoint().z) / numSegments;
253
254 if (xmlLink.getARC().getDIRECTION().equals(ArcDirection.RIGHT))
255 {
256 for (int p = 1; p < numSegments - 1; p++)
257 {
258 double dRad = offsetStart + (offsetEnd - offsetStart) * p / numSegments;
259 coordinates[p] = new OTSPoint3D(center.x + (radiusSI + dRad) * Math.cos(sa - angleStep * p),
260 center.y + (radiusSI + dRad) * Math.sin(sa - angleStep * p),
261 startNode.getPoint().z + slopeStep * p);
262 }
263 }
264 else
265 {
266 for (int p = 1; p < numSegments - 1; p++)
267 {
268 double dRad = offsetStart + (offsetEnd - offsetStart) * p / numSegments;
269 coordinates[p] = new OTSPoint3D(center.x + (radiusSI + dRad) * Math.cos(sa + angleStep * p),
270 center.y + (radiusSI + dRad) * Math.sin(sa + angleStep * p),
271 startNode.getPoint().z + slopeStep * p);
272 }
273 }
274 }
275
276 else if (xmlLink.getBEZIER() != null)
277 {
278 int numSegments = xmlLink.getBEZIER().getNUMSEGMENTS().intValue();
279 double shape = xmlLink.getBEZIER().getSHAPE().doubleValue();
280 boolean weighted = xmlLink.getBEZIER().isWEIGHTED();
281 if (xmlLink.getBEZIER().getSTARTDIRECTION() != null)
282 {
283 startDirection = xmlLink.getBEZIER().getSTARTDIRECTION().getSI();
284 }
285 if (xmlLink.getBEZIER().getENDDIRECTION() != null)
286 {
287 endDirection = xmlLink.getBEZIER().getENDDIRECTION().getSI();
288 }
289 coordinates = Bezier
290 .cubic(numSegments, new DirectedPoint(startPoint.x, startPoint.y, startPoint.z, 0, 0, startDirection),
291 new DirectedPoint(endPoint.x, endPoint.y, endPoint.z, 0, 0, endDirection), shape, weighted)
292 .getPoints();
293 }
294
295 else if (xmlLink.getCLOTHOID() != null)
296 {
297
298
299
300 }
301
302 else
303 {
304 throw new NetworkException("Making link, but link " + xmlLink.getID()
305 + " has no filled straight, arc, bezier, polyline, or clothoid definition");
306 }
307
308 OTSLine3D designLine = OTSLine3D.createAndCleanOTSLine3D(coordinates);
309
310
311 LaneKeepingPolicy laneKeepingPolicy = LaneKeepingPolicy.valueOf(xmlLink.getLANEKEEPING().name());
312 LinkType linkType = otsNetwork.getLinkType(xmlLink.getTYPE());
313 CrossSectionLink link = new CrossSectionLink(otsNetwork, xmlLink.getID(), startNode, endNode, linkType, designLine,
314 laneKeepingPolicy);
315
316 if (xmlLink.getPRIORITY() != null)
317 {
318 Priority priority = Priority.valueOf(xmlLink.getPRIORITY());
319 link.setPriority(priority);
320 }
321 }
322 }
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337 static void applyRoadLayout(final OTSRoadNetwork otsNetwork, final NETWORK network, final OTSSimulatorInterface simulator,
338 final Map<String, ROADLAYOUT> roadLayoutMap, final Map<LinkType, Map<GTUType, Speed>> linkTypeSpeedLimitMap)
339 throws NetworkException, OTSGeometryException, XmlParserException, SimRuntimeException, GTUException
340 {
341 for (LINK xmlLink : ParseUtil.getObjectsOfType(network.getIncludeOrNODEOrCONNECTOR(), LINK.class))
342 {
343 CrossSectionLink csl = (CrossSectionLink) otsNetwork.getLink(xmlLink.getID());
344 List<CrossSectionElement> cseList = new ArrayList<>();
345 Map<String, Lane> lanes = new LinkedHashMap<>();
346
347
348
349
350 BASICROADLAYOUT roadLayoutTagBase;
351 if (xmlLink.getDEFINEDLAYOUT() != null)
352 {
353 if (xmlLink.getROADLAYOUT() != null)
354 {
355 throw new XmlParserException(
356 "Link " + xmlLink.getID() + " Ambiguous RoadLayout; both DEFINEDROADLAYOUT and ROADLAYOUT defined");
357 }
358 roadLayoutTagBase = roadLayoutMap.get(xmlLink.getDEFINEDLAYOUT());
359 if (roadLayoutTagBase == null)
360 {
361 throw new XmlParserException(
362 "Link " + xmlLink.getID() + " Could not find defined RoadLayout " + xmlLink.getDEFINEDLAYOUT());
363 }
364 }
365 else
366 {
367 roadLayoutTagBase = xmlLink.getROADLAYOUT();
368 if (roadLayoutTagBase == null)
369 {
370 throw new XmlParserException("Link " + xmlLink.getID() + " No RoadLayout defined");
371 }
372 }
373
374
375 BASICROADLAYOUT roadLayoutTag = Cloner.cloneRoadLayout(roadLayoutTagBase);
376 for (LANEOVERRIDE laneOverride : xmlLink.getLANEOVERRIDE())
377 {
378 for (CSELANE lane : ParseUtil.getObjectsOfType(roadLayoutTag.getLANEOrNOTRAFFICLANEOrSHOULDER(), CSELANE.class))
379 {
380 if (lane.getID().equals(laneOverride.getLANE()))
381 {
382 if (laneOverride.getSPEEDLIMIT().size() > 0)
383 {
384 lane.getSPEEDLIMIT().clear();
385 lane.getSPEEDLIMIT().addAll(laneOverride.getSPEEDLIMIT());
386 }
387 }
388 }
389 }
390
391
392 List<CSEData> cseDataList = new ArrayList<>();
393 Map<Object, Integer> cseTagMap = new LinkedHashMap<>();
394 calculateOffsets(roadLayoutTag, xmlLink, cseDataList, cseTagMap);
395 boolean fixGradualLateralOffset = xmlLink.isFIXGRADUALOFFSET();
396
397
398 for (CSESTRIPE stripeTag : ParseUtil.getObjectsOfType(roadLayoutTag.getLANEOrNOTRAFFICLANEOrSHOULDER(),
399 CSESTRIPE.class))
400 {
401 CSEData cseData = cseDataList.get(cseTagMap.get(stripeTag));
402 makeStripe(csl, cseData.centerOffsetStart, cseData.centerOffsetEnd, stripeTag, cseList,
403 fixGradualLateralOffset);
404 }
405
406
407 for (CROSSSECTIONELEMENT cseTag : ParseUtil.getObjectsOfType(roadLayoutTag.getLANEOrNOTRAFFICLANEOrSHOULDER(),
408 CROSSSECTIONELEMENT.class))
409 {
410 CSEData cseData = cseDataList.get(cseTagMap.get(cseTag));
411
412
413 if (cseTag instanceof CSELANE)
414 {
415 CSELANE laneTag = (CSELANE) cseTag;
416 boolean direction = laneTag.isDESIGNDIRECTION();
417 LaneType laneType = otsNetwork.getLaneType(laneTag.getLANETYPE());
418
419 Map<GTUType, Speed> speedLimitMap = new LinkedHashMap<>();
420 LinkType linkType = csl.getLinkType();
421 if (!linkTypeSpeedLimitMap.containsKey(linkType))
422 {
423 linkTypeSpeedLimitMap.put(linkType, new LinkedHashMap<>());
424 }
425 speedLimitMap.putAll(linkTypeSpeedLimitMap.get(linkType));
426 for (SPEEDLIMIT speedLimitTag : roadLayoutTag.getSPEEDLIMIT())
427 {
428 GTUType gtuType = otsNetwork.getGtuType(speedLimitTag.getGTUTYPE());
429 speedLimitMap.put(gtuType, speedLimitTag.getLEGALSPEEDLIMIT());
430 }
431 for (SPEEDLIMIT speedLimitTag : laneTag.getSPEEDLIMIT())
432 {
433 GTUType gtuType = otsNetwork.getGtuType(speedLimitTag.getGTUTYPE());
434 speedLimitMap.put(gtuType, speedLimitTag.getLEGALSPEEDLIMIT());
435 }
436 Lane lane = new Lane(csl, laneTag.getID(), cseData.centerOffsetStart, cseData.centerOffsetEnd,
437 cseData.widthStart, cseData.widthEnd, laneType, speedLimitMap, fixGradualLateralOffset);
438 cseList.add(lane);
439 lanes.put(lane.getId(), lane);
440 }
441
442
443 else if (cseTag instanceof CSENOTRAFFICLANE)
444 {
445 CSENOTRAFFICLANE ntlTag = (CSENOTRAFFICLANE) cseTag;
446 String id = ntlTag.getID() != null ? ntlTag.getID() : UUID.randomUUID().toString();
447 Lane lane = new NoTrafficLane(csl, id, cseData.centerOffsetStart, cseData.centerOffsetEnd,
448 cseData.widthStart, cseData.widthEnd, fixGradualLateralOffset);
449 cseList.add(lane);
450 }
451
452
453 else if (cseTag instanceof CSESHOULDER)
454 {
455 CSESHOULDER shoulderTag = (CSESHOULDER) cseTag;
456 String id = shoulderTag.getID() != null ? shoulderTag.getID() : UUID.randomUUID().toString();
457 Shoulder shoulder = new Shoulder(csl, id, cseData.centerOffsetStart, cseData.centerOffsetEnd,
458 cseData.widthStart, cseData.widthEnd, fixGradualLateralOffset);
459 cseList.add(shoulder);
460 }
461 }
462
463
464 for (TRAFFICLIGHTTYPE trafficLight : xmlLink.getTRAFFICLIGHT())
465 {
466 if (!lanes.containsKey(trafficLight.getLANE()))
467 {
468 throw new NetworkException("LINK: " + xmlLink.getID() + ", TrafficLight with id " + trafficLight.getID()
469 + " on Lane " + trafficLight.getLANE() + " - Lane not found");
470 }
471 Lane lane = lanes.get(trafficLight.getLANE());
472 Length position = Transformer.parseLengthBeginEnd(trafficLight.getPOSITION(), lane.getLength());
473 try
474 {
475 Constructor<?> trafficLightConstructor = ClassUtil.resolveConstructor(trafficLight.getCLASS(),
476 new Class[] {String.class, Lane.class, Length.class, DEVSSimulatorInterface.TimeDoubleUnit.class});
477 trafficLightConstructor.newInstance(new Object[] {trafficLight.getID(), lane, position, simulator});
478 }
479 catch (NoSuchMethodException | InstantiationException | IllegalAccessException | IllegalArgumentException
480 | InvocationTargetException exception)
481 {
482 throw new NetworkException("TRAFFICLIGHT: CLASS NAME " + trafficLight.getCLASS().getName()
483 + " for traffic light " + trafficLight.getID() + " on lane " + lane.toString() + " at position "
484 + position + " -- class not found or constructor not right", exception);
485
486 }
487 }
488 }
489 }
490
491
492
493
494
495
496
497
498
499
500 @SuppressWarnings("checkstyle:methodlength")
501 private static void calculateOffsets(final BASICROADLAYOUT roadLayoutTag, final LINK xmlLink,
502 final List<CSEData> cseDataList, final Map<Object, Integer> cseTagMap)
503 {
504 int nr = 0;
505 Length totalWidthStart = Length.ZERO;
506 Length totalWidthEnd = Length.ZERO;
507 boolean startOffset = false;
508 boolean endOffset = false;
509 for (Object o : roadLayoutTag.getLANEOrNOTRAFFICLANEOrSHOULDER())
510 {
511 if (o instanceof CSESTRIPE)
512 {
513 CSESTRIPE stripe = (CSESTRIPE) o;
514 CSEData cseData = new CSEData();
515 cseData.widthStart = Length.ZERO;
516 cseData.widthEnd = Length.ZERO;
517 if (stripe.getCENTEROFFSET() != null)
518 {
519 cseData.centerOffsetStart = stripe.getCENTEROFFSET();
520 cseData.centerOffsetEnd = stripe.getCENTEROFFSET();
521 startOffset = true;
522 endOffset = true;
523 }
524 else
525 {
526 if (stripe.getCENTEROFFSETSTART() != null)
527 {
528 cseData.centerOffsetStart = stripe.getCENTEROFFSETSTART();
529 startOffset = true;
530 }
531 if (stripe.getCENTEROFFSETEND() != null)
532 {
533 cseData.centerOffsetEnd = stripe.getCENTEROFFSETEND();
534 endOffset = true;
535 }
536 }
537 cseDataList.add(cseData);
538 }
539 else
540 {
541 CROSSSECTIONELEMENT cse = (CROSSSECTIONELEMENT) o;
542 CSEData cseData = new CSEData();
543 cseData.widthStart = cse.getWIDTH() == null ? cse.getWIDTHSTART() : cse.getWIDTH();
544 Length halfWidthStart = cseData.widthStart.times(0.5);
545 totalWidthStart = totalWidthStart.plus(cseData.widthStart);
546 cseData.widthEnd = cse.getWIDTH() == null ? cse.getWIDTHEND() : cse.getWIDTH();
547 Length halfWidthEnd = cseData.widthEnd.times(0.5);
548 totalWidthEnd = totalWidthEnd.plus(cseData.widthStart);
549
550 if (cse.getCENTEROFFSET() != null)
551 {
552 cseData.centerOffsetStart = cse.getCENTEROFFSET();
553 cseData.centerOffsetEnd = cse.getCENTEROFFSET();
554 startOffset = true;
555 endOffset = true;
556 }
557 else if (cse.getLEFTOFFSET() != null)
558 {
559 cseData.centerOffsetStart = cse.getLEFTOFFSET().minus(halfWidthStart);
560 cseData.centerOffsetEnd = cse.getLEFTOFFSET().minus(halfWidthEnd);
561 startOffset = true;
562 endOffset = true;
563 }
564 else if (cse.getRIGHTOFFSET() != null)
565 {
566 cseData.centerOffsetStart = cse.getRIGHTOFFSET().plus(halfWidthStart);
567 cseData.centerOffsetEnd = cse.getRIGHTOFFSET().plus(halfWidthEnd);
568 startOffset = true;
569 endOffset = true;
570 }
571
572 if (cse.getCENTEROFFSETSTART() != null)
573 {
574 cseData.centerOffsetStart = cse.getCENTEROFFSETSTART();
575 startOffset = true;
576 }
577 else if (cse.getLEFTOFFSETSTART() != null)
578 {
579 cseData.centerOffsetStart = cse.getLEFTOFFSETSTART().minus(halfWidthStart);
580 startOffset = true;
581 }
582 else if (cse.getRIGHTOFFSETSTART() != null)
583 {
584 cseData.centerOffsetStart = cse.getRIGHTOFFSETSTART().plus(halfWidthStart);
585 startOffset = true;
586 }
587
588 if (cse.getCENTEROFFSETEND() != null)
589 {
590 cseData.centerOffsetEnd = cse.getCENTEROFFSETEND();
591 endOffset = true;
592 }
593 else if (cse.getLEFTOFFSETEND() != null)
594 {
595 cseData.centerOffsetEnd = cse.getLEFTOFFSETEND().minus(halfWidthEnd);
596 endOffset = true;
597 }
598 else if (cse.getRIGHTOFFSETEND() != null)
599 {
600 cseData.centerOffsetEnd = cse.getRIGHTOFFSETEND().plus(halfWidthEnd);
601 endOffset = true;
602 }
603 cseDataList.add(cseData);
604 }
605 cseTagMap.put(o, nr);
606 nr++;
607 }
608
609 if (!startOffset)
610 {
611 cseDataList.get(0).centerOffsetStart = totalWidthStart.times(-0.5).minus(cseDataList.get(0).widthStart.times(-0.5));
612 }
613 if (!endOffset)
614 {
615 cseDataList.get(0).centerOffsetEnd = totalWidthEnd.times(-0.5).minus(cseDataList.get(0).widthEnd.times(-0.5));
616 }
617
618
619 Length cs = null;
620 Length es = null;
621 for (CSEData cseData : cseDataList)
622 {
623 if (cseData.centerOffsetStart != null)
624 {
625 cs = cseData.centerOffsetStart.plus(cseData.widthStart.times(0.5));
626 }
627 else
628 {
629 if (cs != null)
630 {
631 cseData.centerOffsetStart = cs.plus(cseData.widthStart.times(0.5));
632 cs = cs.plus(cseData.widthStart);
633 }
634 }
635 if (cseData.centerOffsetEnd != null)
636 {
637 es = cseData.centerOffsetEnd.plus(cseData.widthEnd.times(0.5));
638 }
639 else
640 {
641 if (es != null)
642 {
643 cseData.centerOffsetEnd = es.plus(cseData.widthEnd.times(0.5));
644 es = es.plus(cseData.widthEnd);
645 }
646 }
647 }
648
649
650 cs = null;
651 es = null;
652 for (int i = cseDataList.size() - 1; i >= 0; i--)
653 {
654 CSEData cseData = cseDataList.get(i);
655 if (cseData.centerOffsetStart != null)
656 {
657 cs = cseData.centerOffsetStart.minus(cseData.widthStart.times(0.5));
658 }
659 else
660 {
661 if (cs != null)
662 {
663 cseData.centerOffsetStart = cs.minus(cseData.widthStart.times(0.5));
664 cs = cs.minus(cseData.widthStart);
665 }
666 }
667 if (cseData.centerOffsetEnd != null)
668 {
669 es = cseData.centerOffsetEnd.minus(cseData.widthEnd.times(0.5));
670 }
671 else
672 {
673 if (es != null)
674 {
675 cseData.centerOffsetEnd = es.minus(cseData.widthEnd.times(0.5));
676 es = es.minus(cseData.widthEnd);
677 }
678 }
679 }
680
681
682 if (xmlLink.getOFFSETSTART() != null && xmlLink.getOFFSETSTART().ne0())
683 {
684 for (CSEData cseData : cseDataList)
685 {
686 cseData.centerOffsetStart = cseData.centerOffsetStart.plus(xmlLink.getOFFSETSTART());
687 }
688 }
689 if (xmlLink.getOFFSETEND() != null && xmlLink.getOFFSETEND().ne0())
690 {
691 for (CSEData cseData : cseDataList)
692 {
693 cseData.centerOffsetEnd = cseData.centerOffsetEnd.plus(xmlLink.getOFFSETEND());
694 }
695 }
696 }
697
698
699
700
701
702
703
704
705
706
707
708
709
710 private static void makeStripe(final CrossSectionLink csl, final Length startOffset, final Length endOffset,
711 final CSESTRIPE stripeTag, final List<CrossSectionElement> cseList, final boolean fixGradualLateralOffset)
712 throws OTSGeometryException, NetworkException, XmlParserException
713 {
714 Length width =
715 stripeTag.getDRAWINGWIDTH() != null ? stripeTag.getDRAWINGWIDTH() : new Length(20.0, LengthUnit.CENTIMETER);
716 switch (stripeTag.getTYPE())
717 {
718 case BLOCKED:
719 Stripe blockedLine = new Stripe(csl, startOffset, endOffset, stripeTag.getDRAWINGWIDTH() != null
720 ? stripeTag.getDRAWINGWIDTH() : new Length(40.0, LengthUnit.CENTIMETER), fixGradualLateralOffset);
721 blockedLine.addPermeability(csl.getNetwork().getGtuType(GTUType.DEFAULTS.ROAD_USER), Permeable.BOTH);
722 cseList.add(blockedLine);
723 break;
724
725 case DASHED:
726 Stripe dashedLine = new Stripe(csl, startOffset, endOffset, width, fixGradualLateralOffset);
727 dashedLine.addPermeability(csl.getNetwork().getGtuType(GTUType.DEFAULTS.ROAD_USER), Permeable.BOTH);
728 cseList.add(dashedLine);
729 break;
730
731 case DOUBLE:
732 Stripe doubleLine = new Stripe(csl, startOffset, endOffset, width, fixGradualLateralOffset);
733 cseList.add(doubleLine);
734 break;
735
736 case LEFTONLY:
737 Stripe leftOnlyLine = new Stripe(csl, startOffset, endOffset, width, fixGradualLateralOffset);
738 leftOnlyLine.addPermeability(csl.getNetwork().getGtuType(GTUType.DEFAULTS.ROAD_USER), Permeable.LEFT);
739 cseList.add(leftOnlyLine);
740 break;
741
742 case RIGHTONLY:
743 Stripe rightOnlyLine = new Stripe(csl, startOffset, endOffset, width, fixGradualLateralOffset);
744 rightOnlyLine.addPermeability(csl.getNetwork().getGtuType(GTUType.DEFAULTS.ROAD_USER), Permeable.RIGHT);
745 cseList.add(rightOnlyLine);
746 break;
747
748 case SOLID:
749 try
750 {
751 Stripe solidLine = new Stripe(csl, startOffset, endOffset, width, fixGradualLateralOffset);
752 cseList.add(solidLine);
753 }
754 catch (OTSGeometryException oge)
755 {
756 System.out.println("Caught OTSGeometryException constructing a stripe on " + csl);
757 }
758 break;
759
760 default:
761 throw new XmlParserException("Unknown Stripe type: " + stripeTag.getTYPE().toString());
762 }
763 }
764
765
766 protected static class CSEData
767 {
768
769 @SuppressWarnings("checkstyle:visibilitymodifier")
770 public Length widthStart;
771
772
773 @SuppressWarnings("checkstyle:visibilitymodifier")
774 public Length widthEnd;
775
776
777 @SuppressWarnings("checkstyle:visibilitymodifier")
778 public Length centerOffsetStart;
779
780
781 @SuppressWarnings("checkstyle:visibilitymodifier")
782 public Length centerOffsetEnd;
783
784
785 @Override
786 public String toString()
787 {
788 return "CSEData [widthStart=" + this.widthStart + ", widthEnd=" + this.widthEnd + ", centerOffsetStart="
789 + this.centerOffsetStart + ", centerOffsetEnd=" + this.centerOffsetEnd + "]";
790 }
791 }
792
793 }