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