View Javadoc
1   package org.opentrafficsim.road.network.factory.vissim;
2   
3   import java.io.Serializable;
4   import java.util.ArrayList;
5   import java.util.HashMap;
6   import java.util.Iterator;
7   import java.util.List;
8   import java.util.Map;
9   
10  import javax.naming.NamingException;
11  
12  import org.djunits.value.vdouble.scalar.Angle;
13  import org.djunits.value.vdouble.scalar.Direction;
14  import org.opentrafficsim.core.geometry.OTSGeometryException;
15  import org.opentrafficsim.core.geometry.OTSLine3D;
16  import org.opentrafficsim.core.geometry.OTSPoint3D;
17  import org.opentrafficsim.core.network.NetworkException;
18  import org.opentrafficsim.core.network.OTSNode;
19  import org.xml.sax.SAXException;
20  
21  import com.vividsolutions.jts.geom.Coordinate;
22  import com.vividsolutions.jts.geom.LineString;
23  
24  import nl.tudelft.simulation.language.Throw;
25  
26  /**
27   * <p>
28   * Copyright (c) 2013-2017 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved. <br>
29   * BSD-style license. See <a href="http://opentrafficsim.org/docs/license.html">OpenTrafficSim License</a>.
30   * <p>
31   * $LastChangedDate: 2017-04-29 13:29:16 +0200 (Sat, 29 Apr 2017) $, @version $Revision: 3573 $, by $Author: averbraeck $,
32   * initial version Jul 23, 2015 <br>
33   * @author <a href="http://www.tbm.tudelft.nl/averbraeck">Alexander Verbraeck</a>
34   */
35  class NodeTag implements Serializable
36  {
37      /** */
38      private static final long serialVersionUID = 20150723L;
39  
40      /** Name. */
41      @SuppressWarnings("checkstyle:visibilitymodifier")
42      String name = null;
43  
44      /** Coordinate (null at first, can be calculated later when connected to a link. */
45      @SuppressWarnings("checkstyle:visibilitymodifier")
46      OTSPoint3D coordinate = null;
47  
48      /** Absolute angle of the node. 0 is "East", pi/2 = "North". */
49      @SuppressWarnings("checkstyle:visibilitymodifier")
50      Direction angle = null;
51  
52      /** TODO slope as an angle. */
53      @SuppressWarnings("checkstyle:visibilitymodifier")
54      Angle slope = null;
55  
56      /** The calculated Node, either through a coordinate or after calculation. */
57      @SuppressWarnings("checkstyle:visibilitymodifier")
58      OTSNode node = null;
59  
60      /**
61       * @param parser VissimNetworkLaneParser; VissimParser
62       * @param fromNode String; coming from Node
63       * @param toNode String; going to Node
64       * @param points OTSPoint3D[]; geometry
65       * @throws SAXException
66       * @throws NetworkException
67       */
68      @SuppressWarnings("checkstyle:needbraces")
69      static void parseNodes(final VissimNetworkLaneParser parser, String fromNode, String toNode, OTSPoint3D[] points)
70              throws SAXException, NetworkException
71      {
72          NodeTag nodeFromTag = new NodeTag();
73          nodeFromTag.name = fromNode;
74          nodeFromTag.coordinate = points[0];
75          // TODO slope for the Node.
76          generateOTSNode(parser, nodeFromTag);
77          parser.getNodeTags().put(nodeFromTag.name, nodeFromTag);
78  
79          NodeTag nodeToTag = new NodeTag();
80          nodeToTag.name = toNode;
81          nodeToTag.coordinate = points[points.length - 1];
82          // TODO slope for the Node.
83          generateOTSNode(parser, nodeToTag);
84          parser.getNodeTags().put(nodeToTag.name, nodeToTag);
85      }
86  
87      /**
88       * @param parser VissimNetworkLaneParser; the parser with the lists of information
89       * @param nodeTag NodeTag; node Info
90       * @throws NetworkException
91       */
92      private static void generateOTSNode(final VissimNetworkLaneParser parser, final NodeTag nodeTag) throws NetworkException
93      {
94          if (nodeTag.coordinate != null && nodeTag.angle != null)
95          {
96              // only make a node if we know the coordinate and angle. Otherwise, wait till we can calculate it.
97              try
98              {
99                  makeOTSNode(nodeTag, parser);
100             }
101             catch (NamingException exception)
102             {
103                 throw new NetworkException(exception);
104             }
105         }
106     }
107 
108     /**
109      * Parse a list of Nodes, e.g. for a ROUTE.
110      * @param nodeNames the space separated String with the node names
111      * @param parser the parser with the lists of information
112      * @return a list of NodeTags
113      * @throws SAXException when parsing of the tag fails
114      * @throws NetworkException when parsing of the tag fails
115      */
116     static List<NodeTag> parseNodeList(final String nodeNames, final VissimNetworkLaneParser parser)
117             throws SAXException, NetworkException
118     {
119         List<NodeTag> nodeList = new ArrayList<>();
120         String[] ns = nodeNames.split("\\s");
121         for (String s : ns)
122         {
123             if (!parser.getNodeTags().containsKey(s))
124             {
125                 throw new SAXException("Node " + s + " from node list [" + nodeNames + "] was not defined");
126             }
127             nodeList.add(parser.getNodeTags().get(s));
128         }
129         return nodeList;
130 
131     }
132 
133     /**
134      * @param nodeTag the tag with the info for the node.
135      * @param parser the parser with the lists of information
136      * @return a constructed node
137      * @throws NetworkException when point cannot be instantiated
138      * @throws NamingException when animation context cannot be found.
139      */
140     static OTSNode makeOTSNode(final NodeTag nodeTag, final VissimNetworkLaneParser parser)
141             throws NetworkException, NamingException
142     {
143         Throw.whenNull(nodeTag.angle, "NodeTag: " + nodeTag.name + " angle == null");
144         if (nodeTag.node != null)
145         {
146             nodeTag.node.getNetwork().removeNode(nodeTag.node);
147         }
148         String id = nodeTag.name;
149         Direction angle = nodeTag.angle;
150         Angle slope = nodeTag.slope == null ? Angle.ZERO : nodeTag.slope;
151         OTSNode node = new OTSNode(parser.getNetwork(), id, nodeTag.coordinate, angle, slope);
152         nodeTag.node = node;
153         return node;
154     }
155 
156     /**
157      * @param parser VissimNetworkLaneParser; the parser with the lists of information
158      */
159     public static void removeDuplicateNodes(final VissimNetworkLaneParser parser)
160     {
161         // the map with NodeTag (key) that should be deleted and replaced by another nodeTag (value)
162         Map<String, String> replaceNodeMap = new HashMap<>();
163         Iterator<NodeTag> nodeTagValues = parser.getNodeTags().values().iterator();
164 
165         // determine identical nodes
166         while (nodeTagValues.hasNext())
167         {
168             NodeTag nodeTag = nodeTagValues.next();
169             // compare to other nodeTags
170             Iterator<NodeTag> nodeTagValuesCopy = parser.getNodeTags().values().iterator();
171             while (nodeTagValuesCopy.hasNext())
172             {
173                 NodeTag nodeTagCopy = nodeTagValuesCopy.next();
174                 // if the coordinates are equal (distance == 0)
175                 if (nodeTagCopy.coordinate.distance(nodeTag.coordinate).si == 0 && !nodeTagCopy.name.equals(nodeTag.name))
176                 {
177                     // is there an already found and handled duplicate node?
178                     if (replaceNodeMap.get(nodeTag.name) == null)
179                     {
180                         replaceNodeMap.put(nodeTagCopy.name, nodeTag.name);
181                     }
182                 }
183             }
184         }
185 
186         // rename nodes in linkTags nodeTags
187         Iterator<LinkTag> linkTagValues = parser.getLinkTags().values().iterator();
188         while (linkTagValues.hasNext())
189         {
190             LinkTag linkTag = linkTagValues.next();
191             NodeTag nodeTag = linkTag.nodeEndTag;
192             if (replaceNodeMap.get(nodeTag.name) != null)
193             {
194                 linkTag.nodeEndTag = parser.getNodeTags().get(replaceNodeMap.get(nodeTag.name));
195             }
196 
197             NodeTag node2Tag = linkTag.nodeStartTag;
198             if (replaceNodeMap.get(node2Tag.name) != null)
199             {
200                 linkTag.nodeStartTag = parser.getNodeTags().get(replaceNodeMap.get(node2Tag.name));
201             }
202         }
203 
204         // remove duplicate nodes from nodeTags
205         Iterator<String> nodeTagNames = replaceNodeMap.keySet().iterator();
206         while (nodeTagNames.hasNext())
207         {
208             String nodeTagName = nodeTagNames.next();
209             parser.getNodeTags().remove(nodeTagName);
210         }
211 
212     }
213 
214     /**
215      * @param parser VissimNetworkLaneParser; the parser with the lists of information
216      */
217     public static void removeRedundantNodeTags(final VissimNetworkLaneParser parser)
218     {
219         Iterator<NodeTag> nodeTagValues;
220         Iterator<LinkTag> linkTagValues;
221         Iterator<LinkTag> connectoTagValues;
222         // remove redundant nodes from nodeTags
223         Map<String, NodeTag> removeNodeMap = new HashMap<>();
224         nodeTagValues = parser.getNodeTags().values().iterator();
225         while (nodeTagValues.hasNext())
226         {
227             NodeTag nodeTag = nodeTagValues.next();
228             linkTagValues = parser.getLinkTags().values().iterator();
229             boolean found = false;
230             while (linkTagValues.hasNext())
231             {
232                 LinkTag linkTag = linkTagValues.next();
233                 if (linkTag.nodeStartTag.name.equals(nodeTag.name) || linkTag.nodeEndTag.name.equals(nodeTag.name))
234                 {
235                     found = true;
236                 }
237             }
238             // connectoTagValues = parser.connectorTags.values().iterator();
239             // while (connectoTagValues.hasNext()) {
240             // LinkTag linkTag = connectoTagValues.next();
241             // if (linkTag.nodeStartTag.equals(nodeTag.name) || linkTag.nodeEndTag.equals(nodeTag.name)) {
242             // found = true;
243             // }
244             // }
245             if (!found)
246             {
247                 removeNodeMap.put(nodeTag.name, nodeTag);
248             }
249         }
250         for (NodeTag nodeTag : removeNodeMap.values())
251         {
252             parser.getNodeTags().remove(nodeTag.name);
253         }
254     }
255 
256     /** {@inheritDoc} */
257     @Override
258     public String toString()
259     {
260         return "NodeTag [name=" + this.name + ", coordinate=" + this.coordinate + ", node=" + this.node + "]";
261     }
262 
263     /**
264      * @param linkTag LinkTag; link with info
265      * @param parser VissimNetworkLaneParser; the parser with the lists of information
266      * @param position Double; position at the link where a node is created
267      * @return NodeTag
268      * @throws OTSGeometryException
269      * @throws NetworkException
270      */
271     public static NodeTag createNewNodeAtLinkPosition(final LinkTag linkTag, final VissimNetworkLaneParser parser,
272             final Double position) throws OTSGeometryException, NetworkException
273     {
274         // make a new Node
275         NodeTag nodeTag = new NodeTag();
276         // generate a LineString
277         OTSLine3D designLineOTS = LinkTag.createLineString(linkTag);
278         LineString designLine = designLineOTS.getLineString();
279         // find the coordinates at the position
280         LineString designLineStart = SubstringLine.getSubstring(designLine, 0.0, position);
281         Coordinate[] points = designLineStart.getCoordinates();
282         OTSPoint3D point = new OTSPoint3D(points[points.length - 1]);
283         nodeTag.coordinate = point;
284         // add a unique name
285         String nodeName = "" + parser.getUpperNodeNr();
286         parser.setUpperNodeNr(parser.getUpperNodeNr() + 1);
287         nodeTag.name = nodeName;
288         // TODO slope for the Node.
289         generateOTSNode(parser, nodeTag);
290         parser.getNodeTags().put(nodeTag.name, nodeTag);
291         return nodeTag;
292     }
293 
294 }