1   package org.opentrafficsim.demo.geometry.shape;
2   
3   import java.awt.Color;
4   import java.io.File;
5   import java.io.IOException;
6   import java.net.URL;
7   import java.rmi.RemoteException;
8   import java.util.Collection;
9   import java.util.LinkedHashMap;
10  import java.util.Map;
11  
12  import javax.naming.NamingException;
13  
14  import org.djunits.unit.util.UNITS;
15  import org.djunits.value.vdouble.scalar.Direction;
16  import org.djunits.value.vdouble.scalar.Frequency;
17  import org.djunits.value.vdouble.scalar.Length;
18  import org.djunits.value.vdouble.scalar.Speed;
19  import org.geotools.data.FileDataStoreFinder;
20  import org.geotools.data.shapefile.ShapefileDataStore;
21  import org.geotools.data.simple.SimpleFeatureCollection;
22  import org.geotools.data.simple.SimpleFeatureIterator;
23  import org.geotools.data.simple.SimpleFeatureSource;
24  import org.geotools.geometry.jts.JTSFactoryFinder;
25  import org.locationtech.jts.geom.Coordinate;
26  import org.locationtech.jts.geom.Geometry;
27  import org.locationtech.jts.geom.GeometryFactory;
28  import org.locationtech.jts.geom.LineString;
29  import org.locationtech.jts.geom.Point;
30  import org.opengis.feature.Property;
31  import org.opengis.feature.simple.SimpleFeature;
32  import org.opentrafficsim.core.dsol.OTSSimulatorInterface;
33  import org.opentrafficsim.core.geometry.OTSGeometryException;
34  import org.opentrafficsim.core.geometry.OTSLine3D;
35  import org.opentrafficsim.core.geometry.OTSPoint3D;
36  import org.opentrafficsim.core.network.Link;
37  import org.opentrafficsim.core.network.LinkType;
38  import org.opentrafficsim.core.network.LongitudinalDirectionality;
39  import org.opentrafficsim.core.network.Network;
40  import org.opentrafficsim.core.network.NetworkException;
41  import org.opentrafficsim.draw.network.LinkAnimation;
42  import org.opentrafficsim.draw.road.LaneAnimation;
43  import org.opentrafficsim.draw.road.ShoulderAnimation;
44  import org.opentrafficsim.road.network.OTSRoadNetwork;
45  import org.opentrafficsim.road.network.lane.CrossSectionLink;
46  import org.opentrafficsim.road.network.lane.Lane;
47  import org.opentrafficsim.road.network.lane.NoTrafficLane;
48  import org.opentrafficsim.road.network.lane.OTSRoadNode;
49  import org.opentrafficsim.road.network.lane.Shoulder;
50  import org.opentrafficsim.road.network.lane.changing.LaneKeepingPolicy;
51  
52  import nl.tudelft.simulation.dsol.simulators.SimulatorInterface;
53  
54  
55  
56  
57  
58  
59  
60  
61  
62  
63  
64  public final class ShapeFileReader implements UNITS
65  {
66      
67      private ShapeFileReader()
68      {
69          
70      }
71  
72      
73  
74  
75  
76  
77  
78  
79  
80  
81      public static Map<String, OTSRoadNode> readNodes(final Network network, final String shapeFileName, final String numberType,
82              final boolean returnCentroid, final boolean allCentroids) throws IOException
83      {
84          
85  
86  
87  
88  
89  
90  
91  
92  
93          URL url;
94          if (new File(shapeFileName).canRead())
95          {
96              url = new File(shapeFileName).toURI().toURL();
97          }
98          else
99          {
100             url = ShapeFileReader.class.getResource(shapeFileName);
101         }
102         ShapefileDataStore storeNodes = (ShapefileDataStore) FileDataStoreFinder.getDataStore(url);
103 
104         Map<String, OTSRoadNode> nodes = new LinkedHashMap<>();
105 
106         SimpleFeatureSource featureSourceNodes = storeNodes.getFeatureSource();
107         SimpleFeatureCollection featureCollectionNodes = featureSourceNodes.getFeatures();
108         SimpleFeatureIterator iterator = featureCollectionNodes.features();
109         try
110         {
111             while (iterator.hasNext())
112             {
113                 SimpleFeature feature = iterator.next();
114                 Coordinate coordinate = ((Point) feature.getAttribute("the_geom")).getCoordinate();
115                 String nr = removeQuotes(String.valueOf(feature.getAttribute(numberType)));
116                 boolean addThisNode = false;
117                 if (returnCentroid)
118                 {
119                     if (nr.substring(0, 1).equals("C") || allCentroids)
120                     {
121                         addThisNode = true;
122                     }
123                 }
124                 else
125                 {
126                     if (nr == null)
127                     {
128                         System.out.println("null found");
129                     }
130                     if (!nr.substring(0, 1).equals("C"))
131                     {
132                         addThisNode = true;
133                     }
134                 }
135                 if (addThisNode)
136                 {
137                     OTSRoadNode node =
138                             new OTSRoadNode(network, nr, new OTSPoint3D(coordinate), Direction.instantiateSI(Double.NaN));
139                     nodes.put(nr, node);
140                 }
141             }
142         }
143         catch (Exception problem)
144         {
145             problem.printStackTrace();
146         }
147         finally
148         {
149             iterator.close();
150             storeNodes.dispose();
151         }
152         System.out.println("aantal knopen (353): geteld " + nodes.size());
153         return nodes;
154     }
155 
156     
157 
158 
159 
160     public static boolean inspectNodeCentroid(final String number)
161     {
162         boolean isCentroid = false;
163         String[] names = removeQuotes(number).split(":");
164         String name = names[0];
165         if (name.charAt(0) == 'C')
166         {
167             isCentroid = true;
168         }
169         return isCentroid;
170     }
171 
172     
173 
174 
175 
176 
177 
178 
179 
180     public static void readLinks(final OTSRoadNetwork network, final String shapeFileName, final Map<String, Link> links,
181             final Map<String, OTSRoadNode> nodes, final OTSSimulatorInterface simulator) throws IOException
182     {
183         
184 
185 
186 
187 
188 
189 
190 
191 
192 
193 
194 
195 
196 
197 
198 
199 
200         URL url;
201         if (new File(shapeFileName).canRead())
202         {
203             url = new File(shapeFileName).toURI().toURL();
204         }
205         else
206         {
207             url = ShapeFileReader.class.getResource(shapeFileName);
208         }
209 
210         ShapefileDataStore storeLinks = (ShapefileDataStore) FileDataStoreFinder.getDataStore(url);
211         SimpleFeatureSource featureSourceLinks = storeLinks.getFeatureSource();
212         SimpleFeatureCollection featureCollectionLinks = featureSourceLinks.getFeatures();
213         SimpleFeatureIterator iterator = featureCollectionLinks.features();
214 
215         try
216         {
217             while (iterator.hasNext())
218             {
219                 SimpleFeature feature = iterator.next();
220                 GeometryFactory geometryFactory = JTSFactoryFinder.getGeometryFactory();
221                 Geometry geometry = (Geometry) feature.getAttribute("the_geom");
222                 Coordinate[] coords = geometry.getCoordinates();
223                 LineString line = geometryFactory.createLineString(coords);
224                 String nr = String.valueOf(feature.getAttribute("LINKNR"));
225                 String nrBA = nr + "_BA";
226                 String name = String.valueOf(feature.getAttribute("NAME"));
227                 
228                 
229                 double lengthIn = Double.parseDouble(String.valueOf(feature.getAttribute("LENGTH")));
230                 Length length = new Length(lengthIn, KILOMETER);
231                 short direction = (short) Long.parseLong(String.valueOf(feature.getAttribute("DIRECTION")));
232                 String lNodeA = String.valueOf(feature.getAttribute("ANODE"));
233                 String lNodeB = String.valueOf(feature.getAttribute("BNODE"));
234                 
235                 String linkTag = (String) feature.getAttribute("LINKTAG");
236                 String wegtype = (String) feature.getAttribute("WEGTYPEAB");
237                 String typeWegVak = (String) feature.getAttribute("TYPEWEGVAB");
238                 String typeWeg = (String) feature.getAttribute("TYPEWEG_AB");
239                 Double speedIn = Double.parseDouble(String.valueOf(feature.getAttribute("SPEEDAB")));
240                 Speed speed = new Speed(speedIn, KM_PER_HOUR);
241                 double capacityIn = Double.parseDouble(String.valueOf(feature.getAttribute("CAPACITYAB")));
242                 Frequency capacity = new Frequency(capacityIn, PER_HOUR);
243                 
244                 
245                 OTSRoadNode nodeA = nodes.get(lNodeA);
246                 OTSRoadNode nodeB = nodes.get(lNodeB);
247 
248                 if (nodeA != null && nodeB != null)
249                 {
250                     CrossSectionLink linkAB = null;
251                     CrossSectionLink linkBA = null;
252                     linkAB = new CrossSectionLink(network, nr, nodeA, nodeB, network.getLinkType(LinkType.DEFAULTS.ROAD),
253                             new OTSLine3D(new OTSPoint3D[] {nodeA.getPoint(), nodeB.getPoint()}), simulator,
254                             LaneKeepingPolicy.KEEPRIGHT);
255                     animate(linkAB, typeWegVak, simulator);
256                     linkBA = new CrossSectionLink(network, nrBA, nodeB, nodeA, network.getLinkType(LinkType.DEFAULTS.ROAD),
257                             new OTSLine3D(new OTSPoint3D[] {nodeB.getPoint(), nodeA.getPoint()}), simulator,
258                             LaneKeepingPolicy.KEEPRIGHT);
259                     animate(linkBA, typeWegVak, simulator);
260                     if (direction == 1)
261                     {
262                         links.put(nr, linkAB);
263                     }
264                     else if (direction == 2)
265                     {
266                         links.put(nrBA, linkBA);
267                     }
268                     else if (direction == 3)
269                     {
270                         links.put(nr, linkAB);
271                         links.put(nrBA, linkBA);
272                     }
273 
274                 }
275                 else
276                 {
277                     System.out.println("Node lNodeA=" + lNodeA + " or lNodeB=" + lNodeB + " not found for linknr=" + nr
278                             + ", name=" + name);
279                 }
280             }
281 
282         }
283         catch (Exception problem)
284         {
285             problem.printStackTrace();
286         }
287         finally
288         {
289             iterator.close();
290             storeLinks.dispose();
291         }
292 
293     }
294 
295     
296 
297 
298 
299     public static void shapeFileInfo(final String shapeFileName) throws IOException
300     {
301         URL url;
302         if (new File(shapeFileName).canRead())
303         {
304             url = new File(shapeFileName).toURI().toURL();
305         }
306         else
307         {
308             url = ShapeFileReader.class.getResource(shapeFileName);
309         }
310         ShapefileDataStore store = (ShapefileDataStore) FileDataStoreFinder.getDataStore(url);
311 
312         SimpleFeatureSource featureSource = store.getFeatureSource();
313         SimpleFeatureCollection featureCollection = featureSource.getFeatures();
314         SimpleFeatureIterator iterator = featureCollection.features();
315         try
316         {
317             while (iterator.hasNext())
318             {
319                 SimpleFeature feature = iterator.next();
320                 Collection<Property> areaProperties = feature.getProperties();
321                 for (Property p : areaProperties)
322                 {
323                     System.out.println(p.getName() + " " + p.getValue().getClass() + " " + p.getValue().toString());
324                 }
325                 return;
326             }
327         }
328         catch (Exception problem)
329         {
330             problem.printStackTrace();
331         }
332         finally
333         {
334             iterator.close();
335             store.dispose();
336         }
337     }
338 
339     
340 
341 
342 
343     public static String removeQuotes(final String name)
344     {
345         String newName = name;
346         if (newName.length() >= 2 && newName.charAt(0) == '"' && newName.charAt(newName.length() - 1) == '"')
347         {
348             newName = newName.substring(1, newName.length() - 1);
349         }
350         return newName;
351     }
352 
353     
354 
355 
356 
357 
358 
359 
360 
361     private static void animate(final CrossSectionLink link, final String wegType,
362             final SimulatorInterface.TimeDoubleUnit simulator) throws NamingException, NetworkException, RemoteException
363     {
364         
365         new LinkAnimation(link, simulator, 0.1f);
366         if (wegType.startsWith("asw") || wegType.startsWith("80"))
367         {
368             int spits = 0;
369             int n = 1;
370             if (wegType.contains("2x2"))
371             {
372                 n = 2;
373             }
374             if (wegType.contains("2x3"))
375             {
376                 n = 3;
377             }
378             if (wegType.contains("2x4"))
379             {
380                 n = 4;
381             }
382             if (wegType.contains("2x5"))
383             {
384                 n = 5;
385             }
386             if (wegType.contains("+ 1") || wegType.contains("+1"))
387             {
388                 spits = 1;
389             }
390             if (wegType.contains("+ 2") || wegType.contains("+2"))
391             {
392                 spits = 2;
393             }
394             addNLanes(n, spits, link, simulator);
395         }
396         if (wegType.startsWith("stads"))
397         {
398             int n = 1;
399             if (wegType.contains("2x2"))
400             {
401                 n = 2;
402             }
403             if (wegType.contains("2x3"))
404             {
405                 n = 3;
406             }
407             boolean middenberm = wegType.contains("met middenberm");
408             addCityStreetLanes(n, middenberm, link, simulator);
409         }
410         else
411         {
412             addCityStreet(link, simulator);
413         }
414     }
415 
416     
417 
418 
419 
420 
421 
422 
423     private static void addNLanes(final int n, final int spits, final CrossSectionLink link,
424             final SimulatorInterface.TimeDoubleUnit simulator) throws NetworkException
425     {
426         
427         
428         Length m05 = new Length(0.5, METER);
429         Length m10 = new Length(1.0, METER);
430         Length m35 = new Length(3.5, METER);
431         Speed speedLimit = new Speed(100, KM_PER_HOUR);
432 
433         try
434         {
435             
436             Shoulder sM = new Shoulder(link, "sM", new Length(0.0, METER), m10);
437             new ShoulderAnimation(sM, simulator, Color.GREEN);
438             for (int i = -1; i <= 1; i += 2)
439             {
440                 LongitudinalDirectionality dir =
441                         (i < 0) ? LongitudinalDirectionality.DIR_PLUS : LongitudinalDirectionality.DIR_MINUS;
442                 
443                 String lr = i < 0 ? "L" : "R";
444                 
445                 Lane laneEM = new NoTrafficLane(link, lr + "." + "EM", new Length(i * 0.75, METER), new Length(i * 0.75, METER),
446                         m05, m05);
447                 new LaneAnimation(laneEM, simulator, Color.LIGHT_GRAY);
448                 double lat = 1;
449                 for (int j = 0; j < n; j++)
450                 {
451                     lat += i * 1.75;
452                     Lane lane = new Lane(link, "lane." + lr + "." + j, new Length(lat, METER), new Length(lat, METER), m35, m35,
453                             null, speedLimit);
454                     new LaneAnimation(lane, simulator, Color.GRAY);
455                     lat += i * 1.75;
456                 }
457                 
458                 for (int j = 0; j < spits; j++)
459                 {
460                     lat += i * 1.75;
461                     Lane lane = new NoTrafficLane(link, "extra." + lr + "." + j, new Length(lat, METER), new Length(lat, METER),
462                             m35, m35);
463                     new LaneAnimation(lane, simulator, Color.LIGHT_GRAY);
464                     lat += i * 1.75;
465                 }
466                 Lane laneEO = new NoTrafficLane(link, lr + "." + "EO", new Length(lat + i * 0.25, METER),
467                         new Length(lat + i * 0.25, METER), m05, m05);
468                 new LaneAnimation(laneEO, simulator, Color.LIGHT_GRAY);
469                 lat += i * 0.5;
470                 Shoulder sO = new Shoulder(link, lr + "." + "sO", new Length(lat, METER), m10);
471                 new ShoulderAnimation(sO, simulator, Color.GREEN);
472             }
473         }
474         catch (NamingException | RemoteException | OTSGeometryException ne)
475         {
476             
477         }
478     }
479 
480     
481 
482 
483 
484 
485 
486 
487     private static void addCityStreetLanes(final int n, final boolean middenberm, final CrossSectionLink link,
488             final SimulatorInterface.TimeDoubleUnit simulator) throws NetworkException
489     {
490         
491         
492         Length m10 = new Length(1.0, METER);
493         Length m30 = new Length(3.0, METER);
494         Speed speedLimit = new Speed(100, KM_PER_HOUR);
495 
496         try
497         {
498             if (middenberm)
499             {
500                 Shoulder sM = new Shoulder(link, "sM", new Length(0.0, METER), m10);
501                 new ShoulderAnimation(sM, simulator, Color.GREEN);
502             }
503             for (int i = -1; i <= 1; i += 2)
504             {
505                 
506                 LongitudinalDirectionality dir =
507                         (i < 0) ? LongitudinalDirectionality.DIR_PLUS : LongitudinalDirectionality.DIR_MINUS;
508                 double lat = middenberm ? 0.5 : 0.0;
509                 for (int j = 0; j < n; j++)
510                 {
511                     lat += i * 1.5;
512                     String lr = i < 0 ? "L" : "R";
513                     Lane lane = new Lane(link, "lane." + lr + "." + j, new Length(lat, METER), new Length(lat, METER), m30, m30,
514                             null, speedLimit);
515                     new LaneAnimation(lane, simulator, Color.DARK_GRAY);
516                     lat += i * 1.5;
517                 }
518             }
519         }
520         catch (NamingException | RemoteException | ArrayIndexOutOfBoundsException | OTSGeometryException ne)
521         {
522             ne.printStackTrace();
523         }
524     }
525 
526     
527 
528 
529 
530 
531     private static void addCityStreet(final CrossSectionLink link, final SimulatorInterface.TimeDoubleUnit simulator)
532             throws NetworkException
533     {
534         Length m60 = new Length(6.0, METER);
535         Speed speedLimit = new Speed(100, KM_PER_HOUR);
536 
537         try
538         {
539             Lane lane = new Lane(link, "lane", new Length(0.0, METER), new Length(0.0, METER), m60, m60, null, speedLimit);
540             new LaneAnimation(lane, simulator, Color.DARK_GRAY);
541         }
542         catch (NamingException | RemoteException | OTSGeometryException ne)
543         {
544             
545         }
546     }
547 
548 }