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; /** Minimum altitude cap */ 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; public static final byte POINT_TYPE_SEGMENT_START = 3; /** * 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