1 package org.opentrafficsim.road.network.factory.opendrive;
2
3 import java.io.Serializable;
4 import java.util.List;
5
6 import org.opentrafficsim.core.network.NetworkException;
7 import org.w3c.dom.NamedNodeMap;
8 import org.w3c.dom.Node;
9 import org.w3c.dom.NodeList;
10 import org.xml.sax.SAXException;
11
12
13
14
15
16
17
18
19
20
21 class LinkTag implements Serializable
22 {
23
24
25 private static final long serialVersionUID = 20150723L;
26
27
28 @SuppressWarnings("checkstyle:visibilitymodifier")
29 String predecessorId = null;
30
31
32 @SuppressWarnings("checkstyle:visibilitymodifier")
33 String predecessorType = null;
34
35
36 @SuppressWarnings("checkstyle:visibilitymodifier")
37 ContactPointEnum predecessorContactPoint = null;
38
39
40 @SuppressWarnings("checkstyle:visibilitymodifier")
41 String successorId = null;
42
43
44 @SuppressWarnings("checkstyle:visibilitymodifier")
45 String successorType = null;
46
47
48 @SuppressWarnings("checkstyle:visibilitymodifier")
49 ContactPointEnum successorContactPoint = null;
50
51
52 @SuppressWarnings("checkstyle:visibilitymodifier")
53 String leftNeighborRoadId = null;
54
55
56 @SuppressWarnings("checkstyle:visibilitymodifier")
57 NeighborDirection leftNeighborDirection = null;
58
59
60 @SuppressWarnings("checkstyle:visibilitymodifier")
61 String rightNeighborRoadId = null;
62
63
64 @SuppressWarnings("checkstyle:visibilitymodifier")
65 NeighborDirection rightNeighborDirection = null;
66
67
68
69
70
71
72
73
74
75 @SuppressWarnings("checkstyle:needbraces")
76 static void parseLink(final NodeList nodeList, final OpenDriveNetworkLaneParser parser, final RoadTag roadTag)
77 throws SAXException, NetworkException
78 {
79 int linkCount = 0;
80 for (Node node : XMLParser.getNodes(nodeList, "link"))
81 {
82 linkCount++;
83 LinkTag linkTag = new LinkTag();
84 roadTag.linkTag = linkTag;
85
86
87
88 List<Node> predecessorNodes = XMLParser.getNodes(node.getChildNodes(), "predecessor");
89 if (predecessorNodes.size() > 1)
90 throw new SAXException("ROAD: more than one LINK.PREDECESSOR tag for road id=" + roadTag.id);
91 if (predecessorNodes.size() == 1)
92 {
93 Node predecessorNode = predecessorNodes.get(0);
94 NamedNodeMap attributes = predecessorNode.getAttributes();
95
96 Node elementId = attributes.getNamedItem("elementId");
97 if (elementId == null)
98 throw new SAXException("ROAD.LINK.PREDECESSOR: missing attribute elementId for ROAD.ID=" + roadTag.id);
99
100 Node elementType = attributes.getNamedItem("elementType");
101 if (elementType == null)
102 throw new SAXException("ROAD.LINK.PREDECESSOR: missing attribute elementType for ROAD.ID=" + roadTag.id);
103 if ("road".equals(elementType.getNodeValue().trim()) || "junction".equals(elementType.getNodeValue().trim()))
104 {
105 linkTag.predecessorType = elementType.getNodeValue().trim();
106 linkTag.predecessorId = elementId.getNodeValue().trim();
107 }
108 else
109 throw new SAXException("ROAD.LINK.PREDECESSOR: elementType for ROAD.ID=" + roadTag.id
110 + " is neither 'road' nor 'junction' but: " + elementType.getNodeValue().trim());
111
112 Node contactPoint = attributes.getNamedItem("contactPoint");
113 if (contactPoint != null)
114
115
116
117 {
118 if ("start".equals(contactPoint.getNodeValue().trim()))
119 linkTag.predecessorContactPoint = ContactPointEnum.START;
120 else if ("end".equals(contactPoint.getNodeValue().trim()))
121 linkTag.predecessorContactPoint = ContactPointEnum.END;
122 else
123 throw new SAXException("ROAD.LINK.PREDECESSOR: contactPoint for ROAD.ID=" + roadTag.id
124 + " is neither 'start' nor 'end' but: " + contactPoint.getNodeValue().trim());
125 }
126 }
127
128
129
130 List<Node> successorNodes = XMLParser.getNodes(node.getChildNodes(), "successor");
131 if (successorNodes.size() > 1)
132 throw new SAXException("ROAD: more than one LINK.SUCCESSOR tag for road id=" + roadTag.id);
133 if (successorNodes.size() == 1)
134 {
135 Node successorNode = successorNodes.get(0);
136 NamedNodeMap attributes = successorNode.getAttributes();
137
138 Node elementId = attributes.getNamedItem("elementId");
139 if (elementId == null)
140 throw new SAXException("ROAD.LINK.SUCCESSOR: missing attribute elementId for ROAD.ID=" + roadTag.id);
141
142 Node elementType = attributes.getNamedItem("elementType");
143 if (elementType == null)
144 throw new SAXException("ROAD.LINK.SUCCESSOR: missing attribute elementType for ROAD.ID=" + roadTag.id);
145 if ("road".equals(elementType.getNodeValue().trim()) || "junction".equals(elementType.getNodeValue().trim()))
146 {
147 linkTag.successorType = elementType.getNodeValue().trim();
148 linkTag.successorId = elementId.getNodeValue().trim();
149 }
150 else
151 throw new SAXException("ROAD.LINK.SUCCESSOR: elementType for ROAD.ID=" + roadTag.id
152 + " is neither 'road' nor 'junction' but: " + elementType.getNodeValue().trim());
153
154 Node contactPoint = attributes.getNamedItem("contactPoint");
155 if (contactPoint != null)
156
157
158
159 {
160 if ("start".equals(contactPoint.getNodeValue().trim()))
161 linkTag.successorContactPoint = ContactPointEnum.START;
162 else if ("end".equals(contactPoint.getNodeValue().trim()))
163 linkTag.successorContactPoint = ContactPointEnum.END;
164 else
165 throw new SAXException("ROAD.LINK.SUCCESSOR: contactPoint for ROAD.ID=" + roadTag.id
166 + " is neither 'start' nor 'end' but: " + contactPoint.getNodeValue().trim());
167 }
168 }
169
170
171
172 List<Node> neighborNodes = XMLParser.getNodes(node.getChildNodes(), "neighbor");
173 if (neighborNodes.size() > 2)
174 throw new SAXException("ROAD: more than two LINK.NEIGHBOR tags for road id=" + roadTag.id);
175 boolean left = false;
176 boolean right = false;
177 for (Node neighborNode : neighborNodes)
178 {
179 NamedNodeMap attributes = neighborNode.getAttributes();
180
181 Node elementId = attributes.getNamedItem("elementId");
182 if (elementId == null)
183 throw new SAXException("ROAD.LINK.NEIGHBOR: missing attribute elementId for ROAD.ID=" + roadTag.id);
184
185 Node direction = attributes.getNamedItem("direction");
186 NeighborDirection ndir = null;
187 if (direction == null)
188 throw new SAXException("ROAD.LINK.NEIGHBOR: missing attribute direction for ROAD.ID=" + roadTag.id);
189 if ("same".equals(direction.getNodeValue().trim()))
190 ndir = NeighborDirection.SAME;
191 else if ("opposite".equals(direction.getNodeValue().trim()))
192 ndir = NeighborDirection.OPPOSITE;
193 else
194 throw new SAXException("ROAD.LINK.NEIGHBOR: contactPoint for ROAD.ID=" + roadTag.id
195 + " is neither 'same' nor 'opposite' but: " + direction.getNodeValue().trim());
196
197 Node side = attributes.getNamedItem("side");
198 if (side == null)
199 throw new SAXException("ROAD.LINK.NEIGHBOR: missing attribute side for ROAD.ID=" + roadTag.id);
200 if ("left".equals(side.getNodeValue().trim()))
201 {
202 if (left)
203 throw new SAXException("ROAD.LINK.NEIGHBOR: left side defined twice for ROAD.ID=" + roadTag.id);
204 left = true;
205 linkTag.leftNeighborRoadId = elementId.getNodeValue().trim();
206 linkTag.leftNeighborDirection = ndir;
207 }
208 else if ("right".equals(side.getNodeValue().trim()))
209 {
210 if (right)
211 throw new SAXException("ROAD.LINK.NEIGHBOR: right side defined twice for ROAD.ID=" + roadTag.id);
212 right = true;
213 linkTag.rightNeighborRoadId = elementId.getNodeValue().trim();
214 linkTag.rightNeighborDirection = ndir;
215 }
216 else
217 throw new SAXException("ROAD.LINK.NEIGHBOR: side for ROAD.ID=" + roadTag.id
218 + " is neither 'left' nor 'right' but: " + side.getNodeValue().trim());
219 }
220
221 }
222
223 if (linkCount > 1)
224 throw new SAXException("ROAD: more than one LINK tag for road id=" + roadTag.id);
225 }
226
227
228 enum ContactPointEnum
229 {
230
231 START,
232
233 END;
234 }
235
236
237 enum NeighborDirection
238 {
239
240 SAME,
241
242 OPPOSITE;
243 }
244
245
246 @Override
247 public final String toString()
248 {
249 return "LinkTag [predecessorId=" + this.predecessorId + ", predecessorType=" + this.predecessorType
250 + ", predecessorContactPoint=" + this.predecessorContactPoint + ", successorId=" + this.successorId
251 + ", successorType=" + this.successorType + ", successorContactPoint=" + this.successorContactPoint
252 + ", leftNeighborRoadId=" + this.leftNeighborRoadId + ", leftNeighborDirection=" + this.leftNeighborDirection
253 + ", rightNeighborRoadId=" + this.rightNeighborRoadId + ", rightNeighborDirection="
254 + this.rightNeighborDirection + "]";
255 }
256 }