View Javadoc
1   package org.opentrafficsim.importexport.osm.output;
2   
3   import java.awt.Color;
4   import java.io.IOException;
5   import java.rmi.RemoteException;
6   import java.util.ArrayList;
7   import java.util.HashMap;
8   import java.util.Iterator;
9   import java.util.List;
10  import java.util.Objects;
11  import java.util.SortedMap;
12  import java.util.TreeMap;
13  
14  import javax.naming.NamingException;
15  
16  import org.geotools.referencing.CRS;
17  import org.geotools.referencing.crs.DefaultGeocentricCRS;
18  import org.geotools.referencing.crs.DefaultGeographicCRS;
19  import org.opengis.referencing.FactoryException;
20  import org.opengis.referencing.crs.CoordinateReferenceSystem;
21  import org.opengis.referencing.operation.MathTransform;
22  import org.opengis.referencing.operation.TransformException;
23  import org.opentrafficsim.core.dsol.OTSAnimatorInterface;
24  import org.opentrafficsim.core.dsol.OTSDEVSSimulatorInterface;
25  import org.opentrafficsim.core.gtu.GTUType;
26  import org.opentrafficsim.core.network.LongitudinalDirectionality;
27  import org.opentrafficsim.core.network.NetworkException;
28  import org.opentrafficsim.core.network.animation.LaneAnimation;
29  import org.opentrafficsim.core.network.geotools.LinearGeometry;
30  import org.opentrafficsim.core.network.geotools.NodeGeotools;
31  import org.opentrafficsim.core.network.lane.CrossSectionLink;
32  import org.opentrafficsim.core.network.lane.Lane;
33  import org.opentrafficsim.core.network.lane.LaneType;
34  import org.opentrafficsim.core.network.lane.SinkLane;
35  import org.opentrafficsim.core.network.lane.SourceLane;
36  import org.opentrafficsim.core.unit.FrequencyUnit;
37  import org.opentrafficsim.core.unit.LengthUnit;
38  import org.opentrafficsim.core.value.vdouble.scalar.DoubleScalar;
39  import org.opentrafficsim.importexport.osm.Link;
40  
41  import com.vividsolutions.jts.geom.Coordinate;
42  import com.vividsolutions.jts.geom.GeometryFactory;
43  import com.vividsolutions.jts.geom.LineString;
44  
45  /**
46   * <p>
47   * Copyright (c) 2013-2014 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights
48   * reserved. <br>
49   * BSD-style license. See <a href="http://opentrafficsim.org/node/13">OpenTrafficSim License</a>.
50   * <p>
51   * @version 30.12.2014 <br>
52   * @author <a href="http://www.tudelft.nl/pknoppers">Peter Knoppers</a>
53   * @author <a>Moritz Bergmann</a>
54   */
55  public final class Convert
56  {
57      /** Do not instantiate this class. */
58      private Convert()
59      {
60          // Cannot be instantiated.
61      }
62  
63      /**
64       * @param c WGS84 Coordinate
65       * @return Geocentric Cartesian Coordinate
66       * @throws FactoryException
67       * @throws TransformException
68       */
69      public static Coordinate transform(final Coordinate c) throws FactoryException, TransformException
70      {
71          final CoordinateReferenceSystem wgs84 = DefaultGeographicCRS.WGS84;
72          final CoordinateReferenceSystem cartesianCRS = DefaultGeocentricCRS.CARTESIAN;
73          final MathTransform mathTransform;
74          try
75          {
76              mathTransform = CRS.findMathTransform(wgs84, cartesianCRS, false);
77              double[] srcPt = {c.x, c.y};
78              double[] dstPt = new double[mathTransform.getTargetDimensions()];
79  
80              mathTransform.transform(srcPt, 0, dstPt, 0, 1);
81              Coordinate c2 = new Coordinate(dstPt[0], dstPt[1]);
82              return c2;
83          }
84          catch (FactoryException e)
85          {
86              throw new FactoryException(e);
87          }
88          catch (TransformException exception)
89          {
90              throw new TransformException(exception.getMessage());
91          }
92      }
93  
94      /**
95       * This method converts an OSM link to an OTS link.
96       * @param link OSM Link to be converted
97       * @return OTS Link
98       */
99      public static CrossSectionLink<?, ?> convertLink(final org.opentrafficsim.importexport.osm.Link link)
100     {
101         NodeGeotools.STR start = convertNode(link.getStart());
102         NodeGeotools.STR end = convertNode(link.getEnd());
103         CrossSectionLink<?, ?> l2;
104         if (link.getSplineList().isEmpty())
105         {
106             GeometryFactory factory = new GeometryFactory();
107             Coordinate[] coordinates = new Coordinate[2];
108             coordinates[0] = new Coordinate(start.getPoint().x, start.getPoint().y, 0);
109             coordinates[1] = new Coordinate(end.getPoint().x, end.getPoint().y, 0);
110             LineString lineString = factory.createLineString(coordinates);
111             l2 =
112                     new CrossSectionLink<String, String>(link.getID(), start, end, new DoubleScalar.Rel<LengthUnit>(
113                             lineString.getLength(), LengthUnit.METER));
114             try
115             {
116                 new LinearGeometry(l2, lineString, null);
117             }
118             catch (NetworkException exception)
119             {
120                 throw new Error("Network exception in LinearGeometry");
121             }
122 
123         }
124         else
125         {
126             List<Coordinate> iC = new ArrayList<Coordinate>();
127             for (org.opentrafficsim.importexport.osm.Node spline : link.getSplineList())
128             {
129                 Coordinate coord = new Coordinate(spline.getLongitude(), spline.getLatitude());
130                 iC.add(coord);
131             }
132             Coordinate[] intermediateCoordinates = new Coordinate[iC.size()];
133             iC.toArray(intermediateCoordinates);
134             int coordinateCount = 2 + (null == intermediateCoordinates ? 0 : intermediateCoordinates.length);
135             Coordinate[] coordinates = new Coordinate[coordinateCount];
136             coordinates[0] = new Coordinate(start.getPoint().x, start.getPoint().y, 0);
137             coordinates[coordinates.length - 1] = new Coordinate(end.getPoint().x, end.getPoint().y, 0);
138             if (null != intermediateCoordinates)
139             {
140                 for (int i = 0; i < intermediateCoordinates.length; i++)
141                 {
142                     coordinates[i + 1] = new Coordinate(intermediateCoordinates[i]);
143                 }
144             }
145             GeometryFactory factory = new GeometryFactory();
146             LineString lineString = factory.createLineString(coordinates);
147             l2 =
148                     new CrossSectionLink<String, String>(link.getID(), start, end, new DoubleScalar.Rel<LengthUnit>(
149                             lineString.getLength(), LengthUnit.METER));
150             try
151             {
152                 new LinearGeometry(l2, lineString, null);
153             }
154             catch (NetworkException exception)
155             {
156                 throw new Error("Network exception in LinearGeometry");
157             }
158         }
159         return l2;
160     }
161 
162     /**
163      * This method converts an OSM node to an OTS node.
164      * @param node OSM Node to be converted
165      * @return OTS Node
166      */
167     public static NodeGeotools.STR convertNode(final org.opentrafficsim.importexport.osm.Node node)
168     {
169         Coordinate coordWGS84;
170         Coordinate coordGCC;
171         if (node.contains("ele"))
172         {
173             try
174             {
175                 coordWGS84 =
176                         new Coordinate(node.getLongitude(), node.getLatitude(), Double.parseDouble(node.getTag("ele")
177                                 .getValue()));
178                 try
179                 {
180                     coordGCC = Convert.transform(coordWGS84);
181                     NodeGeotools.STR n2 = new NodeGeotools.STR(Objects.toString(node.getID()), coordGCC);
182                     return n2;
183                 }
184                 catch (FactoryException exception)
185                 {
186                     exception.printStackTrace();
187                 }
188                 catch (TransformException exception)
189                 {
190                     exception.printStackTrace();
191                 }
192             }
193             catch (NumberFormatException exception)
194             {
195                 exception.printStackTrace();
196             }
197             catch (IOException exception)
198             {
199                 exception.printStackTrace();
200             }
201         }
202         else
203         {
204             coordWGS84 = new Coordinate(node.getLongitude(), node.getLatitude(), 0D);
205             try
206             {
207                 coordGCC = Convert.transform(coordWGS84);
208                 NodeGeotools.STR n2 = new NodeGeotools.STR(Objects.toString(node.getID()), coordGCC);
209                 return n2;
210             }
211             catch (FactoryException exception)
212             {
213                 exception.printStackTrace();
214             }
215             catch (TransformException exception)
216             {
217                 exception.printStackTrace();
218             }
219         }
220         return null;
221     }
222 
223     /**
224      * @param osmlink
225      * @return HashMap of the lane structure
226      */
227     private static HashMap<Double, LaneAttributes> makeStructure(final org.opentrafficsim.importexport.osm.Link osmlink)
228     {
229         SortedMap<Integer, LaneAttributes> structure = new TreeMap<Integer, LaneAttributes>();
230         HashMap<Double, LaneAttributes> structurewithOffset = new HashMap<Double, LaneAttributes>();
231         int forwards = osmlink.getForwardLanes();
232         int backwards = osmlink.getLanes() - osmlink.getForwardLanes();
233         LaneType<String> lt;
234         LaneAttributes la;
235 
236         for (org.opentrafficsim.importexport.osm.Tag t : osmlink.getTags())
237         {
238             if (t.getKey().equals("highway")
239                     && (t.getValue().equals("primary") || t.getValue().equals("secondary")
240                             || t.getValue().equals("tertiary") || t.getValue().equals("residential")
241                             || t.getValue().equals("trunk") || t.getValue().equals("motorway")
242                             || t.getValue().equals("service") || t.getValue().equals("unclassified")
243                             || t.getValue().equals("motorway_link") || t.getValue().equals("primary_link")
244                             || t.getValue().equals("secondary_link") || t.getValue().equals("tertiary_link")
245                             || t.getValue().equals("trunk_link") || t.getValue().equals("road")))
246             {
247                 lt = makeLaneType(org.opentrafficsim.importexport.osm.PredefinedGTUTypes.car);
248                 if (osmlink.getLanes() == 1 && !osmlink.isOneway())
249                 {
250                     la = new LaneAttributes(lt, Color.LIGHT_GRAY, LongitudinalDirectionality.BOTH);
251                     structure.put(0, la);
252                 }
253                 for (int i = 0 - backwards; i < forwards; i++)
254                 {
255                     if (i < 0)
256                     {
257                         la = new LaneAttributes(lt, Color.LIGHT_GRAY, LongitudinalDirectionality.BACKWARD);
258                         structure.put(i, la);
259                     }
260                     if (i >= 0)
261                     {
262                         la = new LaneAttributes(lt, Color.LIGHT_GRAY, LongitudinalDirectionality.FORWARD);
263                         structure.put(i, la);
264                     }
265                 }
266             }
267             else if (t.getKey().equals("highway") && t.getValue().equals("path"))
268             {
269                 List<GTUType<String>> types = new ArrayList<GTUType<String>>();
270                 for (org.opentrafficsim.importexport.osm.Tag t2 : osmlink.getTags())
271                 {
272                     if (t2.getKey().equals("bicycle"))
273                     {
274                         types.add(org.opentrafficsim.importexport.osm.PredefinedGTUTypes.bike);
275                     }
276                     /*
277                      * if (t2.getKey().equals("foot")) {
278                      * types.add(org.opentrafficsim.importexport.osm.PredefinedGTUTypes.pedestrian); }
279                      */
280                 }
281                 lt = makeLaneType(types);
282                 types.add(org.opentrafficsim.importexport.osm.PredefinedGTUTypes.pedestrian);
283                 if (!types.isEmpty())
284                 {
285                     if (osmlink.getLanes() == 1 && !osmlink.isOneway())
286                     {
287                         la = new LaneAttributes(lt, Color.GREEN, LongitudinalDirectionality.BOTH);
288                         structure.put(0, la);
289                     }
290                     for (int i = 0 - backwards; i < forwards; i++)
291                     {
292                         if (i < 0)
293                         {
294                             la = new LaneAttributes(lt, Color.GREEN, LongitudinalDirectionality.BACKWARD);
295                             structure.put(i, la);
296                         }
297                         if (i >= 0)
298                         {
299                             la = new LaneAttributes(lt, Color.GREEN, LongitudinalDirectionality.FORWARD);
300                             structure.put(i, la);
301                         }
302                     }
303                 }
304                 types.clear();
305             }
306         }
307         for (org.opentrafficsim.importexport.osm.Tag t : osmlink.getTags())
308         {
309             if (t.getKey().equals("cycleway"))
310             {
311                 lt = makeLaneType(org.opentrafficsim.importexport.osm.PredefinedGTUTypes.bike);
312                 switch (t.getValue())
313                 {
314                     case "lane":
315                         forwards++;
316                         backwards++;
317                         la = new LaneAttributes(lt, Color.ORANGE, LongitudinalDirectionality.BACKWARD);
318                         structure.put(0 - backwards, la);
319                         la = new LaneAttributes(lt, Color.ORANGE, LongitudinalDirectionality.FORWARD);
320                         structure.put(forwards - 1, la);
321                         break;
322                     case "track":
323                         forwards++;
324                         backwards++;
325                         la = new LaneAttributes(lt, Color.ORANGE, LongitudinalDirectionality.BACKWARD);
326                         structure.put(0 - backwards, la);
327                         la = new LaneAttributes(lt, Color.ORANGE, LongitudinalDirectionality.FORWARD);
328                         structure.put(forwards - 1, la);
329                         break;
330                     case "shared_lane":
331                         List<GTUType<String>> types = new ArrayList<GTUType<String>>();
332                         types.add(org.opentrafficsim.importexport.osm.PredefinedGTUTypes.bike);
333                         types.add(org.opentrafficsim.importexport.osm.PredefinedGTUTypes.car);
334                         lt = makeLaneType(types);
335                         la = new LaneAttributes(lt, Color.ORANGE, LongitudinalDirectionality.BACKWARD);
336                         structure.put(0 - backwards, la);
337                         la = new LaneAttributes(lt, Color.ORANGE, LongitudinalDirectionality.FORWARD);
338                         structure.put(forwards - 1, la);
339                         break;
340                     default:
341                         break;
342                 }
343             }
344         }
345         for (org.opentrafficsim.importexport.osm.Tag t : osmlink.getTags())
346         {
347             if (t.getKey().equals("sidewalk"))
348             {
349                 lt = makeLaneType(org.opentrafficsim.importexport.osm.PredefinedGTUTypes.pedestrian);
350                 switch (t.getValue())
351                 {
352                     case "both":
353                         forwards++;
354                         backwards++;
355                         la = new LaneAttributes(lt, Color.YELLOW, LongitudinalDirectionality.BACKWARD);
356                         structure.put(0 - backwards, la);
357                         la = new LaneAttributes(lt, Color.YELLOW, LongitudinalDirectionality.FORWARD);
358                         structure.put(forwards - 1, la);
359                         break;
360                     case "left":
361                         backwards++;
362                         la = new LaneAttributes(lt, Color.YELLOW, LongitudinalDirectionality.BOTH);
363                         structure.put(0 - backwards, la);
364                         break;
365                     case "right":
366                         forwards++;
367                         la = new LaneAttributes(lt, Color.YELLOW, LongitudinalDirectionality.BOTH);
368                         structure.put(forwards - 1, la);
369                         break;
370                     default:
371                         break;
372                 }
373             }
374         }
375         for (org.opentrafficsim.importexport.osm.Tag t : osmlink.getTags())
376         {
377             if (t.getKey().equals("highway")
378                     && (t.getValue().equals("cycleway") || t.getValue().equals("footway")
379                             || t.getValue().equals("pedestrian") || t.getValue().equals("steps")))
380             {
381                 if (t.getValue().equals("footway") || t.getValue().equals("pedestrian") || t.getValue().equals("steps"))
382                 {
383                     lt = makeLaneType(org.opentrafficsim.importexport.osm.PredefinedGTUTypes.pedestrian);
384                     if (osmlink.getLanes() == 1 && !osmlink.isOneway())
385                     {
386                         la = new LaneAttributes(lt, Color.GREEN, LongitudinalDirectionality.BOTH);
387                         structure.put(0, la);
388                     }
389                     for (int i = 0 - backwards; i < forwards; i++)
390                     {
391                         if (i < 0)
392                         {
393                             la = new LaneAttributes(lt, Color.GREEN, LongitudinalDirectionality.BACKWARD);
394                             structure.put(i, la);
395                         }
396                         if (i >= 0)
397                         {
398                             la = new LaneAttributes(lt, Color.GREEN, LongitudinalDirectionality.FORWARD);
399                             structure.put(i, la);
400                         }
401                     }
402                 }
403                 if (t.getValue().equals("cycleway"))
404                 {
405                     lt = makeLaneType(org.opentrafficsim.importexport.osm.PredefinedGTUTypes.bike);
406                     if (osmlink.getLanes() == 1 && !osmlink.isOneway())
407                     {
408                         la = new LaneAttributes(lt, Color.GREEN, LongitudinalDirectionality.BOTH);
409                         structure.put(0, la);
410                     }
411                     for (int i = 0 - backwards; i < forwards; i++)
412                     {
413                         if (i < 0)
414                         {
415                             la = new LaneAttributes(lt, Color.GREEN, LongitudinalDirectionality.BACKWARD);
416                             structure.put(i, la);
417                         }
418                         if (i >= 0)
419                         {
420                             la = new LaneAttributes(lt, Color.GREEN, LongitudinalDirectionality.FORWARD);
421                             structure.put(i, la);
422                         }
423                     }
424                 }
425             }
426         }
427         structurewithOffset = calculateOffsets(structure, osmlink, forwards, backwards);
428         return structurewithOffset;
429     }
430 
431     /**
432      * @param structure
433      * @param osmlink
434      * @param forwards
435      * @param backwards
436      * @return HashMap containing the lane structure with offsets.
437      */
438     private static HashMap<Double, LaneAttributes> calculateOffsets(final SortedMap<Integer, LaneAttributes> structure,
439             final org.opentrafficsim.importexport.osm.Link osmlink, final Integer forwards, final Integer backwards)
440     {
441         HashMap<Double, LaneAttributes> structurewithOffset = new HashMap<Double, LaneAttributes>();
442         LaneType<?> lt;
443         Double width = 3.05D;
444         LaneAttributes la;
445         // boolean widthOverride = false;
446 
447         for (org.opentrafficsim.importexport.osm.Tag t : osmlink.getTags())
448         {
449             if (t.getKey().equals("width"))
450             {
451                 String w = t.getValue().replace(",", ".");
452                 width = Double.parseDouble(w) / osmlink.getLanes();
453                 // widthOverride = true;
454             }
455         }
456         double currentOffset = 0.0D;
457         if (structure.lastKey() >= 0)
458         {
459             for (int i = 0; i < forwards; i++)
460             {
461                 la = structure.get(i);
462                 lt = la.getLaneType();
463                 /*
464                  * if (lt == null) { String s = "awww shucks"; System.out.println(s); }
465                  */
466                 if (lt.isCompatible(org.opentrafficsim.importexport.osm.PredefinedGTUTypes.car))
467                 {
468                     la.setWidth(width);
469                     structurewithOffset.put(currentOffset, la);
470                     currentOffset += width;
471                 }
472                 else if (lt.isCompatible(org.opentrafficsim.importexport.osm.PredefinedGTUTypes.bike))
473                 {
474                     la.setWidth(0.8D);
475                     structurewithOffset.put(currentOffset, la);
476                     currentOffset += 0.8D;
477                 }
478                 else if (lt.isCompatible(org.opentrafficsim.importexport.osm.PredefinedGTUTypes.pedestrian))
479                 {
480                     la.setWidth(0.95D);
481                     structurewithOffset.put(currentOffset, la);
482                     currentOffset += 0.95D;
483                 }
484             }
485         }
486         if (structure.firstKey() < 0)
487         {
488             currentOffset = 0.0D;
489             for (int i = -1; i >= (0 - backwards); i--)
490             {
491                 la = structure.get(i);
492                 LaneAttributes la2 = structure.get(i + 1);
493                 lt = la.getLaneType();
494                 LaneType<?> lt2 = la2.getLaneType();
495                 if (lt2.isCompatible(org.opentrafficsim.importexport.osm.PredefinedGTUTypes.car))
496                 {
497                     la.setWidth(width);
498                     currentOffset -= width;
499                     structurewithOffset.put(currentOffset, la);
500                 }
501                 else if (lt2.isCompatible(org.opentrafficsim.importexport.osm.PredefinedGTUTypes.bike))
502                 {
503                     la.setWidth(0.8D);
504                     currentOffset -= 0.8D;
505                     structurewithOffset.put(currentOffset, la);
506                 }
507                 else if (lt2.isCompatible(org.opentrafficsim.importexport.osm.PredefinedGTUTypes.pedestrian))
508                 {
509                     la.setWidth(0.95D);
510                     currentOffset -= 0.95D;
511                     structurewithOffset.put(currentOffset, la);
512                 }
513             }
514         }
515         return structurewithOffset;
516     }
517 
518     /**
519      * This method creates lanes out of an OSM link LaneTypes are not jet extensive and can be further increased through
520      * Tags provided by OSM. The standard lane width of 3.05 is an estimation based on the Wuropean width limitation for
521      * vehicles (2.55m) + 25cm each side.
522      * @param osmlink Link; the OSM link to make lanes for
523      * @param simulator
524      * @return Lanes
525      * @throws NetworkException
526      * @throws NamingException
527      * @throws RemoteException
528      */
529     public static List<Lane> makeLanes(final org.opentrafficsim.importexport.osm.Link osmlink,
530             final OTSDEVSSimulatorInterface simulator) throws NetworkException, RemoteException, NamingException
531     {
532         CrossSectionLink<?, ?> otslink = convertLink(osmlink);
533         List<Lane> lanes = new ArrayList<Lane>();
534         LaneType<?> lt = null;
535         Lane result = null;
536         Color color = Color.LIGHT_GRAY;
537         HashMap<Double, LaneAttributes> structure = makeStructure(osmlink);
538 
539         DoubleScalar.Abs<FrequencyUnit> f2000 = new DoubleScalar.Abs<FrequencyUnit>(2000.0, FrequencyUnit.PER_HOUR);
540         /** temporary */
541         Iterator<Double> iter = structure.keySet().iterator();
542         while (iter.hasNext())
543         {
544             Double i = iter.next();
545             LaneAttributes la = structure.get(i);
546             lt = la.getLaneType();
547             Double offSet = i;
548             DoubleScalar.Rel<LengthUnit> latPos = new DoubleScalar.Rel<LengthUnit>(offSet, LengthUnit.METER);
549             if (osmlink.hasTag("hasPreceding") && i >= 0)
550             {
551                 color = Color.RED;
552                 result = new SinkLane(otslink, latPos, la.getWidth(), lt, la.getDirectionality());
553             }
554             else if (osmlink.hasTag("hasPreceding") && i < 0)
555             {
556                 color = Color.BLUE;
557                 result = new SourceLane(otslink, latPos, la.getWidth(), lt, la.getDirectionality());
558             }
559             else if (osmlink.hasTag("hasFollowing") && i >= 0)
560             {
561                 color = Color.BLUE;
562                 result = new SourceLane(otslink, latPos, la.getWidth(), lt, la.getDirectionality());
563             }
564             else if (osmlink.hasTag("hasFollowing") && i < 0)
565             {
566                 color = Color.RED;
567                 result = new SinkLane(otslink, latPos, la.getWidth(), lt, la.getDirectionality());
568             }
569             else
570             {
571                 color = la.getColor();
572                 result =
573                         new Lane(otslink, latPos, latPos, la.getWidth(), la.getWidth(), lt, la.getDirectionality(),
574                                 f2000);
575             }
576             animateLane(result, simulator, color);
577             lanes.add(result);
578         }
579         return lanes;
580     }
581 
582     /**
583      * Animates Lane.
584      * @param l
585      * @param simulator
586      * @param color
587      * @throws RemoteException
588      * @throws NamingException
589      */
590     private static void animateLane(final Lane l, final OTSDEVSSimulatorInterface simulator, final Color color)
591             throws RemoteException, NamingException
592     {
593         if (simulator instanceof OTSAnimatorInterface)
594         {
595             new LaneAnimation(l, simulator, color);
596         }
597     }
598 
599     /**
600      * This method creates a LaneType which supports all GTUTypes that have been specified in the GTUType List "GTUs".
601      * @param gtuTypes List&lt;GTUType&lt;String&gt;&gt;; list of GTUTypes
602      * @return LaneType permeable for all of the specific GTUTypes
603      */
604     public static LaneType<String> makeLaneType(final List<GTUType<String>> gtuTypes)
605     {
606         String iD = "";
607         for (GTUType<String> gtu : gtuTypes)
608         {
609             iD += gtu.getId() + "|";
610         }
611         LaneType<String> lt = new LaneType<String>(iD);
612         for (GTUType<String> gtu : gtuTypes)
613         {
614             lt.addPermeability(gtu);
615         }
616         return lt;
617     }
618 
619     /**
620      * This method creates a LaneType which supports the specified GTUType.
621      * @param gtuType GTUType; the type of GTU that can travel on the new LaneType
622      * @return LaneType
623      */
624     public static LaneType<String> makeLaneType(final GTUType<String> gtuType)
625     {
626         String iD = gtuType.getId();
627         LaneType<String> lt = new LaneType<String>(iD);
628         lt.addPermeability(gtuType);
629         return lt;
630     }
631 
632     /**
633      * @param nodes List of Nodes
634      * @param links List of Links
635      * @return List of Links which are candidates for becoming sinks/sources.
636      */
637     private static ArrayList<org.opentrafficsim.importexport.osm.Link> findPossibleSinks(
638             final List<org.opentrafficsim.importexport.osm.Node> nodes,
639             final List<org.opentrafficsim.importexport.osm.Link> links)
640     {
641         ArrayList<org.opentrafficsim.importexport.osm.Node> foundSinkNodes =
642                 new ArrayList<org.opentrafficsim.importexport.osm.Node>();
643         ArrayList<org.opentrafficsim.importexport.osm.Link> foundSinkLinks =
644                 new ArrayList<org.opentrafficsim.importexport.osm.Link>();
645         for (org.opentrafficsim.importexport.osm.Node n : nodes)
646         {
647             int count = 0;
648             for (org.opentrafficsim.importexport.osm.Link l : links)
649             {
650                 if (l.getStart().equals(n) || l.getEnd().equals(n) || l.getSplineList().contains(n))
651                 {
652                     count += 1;
653                     if (count > 1)
654                     {
655                         break;
656                     }
657                 }
658             }
659             if (count == 1)
660             {
661                 foundSinkNodes.add(n);
662             }
663         }
664         for (org.opentrafficsim.importexport.osm.Link l : links)
665         {
666             if (foundSinkNodes.contains(l.getEnd()) || foundSinkNodes.contains(l.getStart()))
667             {
668                 foundSinkLinks.add(l);
669             }
670             else
671             {
672                 for (org.opentrafficsim.importexport.osm.Node n : l.getSplineList())
673                 {
674                     if (foundSinkNodes.contains(n))
675                     {
676                         foundSinkLinks.add(l);
677                     }
678                 }
679             }
680         }
681         /*
682          * for (org.opentrafficsim.importexport.osm.Node n: foundSinkNodes) { System.out.println(n.getID()); } for
683          * (org.opentrafficsim.importexport.osm.Link l : foundSinkLinks) { System.out.println(l.getID()); }
684          */
685         return foundSinkLinks;
686     }
687 
688     /**
689      * @param net
690      * @return Network with all possible sinks and sources tagged.
691      */
692     public static org.opentrafficsim.importexport.osm.Network findSinksandSources(
693             final org.opentrafficsim.importexport.osm.Network net)
694     {
695         List<org.opentrafficsim.importexport.osm.Node> nodes =
696                 new ArrayList<org.opentrafficsim.importexport.osm.Node>();
697         nodes.addAll(net.getNodes().values());
698         ArrayList<org.opentrafficsim.importexport.osm.Link> foundSinkLinks = findPossibleSinks(nodes, net.getLinks());
699         for (org.opentrafficsim.importexport.osm.Link l : net.getLinks())
700         {
701             if (foundSinkLinks.contains(l))
702             {
703                 if (net.hasFollowingLink(l))
704                 {
705                     l.addTag(new org.opentrafficsim.importexport.osm.Tag("hasFollowing", ""));
706                 }
707                 else if (net.hasPrecedingLink(l))
708                 {
709                     l.addTag(new org.opentrafficsim.importexport.osm.Tag("hasPreceding", ""));
710                 }
711             }
712         }
713         return net;
714     }
715 }
716 
717 /**
718  * <p>
719  * Copyright (c) 2013-2014 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights
720  * reserved. <br>
721  * BSD-style license. See <a href="http://opentrafficsim.org/node/13">OpenTrafficSim License</a>.
722  * <p>
723  * @version Mar 3, 2015 <br>
724  * @author <a>Moritz Bergmann</a>
725  */
726 class LaneAttributes
727 {
728     /** */
729     private LaneType<?> laneType;
730 
731     /** */
732     private Color color;
733 
734     /** */
735     private LongitudinalDirectionality directionaility;
736 
737     /** */
738     private DoubleScalar.Rel<LengthUnit> width;
739 
740     /**
741      * @param lt
742      * @param c
743      * @param d
744      */
745     public LaneAttributes(final LaneType<?> lt, final Color c, final LongitudinalDirectionality d)
746     {
747         this.laneType = lt;
748         this.color = c;
749         this.directionaility = d;
750     }
751 
752     /**
753      * @param lt
754      * @param c
755      * @param d
756      * @param w
757      */
758     public LaneAttributes(final LaneType<?> lt, final Color c, final LongitudinalDirectionality d, final Double w)
759     {
760         this.laneType = lt;
761         this.color = c;
762         this.directionaility = d;
763         this.setWidth(w);
764     }
765 
766     /**
767      * @return LaneType<?>
768      */
769     public LaneType<?> getLaneType()
770     {
771         return this.laneType;
772     }
773 
774     /**
775      * @return Color
776      */
777     public Color getColor()
778     {
779         return this.color;
780     }
781 
782     /**
783      * @return LongitudinalDirectionality
784      */
785     public LongitudinalDirectionality getDirectionality()
786     {
787         return this.directionaility;
788     }
789 
790     /**
791      * @return width.
792      */
793     public DoubleScalar.Rel<LengthUnit> getWidth()
794     {
795         return this.width;
796     }
797 
798     /**
799      * @param width set width.
800      */
801     public void setWidth(final Double width)
802     {
803         DoubleScalar.Rel<LengthUnit> w = new DoubleScalar.Rel<LengthUnit>(width, LengthUnit.METER);
804         this.width = w;
805     }
806 }