View Javadoc
1   package org.opentrafficsim.core.network.geotools;
2   
3   import java.io.Serializable;
4   
5   import org.geotools.geometry.DirectPosition2D;
6   import org.geotools.referencing.CRS;
7   import org.geotools.referencing.GeodeticCalculator;
8   import org.opengis.geometry.DirectPosition;
9   import org.opengis.geometry.coordinate.PointArray;
10  import org.opengis.referencing.crs.CoordinateReferenceSystem;
11  import org.opengis.referencing.operation.TransformException;
12  import org.opentrafficsim.core.network.NetworkException;
13  import org.opentrafficsim.core.unit.LengthUnit;
14  import org.opentrafficsim.core.value.vdouble.scalar.DoubleScalar;
15  
16  import com.vividsolutions.jts.geom.Coordinate;
17  import com.vividsolutions.jts.geom.CoordinateSequence;
18  import com.vividsolutions.jts.geom.GeometryFactory;
19  import com.vividsolutions.jts.geom.LineString;
20  import com.vividsolutions.jts.geom.Point;
21  import com.vividsolutions.jts.geom.impl.CoordinateArraySequence;
22  
23  /**
24   * This class implements a geotools-based geometry for a link in a network.
25   * <p>
26   * Copyright (c) 2013-2014 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved. <br>
27   * BSD-style license. See <a href="http://opentrafficsim.org/node/13">OpenTrafficSim License</a>.
28   * <p>
29   * @version Aug 21, 2014 <br>
30   * @author <a href="http://www.tbm.tudelft.nl/averbraeck">Alexander Verbraeck</a>
31   * @author <a href="http://www.tudelft.nl/pknoppers">Peter Knoppers</a>
32   * @author <a href="http://www.citg.tudelft.nl">Guus Tamminga</a>
33   */
34  public class LinearGeometry implements Serializable
35  {
36      /** */
37      private static final long serialVersionUID = 20141008L;
38  
39      /** link the geometry belongs to. */
40      private final LinkGeotools<?, ?> link;
41  
42      /** geotools (or jts in this case) geometry that represents the link in 3D. */
43      private final LineString line;
44  
45      /** Coordinate Reference System. */
46      private final CoordinateReferenceSystem crs;
47  
48      /** length in meters. */
49      private final DoubleScalar.Rel<LengthUnit> length;
50  
51      /**
52       * @param link the link for which this geometry applies.
53       * @param pointArray the geometry from geotools that represents the link in a CRS.
54       * @throws NetworkException when transformation for distance calculation failed.
55       */
56      public LinearGeometry(final LinkGeotools<?, ?> link, final PointArray pointArray) throws NetworkException
57      {
58          super();
59          this.link = link;
60          this.crs = pointArray.getCoordinateReferenceSystem();
61          double len = 0.0;
62          GeodeticCalculator calc = new GeodeticCalculator(this.crs);
63          Coordinate[] coords = new Coordinate[pointArray.size()];
64          DirectPosition prevPos = null;
65          for (int i = 0; i < pointArray.size(); i++)
66          {
67              DirectPosition p = pointArray.get(i).getDirectPosition();
68              double x = p.getOrdinate(0);
69              double y = p.getDimension() > 1 ? p.getOrdinate(1) : 0;
70              double z = p.getDimension() > 2 ? p.getOrdinate(2) : 0;
71              coords[i] = new Coordinate(x, y, z);
72              if (i > 0)
73              {
74                  try
75                  {
76                      calc.setStartingPosition(prevPos);
77                      calc.setDestinationPosition(p);
78                      len += calc.getOrthodromicDistance();
79                  }
80                  catch (TransformException te)
81                  {
82                      throw new NetworkException("When constructing LinearGeometry for link=" + link.toString()
83                          + ": transformation for distance calculation failed in CRS=" + this.crs.toWKT(), te);
84                  }
85              }
86              prevPos = p;
87          }
88          CoordinateSequence points = new CoordinateArraySequence(coords);
89          GeometryFactory factory = new GeometryFactory();
90          this.line = new LineString(points, factory);
91          this.length = new DoubleScalar.Rel<LengthUnit>(len, LengthUnit.METER);
92          link.setGeometry(this);
93      }
94  
95      /**
96       * @param link the link for which this geometry applies.
97       * @param lineString a JTS LineString representing the geometry.
98       * @param crs the Coordinate Reference System for this line.
99       * @throws NetworkException when transformation for distance calculation failed.
100      */
101     public LinearGeometry(final LinkGeotools<?, ?> link, final LineString lineString, final CoordinateReferenceSystem crs)
102         throws NetworkException
103     {
104         super();
105         this.link = link;
106         this.crs = crs;
107         double len = 0.0;
108         DirectPosition prevPos = null;
109         GeodeticCalculator calc = null;
110         if (CRS.getEllipsoid(this.crs) != null)
111         {
112             calc = new GeodeticCalculator(this.crs);
113         }
114         for (int i = 0; i < lineString.getNumPoints(); i++)
115         {
116             Point point = lineString.getPointN(i);
117             DirectPosition pos = new DirectPosition2D(this.crs, point.getX(), point.getY());
118             if (i > 0)
119             {
120                 try
121                 {
122                     if (calc != null)
123                     {
124                         calc.setStartingPosition(prevPos);
125                         calc.setDestinationPosition(pos);
126                         len += calc.getOrthodromicDistance();
127                     }
128                     else
129                     {
130                         // TODO see if CRS is in meters...
131                         double dx =
132                             prevPos.getDirectPosition().getCoordinate()[0] - pos.getDirectPosition().getCoordinate()[0];
133                         double dy =
134                             prevPos.getDirectPosition().getCoordinate()[1] - pos.getDirectPosition().getCoordinate()[1];
135                         len += Math.sqrt(dx * dx + dy * dy);
136                     }
137                 }
138                 catch (TransformException te)
139                 {
140                     throw new NetworkException("When constructing LinearGeometry for link=" + link.toString()
141                         + ": transformation for distance calculation failed in CRS=" + this.crs.toWKT(), te);
142                 }
143             }
144             prevPos = pos;
145         }
146         this.line = lineString;
147         this.length = new DoubleScalar.Rel<LengthUnit>(len, LengthUnit.METER);
148         link.setGeometry(this);
149     }
150 
151     // TODO possibly add a couple of other constructors for convenience.
152 
153     /**
154      * @return link.
155      */
156     public final LinkGeotools<?, ?> getLink()
157     {
158         return this.link;
159     }
160 
161     /**
162      * @return line.
163      */
164     public final LineString getLineString()
165     {
166         return this.line;
167     }
168 
169     /**
170      * @return crs.
171      */
172     public final CoordinateReferenceSystem getCRS()
173     {
174         return this.crs;
175     }
176 
177     /**
178      * @return line length.
179      */
180     public final DoubleScalar.Rel<LengthUnit> getLineLength()
181     {
182         return this.length;
183     }
184 }