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