addBall method
void
addBall(])
////////////////////////////////// //////////////////////////////////
Implementation
// Metaballs
/////////////////////////////////////
// Adds a reciprocal ball (nice and blobby) that, to be fast, fades to zero after
// a fixed distance, determined by strength and subtract.
void addBall(double ballx,double bally,double ballz, double strength,int subtract, [dynamic colors]) {
final sign = strength.sign;
strength = strength.abs();
bool userDefineColor = colors != null;
Color ballColor = Color( ballx, bally, ballz );
if ( userDefineColor ) {
try {
ballColor = colors is Color
? colors
:(colors is List<double>)
?Color(
math.min(colors[0].abs().toDouble(), 1),
math.min(colors[1].abs().toDouble(), 1),
math.min(colors[2].abs().toDouble(), 1)
):Color(colors);
}
catch(err){
ballColor = Color( ballx, bally, ballz );
}
}
// Let's solve the equation to find the radius:
// 1.0 / (0.000001 + radius^2) * strength - subtract = 0
// strength / (radius^2) = subtract
// strength = subtract * radius^2
// radius^2 = strength / subtract
// radius = sqrt(strength / subtract)
final radius = size * math.sqrt( strength / subtract );
final zs = ballz * size;
final ys = bally * size;
final xs = ballx * size;
int minZ = ( zs - radius ).floor();
if ( minZ < 1 ) minZ = 1;
int maxZ = ( zs + radius ).floor();
if ( maxZ > size - 1 ) maxZ = size.toInt() - 1;
int minY = ( ys - radius ).floor();
if ( minY < 1 ) minY = 1;
int maxY = ( ys + radius ).floor();
if ( maxY > size - 1 ) maxY = size.toInt() - 1;
int minX = ( xs - radius ).floor();
if ( minX < 1 ) minX = 1;
int maxX = (xs + radius).floor();
if ( maxX > size - 1 ) maxX = size.toInt() - 1;
// Don't polygonize in the outer layer because normals aren't
// well-defined there.
for (int z = minZ; z < maxZ; z ++ ) {
double zOffset = size2 * z;
double fz = z / size - ballz;
double fz2 = fz * fz;
for (int y = minY; y < maxY; y ++ ) {
double yOffset = zOffset + size * y;
double fy = y / size - bally;
double fy2 = fy * fy;
for (int x = minX; x < maxX; x ++ ) {
double fx = x / size - ballx;
double val = strength / ( 0.000001 + fx * fx + fy2 + fz2 ) - subtract;
if ( val > 0.0 ) {
field[ yOffset.toInt() + x ] += val * sign;
// optimization
// http://www.geisswerks.com/ryan/BLOBS/blobs.html
final ratio = math.sqrt( ( x - xs ) * ( x - xs ) + ( y - ys ) * ( y - ys ) + ( z - zs ) * ( z - zs ) ) / radius;
final contrib = 1 - ratio * ratio * ratio * ( ratio * ( ratio * 6 - 15 ) + 10 );
palette[(yOffset + x).toInt() * 3 + 0] += ballColor.red * contrib;
palette[(yOffset + x).toInt() * 3 + 1] += ballColor.green * contrib;
palette[(yOffset + x).toInt() * 3 + 2] += ballColor.blue * contrib;
}
}
}
}
}