package tim.prune.threedee;
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 Track _terrainTrack = null;
private PointScaler _scaler = null;
private double _scaleFactor = 1.0;
private double _altFactor = 1.0;
private double _externalScaleFactor = 1.0;
// MAYBE: How to store rods (lifts) in data?
private byte[] _pointTypes = null;
private byte[] _pointHeights = null;
// 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)
{
_track = inTrack;
}
/**
* @param inTrack terrain track to set
*/
public void setTerrain(Track inTrack)
{
_terrainTrack = inTrack;
}
/**
* @return the number of points in the model
*/
public int getNumPoints()
{
if (_track == null) return 0;
return _track.getNumPoints();
}
/**
* @param inFactor altitude exaggeration factor (default 1.0)
*/
public void setAltitudeFactor(double inFactor)
{
_altFactor = inFactor;
}
/**
* @param inSize size of model
*/
public void setModelSize(double inSize)
{
_externalScaleFactor = inSize;
}
/**
* Scale all points and calculate factors
*/
public void scale()
{
// Use PointScaler to sort out x and y values
_scaler = new PointScaler(_track);
_scaler.addTerrain(_terrainTrack);
_scaler.scale(); // Add 10% border
// cap altitude scale factor if it's too big
double maxAlt = _scaler.getAltitudeRange() * _altFactor;
if (maxAlt > 0.5)
{
// capped
// System.out.println("Capped alt factor from " + _altFactor + " to " + (_altFactor * 0.5 / maxAlt));
_altFactor = _altFactor * 0.5 / maxAlt;
}
// 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.getSegmentStart()?POINT_TYPE_SEGMENT_START:POINT_TYPE_NORMAL_POINT));
_pointHeights[i] = (byte) (point.getAltitude().getMetricValue() / 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 * _externalScaleFactor;
}
/**
* 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 * _externalScaleFactor;
}
/**
* 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
double altVal = _scaler.getAltValue(inIndex);
if (altVal <= 0.0) return 0.0;
// scale according to exaggeration factor
return altVal * _altFactor * _externalScaleFactor;
}
/**
* Get the scaled horizontal value for the specified terrain point
* @param inIndex index of point
* @return scaled horizontal value
*/
public double getScaledTerrainHorizValue(int inIndex)
{
return _scaler.getTerrainHorizValue(inIndex) * _scaleFactor * _externalScaleFactor;
}
/**
* Get the scaled vertical value for the specified terrain point
* @param inIndex index of point
* @return scaled vertical value
*/
public double getScaledTerrainVertValue(int inIndex)
{
return _scaler.getTerrainVertValue(inIndex) * _scaleFactor * _externalScaleFactor;
}
/**
* Get the scaled altitude value for the specified terrain point
* @param inIndex index of point
* @return scaled altitude value
*/
public double getScaledTerrainValue(int inIndex)
{
// if no altitude, just return 0
double altVal = _scaler.getTerrainAltValue(inIndex);
if (altVal <= 0.0) return 0.0;
// don't scale by scale factor, needs to be unscaled
return altVal * _altFactor;
}
/**
* @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];
}
}