]> gitweb.fperrin.net Git - GpsPrune.git/blob - tim/prune/data/DataPoint.java
Version 1, September 2006
[GpsPrune.git] / tim / prune / data / DataPoint.java
1 package tim.prune.data;
2
3 /**
4  * Class to represent a single data point in the series
5  * including all its fields
6  * Can be either a track point or a waypoint
7  */
8 public class DataPoint
9 {
10         // Hold these as Strings?  Or FieldValue objects?
11         private String[] _fieldValues = null;
12         // list of fields
13         private FieldList _fieldList = null;
14         // Special fields for coordinates
15         private Coordinate _latitude = null, _longitude = null;
16         private Altitude _altitude;
17         private Timestamp _timestamp = null;
18         private boolean _pointValid = false;
19
20
21         // TODO: Make it possible to turn track point into waypoint - may need to alter FieldList
22
23         /**
24          * Constructor
25          * @param inValueArray array of String values
26          * @param inFieldList list of fields
27          * @param inAltFormat altitude format
28          */
29         public DataPoint(String[] inValueArray, FieldList inFieldList, int inAltFormat)
30         {
31                 // save data
32                 _fieldValues = inValueArray;
33                 // save list of fields
34                 _fieldList = inFieldList;
35
36                 // parse fields
37                 _latitude = new Latitude(getFieldValue(Field.LATITUDE));
38                 _longitude = new Longitude(getFieldValue(Field.LONGITUDE));
39                 _altitude = new Altitude(getFieldValue(Field.ALTITUDE), inAltFormat);
40                 _timestamp = new Timestamp(getFieldValue(Field.TIMESTAMP));
41         }
42
43
44         /**
45          * Private constructor for artificially generated points (eg interpolated)
46          * @param inLatitude latitude
47          * @param inLongitude longitude
48          * @param inAltitude altitude
49          */
50         private DataPoint(Coordinate inLatitude, Coordinate inLongitude, Altitude inAltitude)
51         {
52                 // Only these three fields are available
53                 _fieldValues = new String[0];
54                 _fieldList = new FieldList();
55                 _latitude = inLatitude;
56                 _longitude = inLongitude;
57                 _altitude = inAltitude;
58                 _timestamp = new Timestamp(null);
59         }
60
61
62         /**
63          * Get the value for the given field
64          * @param inField field to interrogate
65          * @return value of field
66          */
67         public String getFieldValue(Field inField)
68         {
69                 return getFieldValue(_fieldList.getFieldIndex(inField));
70         }
71
72
73         /**
74          * Get the value at the given index
75          * @param inIndex index number starting at zero
76          * @return field value, or null if not found
77          */
78         public String getFieldValue(int inIndex)
79         {
80                 if (_fieldValues == null || inIndex < 0 || inIndex >= _fieldValues.length)
81                         return null;
82                 return _fieldValues[inIndex];
83         }
84
85
86         public Coordinate getLatitude()
87         {
88                 return _latitude;
89         }
90         public Coordinate getLongitude()
91         {
92                 return _longitude;
93         }
94         public boolean hasAltitude()
95         {
96                 return _altitude.isValid();
97         }
98         public Altitude getAltitude()
99         {
100                 return _altitude;
101         }
102         public boolean hasTimestamp()
103         {
104                 return _timestamp.isValid();
105         }
106         public Timestamp getTimestamp()
107         {
108                 return _timestamp;
109         }
110
111         /**
112          * @return true if point has a waypoint name
113          */
114         public boolean isWaypoint()
115         {
116                 String name = getFieldValue(Field.WAYPT_NAME);
117                 return (name != null && !name.equals(""));
118         }
119
120         /**
121          * Compare two DataPoint objects to see if they
122          * are duplicates
123          * @param inOther other object to compare
124          * @return true if the points are equivalent
125          */
126         public boolean isDuplicate(DataPoint inOther)
127         {
128                 if (inOther == null) return false;
129                 if (_longitude == null || _latitude == null
130                         || inOther._longitude == null || inOther._latitude == null)
131                 {
132                         return false;
133                 }
134                 // Compare latitude and longitude
135                 if (!_longitude.equals(inOther._longitude) || !_latitude.equals(inOther._latitude))
136                 {
137                         return false;
138                 }
139                 // Note that conversion from decimal to dms can make non-identical points into duplicates
140                 // Compare description (if any)
141                 String name1 = getFieldValue(Field.WAYPT_NAME);
142                 String name2 = inOther.getFieldValue(Field.WAYPT_NAME);
143                 if (name1 == null || name1.equals(""))
144                 {
145                         return (name2 == null || name2.equals(""));
146                 }
147                 else
148                 {
149                         return (name2 != null && name2.equals(name1));
150                 }
151         }
152
153
154         /**
155          * @return true if the point is valid
156          */
157         public boolean isValid()
158         {
159                 return _latitude.isValid() && _longitude.isValid();
160         }
161
162
163         /**
164          * Interpolate a set of points between this one and the given one
165          * @param inEndPoint end point of interpolation
166          * @param inNumPoints number of points to generate
167          * @return the DataPoint array
168          */
169         public DataPoint[] interpolate(DataPoint inEndPoint, int inNumPoints)
170         {
171                 DataPoint[] range = new DataPoint[inNumPoints];
172                 Coordinate endLatitude = inEndPoint.getLatitude();
173                 Coordinate endLongitude = inEndPoint.getLongitude();
174                 Altitude endAltitude = inEndPoint.getAltitude();
175
176                 // Loop over points
177                 for (int i=0; i<inNumPoints; i++)
178                 {
179                         Coordinate latitude = Coordinate.interpolate(_latitude, endLatitude, i, inNumPoints);
180                         Coordinate longitude = Coordinate.interpolate(_longitude, endLongitude, i, inNumPoints);
181                         Altitude altitude = Altitude.interpolate(_altitude, endAltitude, i, inNumPoints);
182                         range[i] = new DataPoint(latitude, longitude, altitude);
183                 }
184                 return range;
185         }
186
187
188         /**
189          * Calculate the number of radians between two points (for distance calculation)
190          * @param inPoint1 first point
191          * @param inPoint2 second point
192          * @return angular distance between points in radians
193          */
194         public static double calculateRadiansBetween(DataPoint inPoint1, DataPoint inPoint2)
195         {
196                 if (inPoint1 == null || inPoint2 == null)
197                         return 0.0;
198                 final double TO_RADIANS = Math.PI / 180.0;
199                 // Get lat and long from points
200                 double lat1 = inPoint1.getLatitude().getDouble() * TO_RADIANS;
201                 double lat2 = inPoint2.getLatitude().getDouble() * TO_RADIANS;
202                 double lon1 = inPoint1.getLongitude().getDouble() * TO_RADIANS;
203                 double lon2 = inPoint2.getLongitude().getDouble() * TO_RADIANS;
204                 // Formula given by Wikipedia:Great-circle_distance as follows:
205                 // angle = 2 arcsin( sqrt( (sin ((lat2-lat1)/2))^^2 + cos(lat1)cos(lat2)(sin((lon2-lon1)/2))^^2))
206                 double firstSine = Math.sin((lat2-lat1) / 2.0);
207                 double secondSine = Math.sin((lon2-lon1) / 2.0);
208                 double term2 = Math.cos(lat1) * Math.cos(lat2) * secondSine * secondSine;
209                 double answer = 2 * Math.asin(Math.sqrt(firstSine*firstSine + term2));
210                 // phew
211                 return answer;
212         }
213 }