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