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