// Generates a packing of points inside a shape // press right/middle mouse buttons a few times until convergence...
class pnt
{
float x; float y; float z;
float len()
{
return sqrt(x*x + y*y + z*z);
}
};
pnt points[] = new pnt[32];
float scalefact = 100;
float mindist = scalefact * 0.5;
void setup() {
size(512, 512, P3D);
fill(204);
for(int i=0; i< points.length; i++)
{
points[i]=new pnt();
points[i].x = random(scalefact*2)-scalefact;
points[i].y = random(scalefact*2)-scalefact;
points[i].z = random(scalefact*2)-scalefact;
}
}
float getImportance(pnt a)
{
return 1.3 - (((a.z/scalefact) + (a.z/a.len()))/2);
}
void mousePressed()
{
if(mouseButton == LEFT) // dump points, report
{
final float UNIT_HEMISPHERE_VOL = (4.0/3.0) * 3.141592 * 0.5;
float totalVol = 0;
for(int i=0; i< points.length; i++)
{
float normRadius = mindist * getImportance(points[i]) / scalefact;
float vol = (4.0/3.0) * 3.141592 * normRadius * normRadius * normRadius;
totalVol+=vol;
}
println("vol ratio" + UNIT_HEMISPHERE_VOL/totalVol);
for(int i=0; i< points.length; i++)
{
//println(points[i].x/scalefact+", "+points[i].y/scalefact+", "+points[i].z/scalefact+", "+points[i].len()/scalefact+",");
float normRadius = mindist * getImportance(points[i]) / scalefact;
float vol = (4.0/3.0) * 3.141592 * normRadius * normRadius * normRadius;
float weight = vol / totalVol;
println(points[i].x/scalefact+", "+points[i].y/scalefact+", "+points[i].z/scalefact+", "+weight+",");
}
println("vol ratio: " + UNIT_HEMISPHERE_VOL/totalVol);
}
else if(mouseButton == CENTER)
{
mindist -= 5; // manual control...
}
else // RIGHT mouse button
{
// A LITTLE BIT OF NOISE
for(int i=0; i< points.length; i++)
{
points[i].x += random(mindist/(scalefact/10))-(mindist/(scalefact/5));
points[i].y += random(mindist/(scalefact/10))-(mindist/(scalefact/5));
points[i].z += random(mindist/(scalefact/10))-(mindist/(scalefact/5));
}
}
}
void draw() {
lights();
background(0);
// Change height of the camera with mouseY
camera(sin(mouseX/512.0 * 6.0)*300, cos(mouseX/512.0 * 6.0)*300, mouseY, // eyeX, eyeY, eyeZ
0.0, 0.0, 0.0, // centerX, centerY, centerZ
0.0, 0.0, -1.0); // upX, upY, upZ
noStroke();
// SHAPE CONSTRAINT
for(int i=0; i< points.length; i++)
{
float len = points[i].len();
float radius = getImportance(points[i])*mindist;
len+=radius;
if(len > scalefact) // inside the sphere
{
points[i].x /= len / scalefact;
points[i].y /= len / scalefact;
points[i].z /= len / scalefact;
}
// hemisphere
if(points[i].z-radius< 0) points[i].z=radius;
}
float totaldist = 0;
// DISTANCE CONSTRAINT
for(int i=0; i< points.length; i++)
{
float radius = getImportance(points[i])*mindist;
for(int k=0; k< 50; k++)
{
int j = (int)random(points.length);
if(i!=j)
{
pnt tmp = new pnt();
tmp.x = points[j].x - points[i].x;
tmp.y = points[j].y - points[i].y;
tmp.z = points[j].z - points[i].z;
float len = tmp.len();
if( len < radius )
{
tmp.x = (tmp.x/len) * radius;
tmp.y = (tmp.y/len) * radius;
tmp.z = (tmp.z/len) * radius;
points[i].x = points[j].x - tmp.x;
points[i].y = points[j].y - tmp.y;
points[i].z = points[j].z - tmp.z;
totaldist += len;
}
}
}
}
// display distance violation
fill(15,15,15,255);
box(scalefact,scalefact,1);
totaldist = sqrt(totaldist);
fill(128,0,128,128);
box(totaldist,totaldist,5);
for(int i=0; i< points.length; i++)
{
pushMatrix();
translate(points[i].x,points[i].y,points[i].z);
if(mindist>0)
{
fill(255,255,255,64);
sphere(mindist * getImportance(points[i]) );
}
fill(255,0,0,255);
sphere(5 * getImportance(points[i]) );
popMatrix();
stroke(255,0,0,255);
line(0,0,0,points[i].x,points[i].y,points[i].z);
noStroke();
}
}