package tim.prune.threedee;
public class TerrainPatch
{
private int _gridSize = 0;
private double[] _altitudes = null;
private int[] _tempDists = null;
/**
* Constructor
* @param inGridSize size of grid edge
*/
public TerrainPatch(int inGridSize)
{
_gridSize = inGridSize;
int numNodes = inGridSize * inGridSize;
_altitudes = new double[numNodes];
_tempDists = new int[numNodes];
}
/**
* Add an altitude interpolation to the mix
* @param inPointIndex point index to array
* @param inValue altitude value in metres
* @param inGapIndex index of point within gap, from 1 to gapLength-1
* @param inGapLength length of gap, minimum 2
*/
public void addAltitude(int inPointIndex, double inValue, int inGapIndex, int inGapLength)
{
final int dist = Math.min(inGapIndex, inGapLength-inGapIndex);
if (_tempDists[inPointIndex] == 0)
{
if (_altitudes[inPointIndex] > 0.0) System.err.println("Altitude shouldn't be 0 if dist is 0!");
// first point
_altitudes[inPointIndex] = inValue;
_tempDists[inPointIndex] = dist;
}
else
{
// second point
final double firstValue = _altitudes[inPointIndex];
final int firstDist = _tempDists[inPointIndex];
final double firstWeight = dist * 1.0 / (dist + firstDist);
final double secondWeight= firstDist * 1.0 / (dist + firstDist);
_altitudes[inPointIndex] = firstWeight * firstValue + secondWeight * inValue;
_tempDists[inPointIndex] = 0;
}
}
/**
* Smooth the patch to reduce blockiness
*/
public void smooth()
{
double[] altCopy = new double[_altitudes.length];
for (int i=0; i<_gridSize; i++)
{
for (int j=0; j<_gridSize; j++)
{
if (hasAltitude(i, j) && hasAltitude(i-1, j) && hasAltitude(i+1, j)
&& hasAltitude(i, j+1) && hasAltitude(i-1, j+1) && hasAltitude(i+1, j+1)
&& hasAltitude(i, j-1) && hasAltitude(i-1, j-1) && hasAltitude(i+1, j-1))
{
// got a 3x3 square, can do a blur
double alt = (getAltitude(i, j) + getAltitude(i-1, j) + getAltitude(i+1, j)
+ getAltitude(i, j+1) + getAltitude(i-1, j+1) + getAltitude(i+1, j+1)
+ getAltitude(i, j-1) + getAltitude(i-1, j-1) + getAltitude(i+1, j-1)) / 9.0;
altCopy[i * _gridSize + j] = alt;
}
}
}
// Copy results back
for (int k=0; k<altCopy.length; k++)
{
if (altCopy[k] > 0.0)
{
_altitudes[k] = altCopy[k];
}
}
}
/**
* @param inI first index
* @param inJ second index
* @return true if there is an altitude in the patch in this position
*/
private boolean hasAltitude(int inI, int inJ)
{
return inI >= 0 && inI < _gridSize && inJ >= 0 && inJ < _gridSize
&& _altitudes[inI * _gridSize + inJ] > 0.0;
}
/**
* @param inI first index
* @param inJ second index
* @return true if there is an altitude in the patch in this position
*/
private double getAltitude(int inI, int inJ)
{
if (inI >= 0 && inI < _gridSize && inJ >= 0 && inJ < _gridSize)
{
return _altitudes[inI * _gridSize + inJ];
}
return 0.0;
}
/**
* @param inPointIndex point index
* @return altitude value
*/
public double getAltitude(int inPointIndex)
{
if (_tempDists[inPointIndex] != 0) System.err.println("Dists should be 0 if we're retrieving!");
return _altitudes[inPointIndex];
}
}