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.TimeUnit;
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(new Time(0.0, TimeUnit.SECOND), new Duration(0.0, TimeUnit.SECOND),
66                              new Duration(60.0, TimeUnit.MINUTE), 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-2016 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(
154                 final SimulatorInterface<Time, Duration, OTSSimTimeDouble> pSimulator)
155                 throws SimRuntimeException
156         {
157 
158             this.simulator = (OTSDEVSSimulatorInterface) pSimulator;
159 
160             try
161             {
162                 // open the NWB basic shape file
163                 Map<String, AbstractNWBRoadElement> roadMapNWB = getRoadMapNWB("A58", "NWB_A58", "NWB_wegvakken");
164 
165                 // open the shape file with driving lane information
166                 Map<String, AbstractNWBRoadElement> laneMapNWB = getRoadMapNWB("A58", "rijstroken_A58", "NWB_rijstroken");
167 
168                 // open the shape file with specific lane information such as on and off ramps and weaving areas
169                 Map<String, AbstractNWBRoadElement> specialLaneMapNWB =
170                         getRoadMapNWB("A58", "mengstroken_A58", "NWB_mengstroken");
171 
172                 combineNWBMaps(roadMapNWB, laneMapNWB, specialLaneMapNWB);
173             }
174             catch (NetworkException nwe)
175             {
176                 nwe.printStackTrace();
177             }
178 
179         }
180 
181         /**
182          * Combine the data (split road elements and add lane-attributes).
183          * @param roadMapNWB
184          * @param laneMapNWB
185          * @param specialLaneMapNWB
186          */
187         private void combineNWBMaps(Map<String, AbstractNWBRoadElement> roadMapNWB,
188                 Map<String, AbstractNWBRoadElement> laneMapNWB, Map<String, AbstractNWBRoadElement> specialLaneMapNWB)
189         {
190             // TODO : Alexander, de combinemaps moet verder worden uitgewerkt!
191             // Here, a segment of the NWB wegvak is being extracted (for instance the first part of the wegvak has an on-ramp)
192             // We should thus split this NWB-wegvak in two parts, the first part with the on-ramp (additional lane) and the
193             // remainder with the original attributes
194             for (AbstractNWBRoadElement laneElement : laneMapNWB.values())
195             {
196                 NWBDrivingLane lane = (NWBDrivingLane) laneElement;
197                 NWBRoadElement road = (NWBRoadElement) roadMapNWB.get(lane.getRoadId());
198                 List<LineString> lineSegmentList = splitRoad(road, lane);
199             }
200         }
201 
202         /**
203          * Split a road if there is a lane along a PART of this road.
204          * @param road
205          * @param segment
206          * @return list of linestrings
207          */
208         private List<LineString> splitRoad(NWBRoadElement road, NWBDrivingLane segment)
209         {
210             MultiLineString lines = (MultiLineString) road.getMyGeom();
211             LineString line = (LineString) lines.getGeometryN(0);
212             List<LineString> lineSegmentList = new ArrayList<>();
213             ;
214             // The getSubstring is copied from The JCS Conflation Suite (JCS): I assume it is not supported anymore, but can
215             // still be found...
216             lineSegmentList.add(SubstringLine.getSubstring(line, segment.getBeginDistance(), segment.getEndDistance()));
217             if (segment.getBeginDistance() > 0)
218             {
219                 lineSegmentList.add(SubstringLine.getSubstring(line, 0, segment.getBeginDistance()));
220             }
221             if (segment.getEndDistance() < road.getEndDistance())
222             {
223                 lineSegmentList.add(SubstringLine.getSubstring(line, 0, segment.getBeginDistance()));
224             }
225             return lineSegmentList;
226         }
227 
228         /**
229          * Import a list of road (link) elements from a shape file
230          * @param initialDir
231          * @param fileName
232          * @param shapeIdentifier
233          * @return map of naames road elements
234          * @throws NetworkException
235          */
236         private Map<String, AbstractNWBRoadElement> getRoadMapNWB(String initialDir, String fileName, String shapeIdentifier)
237                 throws NetworkException
238         {
239             FileDataStore dataStoreLink = null;
240             try
241             {
242                 dataStoreLink = newDatastore(initialDir, fileName);
243             }
244             catch (IOException e)
245             {
246                 // TODO Auto-generated catch block
247                 e.printStackTrace();
248             }
249             // open and read shape file links
250             FeatureIterator feautureIterator = getFeatureIterator(dataStoreLink);
251             // loop through the features and first retrieve the geometry
252             Map<String, AbstractNWBRoadElement> roadMApNWB = getFeatureAttributes(feautureIterator, shapeIdentifier);
253             return roadMApNWB;
254 
255         }
256 
257         /**
258          * @param initialDir
259          * @param fileName
260          * @return shapefile datastore
261          * @throws IOException
262          */
263         private FileDataStore newDatastore(String initialDir, final String fileName) throws IOException
264         {
265             try
266             {
267                 URL url = TestShapeParser.class.getResource("/");
268                 File file = new File(url.getFile() + "../../Data/" + initialDir);
269                 String fn = file.getCanonicalPath();
270                 fn = fn.replace('\\', '/');
271                 File iniDir = new File(fn);
272                 file = new File(iniDir, fileName + ".shp");
273 
274                 FileDataStore dataStoreLink = FileDataStoreFinder.getDataStore(file);
275                 return dataStoreLink;
276 
277             }
278             catch (IOException exception)
279             {
280                 exception.printStackTrace();
281             }
282             return null;
283 
284         }
285 
286         /**
287          * @param dataStore
288          * @return iterator
289          */
290         private FeatureIterator getFeatureIterator(FileDataStore dataStore)
291         {
292             try
293             {
294                 String[] typeNameLink = dataStore.getTypeNames();
295                 SimpleFeatureSource sourceLink;
296                 sourceLink = dataStore.getFeatureSource(typeNameLink[0]);
297                 SimpleFeatureCollection featuresLink = sourceLink.getFeatures();
298                 return featuresLink.features();
299 
300             }
301             catch (IOException e)
302             {
303                 // TODO Auto-generated catch block
304                 e.printStackTrace();
305             }
306             return null;
307         }
308 
309         /**
310          * @param feautureIterator
311          * @param shapeIdentifier
312          * @return feature attributes
313          * @throws NetworkException
314          */
315         private Map<String, AbstractNWBRoadElement> getFeatureAttributes(final FeatureIterator feautureIterator,
316                 String shapeIdentifier) throws NetworkException
317         {
318             Map<String, AbstractNWBRoadElement> roadMap = new HashMap<>();
319             while (feautureIterator.hasNext())
320             {
321                 Feature feature = feautureIterator.next();
322                 // geometry is always first
323                 if (shapeIdentifier.equals("NWB_wegvakken"))
324                 {
325                     NWBRoadElement road = getPropertiesNWB(feature);
326                     roadMap.put(road.getRoadId(), road);
327                 }
328                 else if (shapeIdentifier.equals("NWB_rijstroken"))
329                 {
330                     NWBDrivingLane road = getPropertiesDrivingLanes(feature);
331                     roadMap.put(road.getRoadId(), road);
332                 }
333                 else if (shapeIdentifier.equals("NWB_mengstroken"))
334                 {
335                     NWBDrivingLane road = getPropertiesSpecialLanes(feature);
336                     roadMap.put(road.getRoadId(), road);
337                 }
338             }
339             return roadMap;
340         }
341 
342         /**
343          * @param feature
344          * @return one road element with properties
345          * @throws NetworkException
346          */
347         private NWBRoadElement getPropertiesNWB(final Feature feature) throws NetworkException
348         {
349             Geometry theGeom = (Geometry) feature.getDefaultGeometryProperty().getValue();
350             Coordinate[] coordinates = theGeom.getCoordinates();
351             Property property = feature.getProperty("WVK_ID");
352             String roadId = property.getValue().toString();
353             property = feature.getProperty("JTE_ID_BEG");
354             String junctionIdBegin = property.getValue().toString();
355             property = feature.getProperty("JTE_ID_END");
356             String junctionIdEnd = property.getValue().toString();
357             property = feature.getProperty("ADMRICHTNG");
358             String adminDirection = property.getValue().toString();
359             property = feature.getProperty("RIJRICHTNG");
360             String drivingDirection = property.getValue().toString();
361             property = feature.getProperty("BEGINKM");
362             Double beginKM = parseDouble(property);
363             property = feature.getProperty("EINDKM");
364             Double endKM = parseDouble(property);
365             property = feature.getProperty("BEGAFSTAND");
366             Double beginDistance = parseDouble(property);
367             property = feature.getProperty("ENDAFSTAND");
368             Double endDistance = parseDouble(property);
369 
370             OTSNode startNode = new OTSNode(this.network, junctionIdBegin, new OTSPoint3D(coordinates[0]));
371             OTSNode endNode = new OTSNode(this.network, junctionIdEnd, new OTSPoint3D(coordinates[coordinates.length - 1]));
372             return new NWBRoadElement(theGeom, startNode, endNode, roadId, beginDistance, endDistance, junctionIdBegin,
373                     junctionIdEnd, adminDirection, drivingDirection, beginKM, endKM);
374         }
375 
376         /**
377          * @param feature
378          * @return info on one driving lane
379          * @throws NetworkException 
380          */
381         private NWBDrivingLane getPropertiesDrivingLanes(final Feature feature) throws NetworkException
382         {
383             Geometry theGeom = (Geometry) feature.getDefaultGeometryProperty().getValue();
384             Coordinate[] coordinates = theGeom.getCoordinates();
385 
386             Property property = feature.getProperty("WVK_ID");
387             String roadId = property.getValue().toString();
388 
389             property = feature.getProperty("KANTCODE");
390             String sideCode = property.getValue().toString();
391 
392             property = feature.getProperty("BEGAFSTAND");
393             Double beginDistance = parseDouble(property);
394 
395             property = feature.getProperty("ENDAFSTAND");
396             Double endDistance = parseDouble(property);
397 
398             property = feature.getProperty("OMSCHR");
399             String laneDescription = property.getValue().toString();
400             String[] lanes = laneDescription.split("->");
401             Integer startNumberOfLanes = Integer.parseInt(lanes[0].trim());
402             Integer endNumberOfLanes = Integer.parseInt(lanes[1].trim());
403 
404             String junctionIdBegin = roadId + "_" + beginDistance;
405             String junctionIdEnd = roadId + "_" + endDistance;
406             OTSNode startNode = new OTSNode(this.network, junctionIdBegin, new OTSPoint3D(coordinates[0]));
407             OTSNode endNode = new OTSNode(this.network, junctionIdEnd, new OTSPoint3D(coordinates[coordinates.length - 1]));
408             return new NWBDrivingLane(theGeom, startNode, endNode, roadId, beginDistance, endDistance, startNumberOfLanes,
409                     endNumberOfLanes, sideCode);
410         }
411 
412         /**
413          * @param feature
414          * @return info on one special lane
415          * @throws NetworkException 
416          */
417         private NWBDrivingLane getPropertiesSpecialLanes(final Feature feature) throws NetworkException
418         {
419             Geometry theGeom = (Geometry) feature.getDefaultGeometryProperty().getValue();
420             Coordinate[] coordinates = theGeom.getCoordinates();
421 
422             Property property = feature.getProperty("WVK_ID");
423             String roadId = property.getValue().toString();
424 
425             property = feature.getProperty("KANTCODE");
426             String sideCode = property.getValue().toString();
427 
428             property = feature.getProperty("BEGAFSTAND");
429             Double beginDistance = parseDouble(property);
430 
431             property = feature.getProperty("ENDAFSTAND");
432             Double endDistance = parseDouble(property);
433 
434             property = feature.getProperty("OMSCHR");
435             String laneType = property.getValue().toString();
436 
437             property = feature.getProperty("AANT_MSK");
438             String laneDescription = property.getValue().toString();
439             String[] lanes = laneDescription.split("->");
440             Integer startNumberOfLanes = Integer.parseInt(lanes[0].trim().substring(0, 1));
441             Integer endNumberOfLanes = Integer.parseInt(lanes[1].trim().substring(0, 1));
442 
443             String junctionIdBegin = roadId + "_" + beginDistance;
444             String junctionIdEnd = roadId + "_" + endDistance;
445             OTSNode startNode = new OTSNode(this.network, junctionIdBegin, new OTSPoint3D(coordinates[0]));
446             OTSNode endNode = new OTSNode(this.network, junctionIdEnd, new OTSPoint3D(coordinates[coordinates.length - 1]));
447             return new NWBDrivingLane(theGeom, startNode, endNode, roadId, beginDistance, endDistance, startNumberOfLanes,
448                     endNumberOfLanes, sideCode);
449         }
450 
451         /**
452          * @param property
453          * @return a double
454          */
455         private Double parseDouble(Property property)
456         {
457             if (property.getValue() != null)
458             {
459                 if (property.getValue().toString() != null)
460                 {
461                     return Double.parseDouble(property.getValue().toString());
462                 }
463             }
464             return Double.NaN;
465         }
466 
467         /** {@inheritDoc} */
468         @Override
469         public SimulatorInterface<Time, Duration, OTSSimTimeDouble> getSimulator()
470         {
471             return this.simulator;
472         }
473 
474         /** {@inheritDoc} */
475         @Override
476         public OTSNetwork getNetwork()
477         {
478             return this.network;
479         }
480 
481         /** {@inheritDoc} */
482         @Override
483         public final String toString()
484         {
485             return "TestXMLModel [simulator=" + this.simulator + "]";
486         }
487 
488     }
489 
490 }