/**
* @class
* An object representing a vector field.
*
* @param {int} height The desired resolution in the "height"-dimension.
* @param {int} width The desired resolution in the "width"-dimension.
* @param {int} depth The desired resolution in the "depth"-dimension.
*/
function Volume(height, width, depth) {
this.height = height;
this.width = width;
this.depth = depth;
/** An array of type THREE.Vector3 representing the vector field. */
this.data = new Array(height * width * depth);
/**
* Refreshes the internal data as a simulation of vector field, which might have been
* caused by a tornado.
*
* Taken from: {@link http://web.cse.ohio-state.edu/~crawfis/Data/Tornado/tornadoSrc.c}
* @param {int} time The timepoint of the tornado.
*/
this.generateTornado = function(time) {
var ix, iy, iz;
var x, y, z;
var r, xc, yc, scale, temp, z0;
var r2 = 8;
var SMALL = 0.00000000001;
var xdelta = 1.0 / (this.width-1.0);
var ydelta = 1.0 / (this.height-1.0);
var zdelta = 1.0 / (this.depth-1.0);
for( iz = 0; iz < this.depth; iz++ )
{
z = iz * zdelta;
xc = 0.5 + 0.1 * Math.sin(0.04*time+10.0*z);
yc = 0.5 + 0.1 * Math.cos(0.03*time+3.0*z);
r = 0.1 + 0.4 * z*z + 0.1 * z * Math.sin(8.0*z);
r2 = 0.2 + 0.1*z;
for( iy = 0; iy < this.height; iy++ )
{
y = iy * ydelta;
for( ix = 0; ix < this.width; ix++ )
{
x = ix * xdelta;
temp = Math.sqrt( (y-yc)*(y-yc) + (x-xc)*(x-xc) );
scale = Math.abs( r - temp );
if ( scale > r2 )
scale = 0.8 - scale;
else
scale = 1.0;
z0 = 0.1 * (0.1 - temp*z );
if ( z0 < 0.0 ) z0 = 0.0;
temp = Math.sqrt( temp*temp + z0*z0 );
scale = (r + r2 - temp) * scale / (temp + SMALL);
scale = scale / (1+z);
var vec = new THREE.Vector3(
scale * (y-yc) + 0.1*(x-xc),
scale * -(x-xc) + 0.1*(y-yc),
scale * z0
);
vec = vec.divideScalar(vec.length());
this.data[ix*(this.height*this.depth) + iy*this.depth + iz] = vec;
}
}
}
}
this.generateTest1 = function() {
for(var iz = 0; iz < this.depth; iz++ )
{
for(var iy = 0; iy < this.height; iy++ )
{
for(var ix = 0; ix < this.width; ix++ )
{
var vec = new THREE.Vector3(-iy/this.height - 0.5, ix/this.width - 0.5, 0.0);
vec.add(new THREE.Vector3(-ix/this.width + 0.5, iy/this.height - 0.5, 0.0).multiplyScalar(5));
vec.divideScalar(3);
this.data[ix*(this.height*this.depth) + iy*this.depth + iz] = vec;
}
}
}
}
/**
* Samples the volume by nearest neighbor.
* @param {THREE.Vector3} pos The position, where data should be sampled.
*/
this.nearest = function(pos) {
var x = Math.floor(pos.x * this.width);
var y = Math.floor(pos.y * this.height);
var z = Math.floor(pos.z * this.depth);
var res = this.data[x*(this.height*this.depth) + y*this.depth + z];
return res.clone();
}
/**
* Samples the volume trilinear. (Not really ...)
* @param {THREE.Vector3} pos The position, where data should be sampled.
*/
this.trilinear = function(pos) {
var x0 = Math.floor(pos.x * this.width);
var x1 = x0+1;
var y0 = Math.floor(pos.y * this.height);
var y1 = y0+1;
var z0 = Math.floor(pos.z * this.depth);
var z1 = z0+1;
if (z1 == 0 || z1 == this.depth-1 ||
y1 == 0 || y1 == this.height-1 ||
x1 == 0 || x1 == this.width-1 ||
z0 == 0 || z0 == this.depth-1 ||
y0 == 0 || y0 == this.height-1 ||
x0 == 0 || x0 == this.width-1) {
// We are at the edge, so we are lazy and use nearest neighbor here.
return this.nearest(pos);
} else {
// TODO implement real trilinear
var sum = new THREE.Vector3();
sum.add(this.data[(x0+1)*(this.height*this.depth) + y0 *this.depth + z0 ]);
sum.add(this.data[(x0-1)*(this.height*this.depth) + y0 *this.depth + z0 ]);
sum.add(this.data[ x0 *(this.height*this.depth) + (y0+1)*this.depth + z0 ]);
sum.add(this.data[ x0 *(this.height*this.depth) + (y0-1)*this.depth + z0 ]);
sum.add(this.data[ x0 *(this.height*this.depth) + y0 *this.depth + (z0+1)]);
sum.add(this.data[ x0 *(this.height*this.depth) + y0 *this.depth + (z0-1)]);
sum.divideScalar(6);
return sum;
}
}
}