View Javadoc
1   package org.opentrafficsim.road.network.factory.shape;
2   
3   import java.awt.geom.Rectangle2D;
4   import java.io.File;
5   import java.io.IOException;
6   import java.net.URL;
7   import java.util.ArrayList;
8   import java.util.HashMap;
9   import java.util.List;
10  import java.util.Map;
11  
12  import javax.naming.NamingException;
13  import javax.swing.SwingUtilities;
14  
15  import org.djunits.unit.DurationUnit;
16  import org.djunits.value.vdouble.scalar.Duration;
17  import org.djunits.value.vdouble.scalar.Time;
18  import org.geotools.data.FileDataStore;
19  import org.geotools.data.FileDataStoreFinder;
20  import org.geotools.data.simple.SimpleFeatureCollection;
21  import org.geotools.data.simple.SimpleFeatureSource;
22  import org.geotools.feature.FeatureIterator;
23  import org.opengis.feature.Feature;
24  import org.opengis.feature.Property;
25  import org.opentrafficsim.base.modelproperties.PropertyException;
26  import org.opentrafficsim.core.dsol.OTSDEVSSimulatorInterface;
27  import org.opentrafficsim.core.dsol.OTSModelInterface;
28  import org.opentrafficsim.core.dsol.OTSSimTimeDouble;
29  import org.opentrafficsim.core.geometry.OTSPoint3D;
30  import org.opentrafficsim.core.gtu.animation.GTUColorer;
31  import org.opentrafficsim.core.network.NetworkException;
32  import org.opentrafficsim.core.network.OTSNetwork;
33  import org.opentrafficsim.core.network.OTSNode;
34  import org.opentrafficsim.simulationengine.AbstractWrappableAnimation;
35  import org.opentrafficsim.simulationengine.OTSSimulationException;
36  import org.opentrafficsim.simulationengine.SimpleSimulatorInterface;
37  
38  import com.vividsolutions.jts.geom.Coordinate;
39  import com.vividsolutions.jts.geom.Geometry;
40  import com.vividsolutions.jts.geom.LineString;
41  import com.vividsolutions.jts.geom.MultiLineString;
42  
43  import nl.tudelft.simulation.dsol.SimRuntimeException;
44  import nl.tudelft.simulation.dsol.simulators.SimulatorInterface;
45  
46  public class TestShapeParser extends AbstractWrappableAnimation
47  {
48  
49      /**
50       * Main program.
51       * @param args String[]; the command line arguments (not used)
52       * @throws SimRuntimeException should never happen
53       */
54      public static void main(final String[] args) throws SimRuntimeException
55      {
56          SwingUtilities.invokeLater(new Runnable()
57          {
58              @Override
59              public void run()
60              {
61                  try
62                  {
63                      TestShapeParser xmlModel = new TestShapeParser();
64                      // 1 hour simulation run for testing
65                      xmlModel.buildAnimator(Time.ZERO, Duration.ZERO, new Duration(60.0, DurationUnit.MINUTE),
66                              new ArrayList<org.opentrafficsim.base.modelproperties.Property<?>>(), null, true);
67                  }
68                  catch (SimRuntimeException | NamingException | OTSSimulationException | PropertyException exception)
69                  {
70                      exception.printStackTrace();
71                  }
72              }
73          });
74      }
75  
76      /** {@inheritDoc} */
77      @Override
78      public final String shortName()
79      {
80          return "TestXMLModel";
81      }
82  
83      /** {@inheritDoc} */
84      @Override
85      public final String description()
86      {
87          return "TestXMLModel";
88      }
89  
90      /** {@inheritDoc} */
91      @Override
92      public final void stopTimersThreads()
93      {
94          super.stopTimersThreads();
95      }
96  
97      /** {@inheritDoc} */
98      @Override
99      protected final void addTabs(final SimpleSimulatorInterface simulator)
100     {
101         return;
102     }
103 
104     /** {@inheritDoc} */
105     @Override
106     protected final OTSModelInterface makeModel(final GTUColorer colorer)
107     {
108         return new GisNDWImport();
109     }
110 
111     /** {@inheritDoc} */
112     @Override
113     protected final java.awt.geom.Rectangle2D.Double makeAnimationRectangle()
114     {
115         return new Rectangle2D.Double(-1000, -1000, 2000, 2000);
116     }
117 
118     /** {@inheritDoc} */
119     @Override
120     public final String toString()
121     {
122         return "TestGISParser []";
123     }
124 
125     /**
126      * Model to test the Esri Shape File Format parser.
127      * <p>
128      * Copyright (c) 2013-2017 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. <br>
129      * All rights reserved. BSD-style license. See <a href="http://opentrafficsim.org/docs/license.html">OpenTrafficSim
130      * License</a>.
131      * <p>
132      * $LastChangedDate: 2016-08-26 16:34:41 +0200 (Fri, 26 Aug 2016) $, @version $Revision: 2150 $, by $Author: gtamminga $,
133      * initial version un 27, 2015 <br>
134      * @author <a href="http://www.tbm.tudelft.nl/averbraeck">Alexander Verbraeck</a>
135      * @author <a href="http://www.tudelft.nl/pknoppers">Peter Knoppers</a>
136      */
137     /**
138      * @author P070518
139      */
140     class GisNDWImport implements OTSModelInterface
141     {
142         /** */
143         private static final long serialVersionUID = 20141121L;
144 
145         /** The simulator. */
146         private OTSDEVSSimulatorInterface simulator;
147 
148         /** The network. */
149         private final OTSNetwork network = new OTSNetwork("test network");
150 
151         /** {@inheritDoc} */
152         @Override
153         public final void constructModel(final SimulatorInterface<Time, Duration, OTSSimTimeDouble> pSimulator)
154                 throws SimRuntimeException
155         {
156 
157             this.simulator = (OTSDEVSSimulatorInterface) pSimulator;
158 
159             try
160             {
161                 // open the NWB basic shape file
162                 Map<String, AbstractNWBRoadElement> roadMapNWB = getRoadMapNWB("A58", "NWB_A58", "NWB_wegvakken");
163 
164                 // open the shape file with driving lane information
165                 Map<String, AbstractNWBRoadElement> laneMapNWB = getRoadMapNWB("A58", "rijstroken_A58", "NWB_rijstroken");
166 
167                 // open the shape file with specific lane information such as on and off ramps and weaving areas
168                 Map<String, AbstractNWBRoadElement> specialLaneMapNWB =
169                         getRoadMapNWB("A58", "mengstroken_A58", "NWB_mengstroken");
170 
171                 combineNWBMaps(roadMapNWB, laneMapNWB, specialLaneMapNWB);
172             }
173             catch (NetworkException nwe)
174             {
175                 nwe.printStackTrace();
176             }
177 
178         }
179 
180         /**
181          * Combine the data (split road elements and add lane-attributes).
182          * @param roadMapNWB
183          * @param laneMapNWB
184          * @param specialLaneMapNWB
185          */
186         private void combineNWBMaps(Map<String, AbstractNWBRoadElement> roadMapNWB,
187                 Map<String, AbstractNWBRoadElement> laneMapNWB, Map<String, AbstractNWBRoadElement> specialLaneMapNWB)
188         {
189             // TODO : Alexander, de combinemaps moet verder worden uitgewerkt!
190             // Here, a segment of the NWB wegvak is being extracted (for instance the first part of the wegvak has an on-ramp)
191             // We should thus split this NWB-wegvak in two parts, the first part with the on-ramp (additional lane) and the
192             // remainder with the original attributes
193             for (AbstractNWBRoadElement laneElement : laneMapNWB.values())
194             {
195                 NWBDrivingLane lane = (NWBDrivingLane) laneElement;
196                 NWBRoadElement road = (NWBRoadElement) roadMapNWB.get(lane.getRoadId());
197                 List<LineString> lineSegmentList = splitRoad(road, lane);
198             }
199         }
200 
201         /**
202          * Split a road if there is a lane along a PART of this road.
203          * @param road
204          * @param segment
205          * @return list of linestrings
206          */
207         private List<LineString> splitRoad(NWBRoadElement road, NWBDrivingLane segment)
208         {
209             MultiLineString lines = (MultiLineString) road.getMyGeom();
210             LineString line = (LineString) lines.getGeometryN(0);
211             List<LineString> lineSegmentList = new ArrayList<>();
212             ;
213             // The getSubstring is copied from The JCS Conflation Suite (JCS): I assume it is not supported anymore, but can
214             // still be found...
215             lineSegmentList.add(SubstringLine.getSubstring(line, segment.getBeginDistance(), segment.getEndDistance()));
216             if (segment.getBeginDistance() > 0)
217             {
218                 lineSegmentList.add(SubstringLine.getSubstring(line, 0, segment.getBeginDistance()));
219             }
220             if (segment.getEndDistance() < road.getEndDistance())
221             {
222                 lineSegmentList.add(SubstringLine.getSubstring(line, 0, segment.getBeginDistance()));
223             }
224             return lineSegmentList;
225         }
226 
227         /**
228          * Import a list of road (link) elements from a shape file
229          * @param initialDir
230          * @param fileName
231          * @param shapeIdentifier
232          * @return map of naames road elements
233          * @throws NetworkException
234          */
235         private Map<String, AbstractNWBRoadElement> getRoadMapNWB(String initialDir, String fileName, String shapeIdentifier)
236                 throws NetworkException
237         {
238             FileDataStore dataStoreLink = null;
239             try
240             {
241                 dataStoreLink = newDatastore(initialDir, fileName);
242             }
243             catch (IOException e)
244             {
245                 // TODO Auto-generated catch block
246                 e.printStackTrace();
247             }
248             // open and read shape file links
249             FeatureIterator feautureIterator = getFeatureIterator(dataStoreLink);
250             // loop through the features and first retrieve the geometry
251             Map<String, AbstractNWBRoadElement> roadMApNWB = getFeatureAttributes(feautureIterator, shapeIdentifier);
252             return roadMApNWB;
253 
254         }
255 
256         /**
257          * @param initialDir
258          * @param fileName
259          * @return shapefile datastore
260          * @throws IOException
261          */
262         private FileDataStore newDatastore(String initialDir, final String fileName) throws IOException
263         {
264             try
265             {
266                 URL url = TestShapeParser.class.getResource("/");
267                 File file = new File(url.getFile() + "../../Data/" + initialDir);
268                 String fn = file.getCanonicalPath();
269                 fn = fn.replace('\\', '/');
270                 File iniDir = new File(fn);
271                 file = new File(iniDir, fileName + ".shp");
272 
273                 FileDataStore dataStoreLink = FileDataStoreFinder.getDataStore(file);
274                 return dataStoreLink;
275 
276             }
277             catch (IOException exception)
278             {
279                 exception.printStackTrace();
280             }
281             return null;
282 
283         }
284 
285         /**
286          * @param dataStore
287          * @return iterator
288          */
289         private FeatureIterator getFeatureIterator(FileDataStore dataStore)
290         {
291             try
292             {
293                 String[] typeNameLink = dataStore.getTypeNames();
294                 SimpleFeatureSource sourceLink;
295                 sourceLink = dataStore.getFeatureSource(typeNameLink[0]);
296                 SimpleFeatureCollection featuresLink = sourceLink.getFeatures();
297                 return featuresLink.features();
298 
299             }
300             catch (IOException e)
301             {
302                 // TODO Auto-generated catch block
303                 e.printStackTrace();
304             }
305             return null;
306         }
307 
308         /**
309          * @param feautureIterator
310          * @param shapeIdentifier
311          * @return feature attributes
312          * @throws NetworkException
313          */
314         private Map<String, AbstractNWBRoadElement> getFeatureAttributes(final FeatureIterator feautureIterator,
315                 String shapeIdentifier) throws NetworkException
316         {
317             Map<String, AbstractNWBRoadElement> roadMap = new HashMap<>();
318             while (feautureIterator.hasNext())
319             {
320                 Feature feature = feautureIterator.next();
321                 // geometry is always first
322                 if (shapeIdentifier.equals("NWB_wegvakken"))
323                 {
324                     NWBRoadElement road = getPropertiesNWB(feature);
325                     roadMap.put(road.getRoadId(), road);
326                 }
327                 else if (shapeIdentifier.equals("NWB_rijstroken"))
328                 {
329                     NWBDrivingLane road = getPropertiesDrivingLanes(feature);
330                     roadMap.put(road.getRoadId(), road);
331                 }
332                 else if (shapeIdentifier.equals("NWB_mengstroken"))
333                 {
334                     NWBDrivingLane road = getPropertiesSpecialLanes(feature);
335                     roadMap.put(road.getRoadId(), road);
336                 }
337             }
338             return roadMap;
339         }
340 
341         /**
342          * @param feature
343          * @return one road element with properties
344          * @throws NetworkException
345          */
346         private NWBRoadElement getPropertiesNWB(final Feature feature) throws NetworkException
347         {
348             Geometry theGeom = (Geometry) feature.getDefaultGeometryProperty().getValue();
349             Coordinate[] coordinates = theGeom.getCoordinates();
350             Property property = feature.getProperty("WVK_ID");
351             String roadId = property.getValue().toString();
352             property = feature.getProperty("JTE_ID_BEG");
353             String junctionIdBegin = property.getValue().toString();
354             property = feature.getProperty("JTE_ID_END");
355             String junctionIdEnd = property.getValue().toString();
356             property = feature.getProperty("ADMRICHTNG");
357             String adminDirection = property.getValue().toString();
358             property = feature.getProperty("RIJRICHTNG");
359             String drivingDirection = property.getValue().toString();
360             property = feature.getProperty("BEGINKM");
361             Double beginKM = parseDouble(property);
362             property = feature.getProperty("EINDKM");
363             Double endKM = parseDouble(property);
364             property = feature.getProperty("BEGAFSTAND");
365             Double beginDistance = parseDouble(property);
366             property = feature.getProperty("ENDAFSTAND");
367             Double endDistance = parseDouble(property);
368 
369             OTSNode startNode = new OTSNode(this.network, junctionIdBegin, new OTSPoint3D(coordinates[0]));
370             OTSNode endNode = new OTSNode(this.network, junctionIdEnd, new OTSPoint3D(coordinates[coordinates.length - 1]));
371             return new NWBRoadElement(theGeom, startNode, endNode, roadId, beginDistance, endDistance, junctionIdBegin,
372                     junctionIdEnd, adminDirection, drivingDirection, beginKM, endKM);
373         }
374 
375         /**
376          * @param feature
377          * @return info on one driving lane
378          * @throws NetworkException
379          */
380         private NWBDrivingLane getPropertiesDrivingLanes(final Feature feature) throws NetworkException
381         {
382             Geometry theGeom = (Geometry) feature.getDefaultGeometryProperty().getValue();
383             Coordinate[] coordinates = theGeom.getCoordinates();
384 
385             Property property = feature.getProperty("WVK_ID");
386             String roadId = property.getValue().toString();
387 
388             property = feature.getProperty("KANTCODE");
389             String sideCode = property.getValue().toString();
390 
391             property = feature.getProperty("BEGAFSTAND");
392             Double beginDistance = parseDouble(property);
393 
394             property = feature.getProperty("ENDAFSTAND");
395             Double endDistance = parseDouble(property);
396 
397             property = feature.getProperty("OMSCHR");
398             String laneDescription = property.getValue().toString();
399             String[] lanes = laneDescription.split("->");
400             Integer startNumberOfLanes = Integer.parseInt(lanes[0].trim());
401             Integer endNumberOfLanes = Integer.parseInt(lanes[1].trim());
402 
403             String junctionIdBegin = roadId + "_" + beginDistance;
404             String junctionIdEnd = roadId + "_" + endDistance;
405             OTSNode startNode = new OTSNode(this.network, junctionIdBegin, new OTSPoint3D(coordinates[0]));
406             OTSNode endNode = new OTSNode(this.network, junctionIdEnd, new OTSPoint3D(coordinates[coordinates.length - 1]));
407             return new NWBDrivingLane(theGeom, startNode, endNode, roadId, beginDistance, endDistance, startNumberOfLanes,
408                     endNumberOfLanes, sideCode);
409         }
410 
411         /**
412          * @param feature
413          * @return info on one special lane
414          * @throws NetworkException
415          */
416         private NWBDrivingLane getPropertiesSpecialLanes(final Feature feature) throws NetworkException
417         {
418             Geometry theGeom = (Geometry) feature.getDefaultGeometryProperty().getValue();
419             Coordinate[] coordinates = theGeom.getCoordinates();
420 
421             Property property = feature.getProperty("WVK_ID");
422             String roadId = property.getValue().toString();
423 
424             property = feature.getProperty("KANTCODE");
425             String sideCode = property.getValue().toString();
426 
427             property = feature.getProperty("BEGAFSTAND");
428             Double beginDistance = parseDouble(property);
429 
430             property = feature.getProperty("ENDAFSTAND");
431             Double endDistance = parseDouble(property);
432 
433             property = feature.getProperty("OMSCHR");
434             String laneType = property.getValue().toString();
435 
436             property = feature.getProperty("AANT_MSK");
437             String laneDescription = property.getValue().toString();
438             String[] lanes = laneDescription.split("->");
439             Integer startNumberOfLanes = Integer.parseInt(lanes[0].trim().substring(0, 1));
440             Integer endNumberOfLanes = Integer.parseInt(lanes[1].trim().substring(0, 1));
441 
442             String junctionIdBegin = roadId + "_" + beginDistance;
443             String junctionIdEnd = roadId + "_" + endDistance;
444             OTSNode startNode = new OTSNode(this.network, junctionIdBegin, new OTSPoint3D(coordinates[0]));
445             OTSNode endNode = new OTSNode(this.network, junctionIdEnd, new OTSPoint3D(coordinates[coordinates.length - 1]));
446             return new NWBDrivingLane(theGeom, startNode, endNode, roadId, beginDistance, endDistance, startNumberOfLanes,
447                     endNumberOfLanes, sideCode);
448         }
449 
450         /**
451          * @param property
452          * @return a double
453          */
454         private Double parseDouble(Property property)
455         {
456             if (property.getValue() != null)
457             {
458                 if (property.getValue().toString() != null)
459                 {
460                     return Double.parseDouble(property.getValue().toString());
461                 }
462             }
463             return Double.NaN;
464         }
465 
466         /** {@inheritDoc} */
467         @Override
468         public SimulatorInterface<Time, Duration, OTSSimTimeDouble> getSimulator()
469         {
470             return this.simulator;
471         }
472 
473         /** {@inheritDoc} */
474         @Override
475         public OTSNetwork getNetwork()
476         {
477             return this.network;
478         }
479 
480         /** {@inheritDoc} */
481         @Override
482         public final String toString()
483         {
484             return "TestXMLModel [simulator=" + this.simulator + "]";
485         }
486 
487     }
488 
489 }