]> gitweb.fperrin.net Git - GpsPrune.git/blobdiff - tim/prune/threedee/ThreeDModel.java
Version 2, March 2007
[GpsPrune.git] / tim / prune / threedee / ThreeDModel.java
diff --git a/tim/prune/threedee/ThreeDModel.java b/tim/prune/threedee/ThreeDModel.java
new file mode 100644 (file)
index 0000000..db748c0
--- /dev/null
@@ -0,0 +1,239 @@
+package tim.prune.threedee;
+
+import tim.prune.data.Altitude;
+import tim.prune.data.DataPoint;
+import tim.prune.data.PointScaler;
+import tim.prune.data.Track;
+
+/**
+ * Class to hold a 3d model of the track data,
+ * including all points and scaling operations.
+ * Used by java3d and also Pov export functions
+ */
+public class ThreeDModel
+{
+       private Track _track = null;
+       private PointScaler _scaler = null;
+       private double _modelSize;
+       private int _altitudeCap = -1;
+       private double _scaleFactor = 1.0;
+       private double _altFactor = 1.0;
+       // TODO: How to store rods (lifts) in data?
+       private byte[] _pointTypes = null;
+       private byte[] _pointHeights = null;
+
+       private static final double DEFAULT_MODEL_SIZE = 10.0;
+       public static final int MINIMUM_ALTITUDE_CAP = 100;
+
+       // Constants for point types
+       public static final byte POINT_TYPE_WAYPOINT = 1;
+       public static final byte POINT_TYPE_NORMAL_POINT = 2;
+
+
+       /**
+        * Constructor
+        * @param inTrack Track object
+        */
+       public ThreeDModel(Track inTrack)
+       {
+               this(inTrack, DEFAULT_MODEL_SIZE);
+       }
+
+
+       /**
+        * Constructor
+        * @param inTrack Track object
+        * @param inSize model size
+        */
+       public ThreeDModel(Track inTrack, double inSize)
+       {
+               _track = inTrack;
+               _modelSize = inSize;
+               if (_modelSize <= 0.0) _modelSize = DEFAULT_MODEL_SIZE;
+       }
+
+
+       /**
+        * @return the number of points in the model
+        */
+       public int getNumPoints()
+       {
+               if (_track == null) return 0;
+               return _track.getNumPoints();
+       }
+
+
+       /**
+        * Set the altitude cap
+        * @param inAltitudeCap altitude range to cap to (ignored if less than data range)
+        */
+       public void setAltitudeCap(int inAltitudeCap)
+       {
+               _altitudeCap = inAltitudeCap;
+               if (_altitudeCap < MINIMUM_ALTITUDE_CAP)
+               {
+                       _altitudeCap = MINIMUM_ALTITUDE_CAP;
+               }
+       }
+
+
+       /**
+        * Scale all points and calculate factors
+        */
+       public void scale()
+       {
+               // Use PointScaler to sort out x and y values
+               _scaler = new PointScaler(_track);
+               _scaler.scale();
+               // Calculate scale factor to fit within box
+               _scaleFactor = 1.0;
+               if (_scaler.getMaximumHoriz() > 0.0 || _scaler.getMaximumVert() > 0.0)
+               {
+                       if (_scaler.getMaximumHoriz() > _scaler.getMaximumVert())
+                       {
+                               // scale limited by longitude
+                               _scaleFactor = _modelSize / _scaler.getMaximumHoriz();
+                       }
+                       else
+                       {
+                               // scale limited by latitude
+                               _scaleFactor = _modelSize / _scaler.getMaximumVert();
+                       }
+               }
+               // calculate altitude scale factor
+               _altFactor = 1.0;
+               if (_scaler.getMaximumAlt() >= 0)
+               {
+                       // limit by altitude cap or by data range?
+                       if (_scaler.getMaximumAlt() > _altitudeCap)
+                       {
+                               // data is bigger than cap
+                               _altFactor = _modelSize / _scaler.getMaximumAlt();
+                       }
+                       else
+                       {
+                               // capped
+                               _altFactor = _modelSize / _altitudeCap;
+                       }
+               }
+               // calculate lat/long lines
+               _scaler.calculateLatLongLines();
+
+               // calculate point types and height codes
+               calculatePointTypes();
+       }
+
+
+       /**
+        * Calculate the point types and height codes
+        */
+       private void calculatePointTypes()
+       {
+               int numPoints = getNumPoints();
+               _pointTypes = new byte[numPoints];
+               _pointHeights = new byte[numPoints];
+               // Loop over points in track
+               for (int i=0; i<numPoints; i++)
+               {
+                       DataPoint point = _track.getPoint(i);
+                       _pointTypes[i] = (point.isWaypoint()?POINT_TYPE_WAYPOINT:POINT_TYPE_NORMAL_POINT);
+                       _pointHeights[i] = (byte) (point.getAltitude().getValue(Altitude.FORMAT_METRES) / 500);
+               }
+       }
+
+
+       /**
+        * Get the scaled horizontal value for the specified point
+        * @param inIndex index of point
+        * @return scaled horizontal value
+        */
+       public double getScaledHorizValue(int inIndex)
+       {
+               return _scaler.getHorizValue(inIndex) * _scaleFactor;
+       }
+
+       /**
+        * Get the scaled vertical value for the specified point
+        * @param inIndex index of point
+        * @return scaled vertical value
+        */
+       public double getScaledVertValue(int inIndex)
+       {
+               return _scaler.getVertValue(inIndex) * _scaleFactor;
+       }
+
+       /**
+        * Get the scaled altitude value for the specified point
+        * @param inIndex index of point
+        * @return scaled altitude value
+        */
+       public double getScaledAltValue(int inIndex)
+       {
+               // if no altitude, just return 0
+               int altVal = _scaler.getAltValue(inIndex);
+               if (altVal < 0) return 0;
+               // scale according to altitude cap
+               return altVal * _altFactor;
+       }
+
+
+       /**
+        * @return number of latitude lines
+        */
+       public int getNumLatitudeLines()
+       {
+               return _scaler.getLatitudeLines().length;
+       }
+
+       /**
+        * @param inIndex index of line, starting at 0
+        * @return scaled position of latitude line
+        */
+       public double getScaledLatitudeLine(int inIndex)
+       {
+               return _scaler.getScaledLatitudeLines()[inIndex] * _scaleFactor;
+       }
+
+       /**
+        * @return number of longitude lines
+        */
+       public int getNumLongitudeLines()
+       {
+               return _scaler.getLongitudeLines().length;
+       }
+
+       /**
+        * @param inIndex index of line, starting at 0
+        * @return scaled position of longitude line
+        */
+       public double getScaledLongitudeLine(int inIndex)
+       {
+               return _scaler.getScaledLongitudeLines()[inIndex] * _scaleFactor;
+       }
+
+       /**
+        * @param inIndex index of point, starting at 0
+        * @return point type, either POINT_TYPE_WAYPOINT or POINT_TYPE_NORMAL_POINT
+        */
+       public byte getPointType(int inIndex)
+       {
+               return _pointTypes[inIndex];
+       }
+
+       /**
+        * @param inIndex index of point, starting at 0
+        * @return point height code
+        */
+       public byte getPointHeightCode(int inIndex)
+       {
+               return _pointHeights[inIndex];
+       }
+
+       /**
+        * @return the current model size
+        */
+       public double getModelSize()
+       {
+               return _modelSize;
+       }
+}