]> gitweb.fperrin.net Git - GpsPrune.git/blobdiff - tim/prune/data/DataPoint.java
Version 1, September 2006
[GpsPrune.git] / tim / prune / data / DataPoint.java
diff --git a/tim/prune/data/DataPoint.java b/tim/prune/data/DataPoint.java
new file mode 100644 (file)
index 0000000..5d66ec5
--- /dev/null
@@ -0,0 +1,213 @@
+package tim.prune.data;
+
+/**
+ * Class to represent a single data point in the series
+ * including all its fields
+ * Can be either a track point or a waypoint
+ */
+public class DataPoint
+{
+       // Hold these as Strings?  Or FieldValue objects?
+       private String[] _fieldValues = null;
+       // list of fields
+       private FieldList _fieldList = null;
+       // Special fields for coordinates
+       private Coordinate _latitude = null, _longitude = null;
+       private Altitude _altitude;
+       private Timestamp _timestamp = null;
+       private boolean _pointValid = false;
+
+
+       // TODO: Make it possible to turn track point into waypoint - may need to alter FieldList
+
+       /**
+        * Constructor
+        * @param inValueArray array of String values
+        * @param inFieldList list of fields
+        * @param inAltFormat altitude format
+        */
+       public DataPoint(String[] inValueArray, FieldList inFieldList, int inAltFormat)
+       {
+               // save data
+               _fieldValues = inValueArray;
+               // save list of fields
+               _fieldList = inFieldList;
+
+               // parse fields
+               _latitude = new Latitude(getFieldValue(Field.LATITUDE));
+               _longitude = new Longitude(getFieldValue(Field.LONGITUDE));
+               _altitude = new Altitude(getFieldValue(Field.ALTITUDE), inAltFormat);
+               _timestamp = new Timestamp(getFieldValue(Field.TIMESTAMP));
+       }
+
+
+       /**
+        * Private constructor for artificially generated points (eg interpolated)
+        * @param inLatitude latitude
+        * @param inLongitude longitude
+        * @param inAltitude altitude
+        */
+       private DataPoint(Coordinate inLatitude, Coordinate inLongitude, Altitude inAltitude)
+       {
+               // Only these three fields are available
+               _fieldValues = new String[0];
+               _fieldList = new FieldList();
+               _latitude = inLatitude;
+               _longitude = inLongitude;
+               _altitude = inAltitude;
+               _timestamp = new Timestamp(null);
+       }
+
+
+       /**
+        * Get the value for the given field
+        * @param inField field to interrogate
+        * @return value of field
+        */
+       public String getFieldValue(Field inField)
+       {
+               return getFieldValue(_fieldList.getFieldIndex(inField));
+       }
+
+
+       /**
+        * Get the value at the given index
+        * @param inIndex index number starting at zero
+        * @return field value, or null if not found
+        */
+       public String getFieldValue(int inIndex)
+       {
+               if (_fieldValues == null || inIndex < 0 || inIndex >= _fieldValues.length)
+                       return null;
+               return _fieldValues[inIndex];
+       }
+
+
+       public Coordinate getLatitude()
+       {
+               return _latitude;
+       }
+       public Coordinate getLongitude()
+       {
+               return _longitude;
+       }
+       public boolean hasAltitude()
+       {
+               return _altitude.isValid();
+       }
+       public Altitude getAltitude()
+       {
+               return _altitude;
+       }
+       public boolean hasTimestamp()
+       {
+               return _timestamp.isValid();
+       }
+       public Timestamp getTimestamp()
+       {
+               return _timestamp;
+       }
+
+       /**
+        * @return true if point has a waypoint name
+        */
+       public boolean isWaypoint()
+       {
+               String name = getFieldValue(Field.WAYPT_NAME);
+               return (name != null && !name.equals(""));
+       }
+
+       /**
+        * Compare two DataPoint objects to see if they
+        * are duplicates
+        * @param inOther other object to compare
+        * @return true if the points are equivalent
+        */
+       public boolean isDuplicate(DataPoint inOther)
+       {
+               if (inOther == null) return false;
+               if (_longitude == null || _latitude == null
+                       || inOther._longitude == null || inOther._latitude == null)
+               {
+                       return false;
+               }
+               // Compare latitude and longitude
+               if (!_longitude.equals(inOther._longitude) || !_latitude.equals(inOther._latitude))
+               {
+                       return false;
+               }
+               // Note that conversion from decimal to dms can make non-identical points into duplicates
+               // Compare description (if any)
+               String name1 = getFieldValue(Field.WAYPT_NAME);
+               String name2 = inOther.getFieldValue(Field.WAYPT_NAME);
+               if (name1 == null || name1.equals(""))
+               {
+                       return (name2 == null || name2.equals(""));
+               }
+               else
+               {
+                       return (name2 != null && name2.equals(name1));
+               }
+       }
+
+
+       /**
+        * @return true if the point is valid
+        */
+       public boolean isValid()
+       {
+               return _latitude.isValid() && _longitude.isValid();
+       }
+
+
+       /**
+        * Interpolate a set of points between this one and the given one
+        * @param inEndPoint end point of interpolation
+        * @param inNumPoints number of points to generate
+        * @return the DataPoint array
+        */
+       public DataPoint[] interpolate(DataPoint inEndPoint, int inNumPoints)
+       {
+               DataPoint[] range = new DataPoint[inNumPoints];
+               Coordinate endLatitude = inEndPoint.getLatitude();
+               Coordinate endLongitude = inEndPoint.getLongitude();
+               Altitude endAltitude = inEndPoint.getAltitude();
+
+               // Loop over points
+               for (int i=0; i<inNumPoints; i++)
+               {
+                       Coordinate latitude = Coordinate.interpolate(_latitude, endLatitude, i, inNumPoints);
+                       Coordinate longitude = Coordinate.interpolate(_longitude, endLongitude, i, inNumPoints);
+                       Altitude altitude = Altitude.interpolate(_altitude, endAltitude, i, inNumPoints);
+                       range[i] = new DataPoint(latitude, longitude, altitude);
+               }
+               return range;
+       }
+
+
+       /**
+        * Calculate the number of radians between two points (for distance calculation)
+        * @param inPoint1 first point
+        * @param inPoint2 second point
+        * @return angular distance between points in radians
+        */
+       public static double calculateRadiansBetween(DataPoint inPoint1, DataPoint inPoint2)
+       {
+               if (inPoint1 == null || inPoint2 == null)
+                       return 0.0;
+               final double TO_RADIANS = Math.PI / 180.0;
+               // Get lat and long from points
+               double lat1 = inPoint1.getLatitude().getDouble() * TO_RADIANS;
+               double lat2 = inPoint2.getLatitude().getDouble() * TO_RADIANS;
+               double lon1 = inPoint1.getLongitude().getDouble() * TO_RADIANS;
+               double lon2 = inPoint2.getLongitude().getDouble() * TO_RADIANS;
+               // Formula given by Wikipedia:Great-circle_distance as follows:
+               // angle = 2 arcsin( sqrt( (sin ((lat2-lat1)/2))^^2 + cos(lat1)cos(lat2)(sin((lon2-lon1)/2))^^2))
+               double firstSine = Math.sin((lat2-lat1) / 2.0);
+               double secondSine = Math.sin((lon2-lon1) / 2.0);
+               double term2 = Math.cos(lat1) * Math.cos(lat2) * secondSine * secondSine;
+               double answer = 2 * Math.asin(Math.sqrt(firstSine*firstSine + term2));
+               // phew
+               return answer;
+       }
+}