Hi quarks,
I've been experimenting with your fantastic shapes3d library and have encountered some problms using the I_RadiusGen interface.
In the code below, the class implementing the interface, VariableTubeRadius, uses the parameter function
50*(t+0.00001)*(1-t).
The reason I've included the factor t+0.00001 in this function (and not simply t) is that with the latter the variable radius implementation fails. This seems to be due to the fact that the function value is zero at t = 0. But then the function value is also zero when t = 1.
So my first question is what's going on here?
My second question relates to the fact that the 't = 0' and 't = 1' ends of each bezier tube have a significantly different radius. As far as I can tell this is not due to the fact that I've added 0.00001 to the first factor in t - as the same probelm occurs when this factor is replaced with t + 0.00000000000001 (for example).
What's going on here?
I'm quite fond of these bezier tubes and it'd be great if I could code the variable radius function such that they are precisely tapered at both ends.
Cheers,
Jim
- import peasy.*;
import shapes3d.utils.*;
import shapes3d.animation.*;
import shapes3d.*;
PeasyCam cam;
import processing.opengl.*;
int bezTubeNumber = 5;
int sIA, pIA, cSIA, cPIA, sIB, pIB, cSIB, cPIB;
float cPSA, cPSB;
int w = 700;
int h = 650;
int n = 3;
float[][][] p = new float[6][int(pow(n,2))][3];
float Xi = 0;
float Yi = 0;
float Zi = 0;
float s = 200;
boolean pcam = true;
int segs = 20, slices = 20;
ArrayList btube = new ArrayList();
float bezTubeRadius = 50.0;
boolean reGen = true;
VariableTubeRadius vTRO = new VariableTubeRadius();
void setup() {
size(w, h, OPENGL);
hint(ENABLE_OPENGL_4X_SMOOTH);
background(255);
lights();
if (pcam) {
cam = new PeasyCam(this, 800);
cam.setRotations(-1.1393493,0.59715605,-0.23067099);
cam.lookAt(100.6000938,-2.0371575,-3.7414675);
}
smooth();
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
p[0][j+i*n][0] = (float)(Xi + s);
p[0][j+i*n][1] = (float)(Yi + j*s/(n-1));
p[0][j+i*n][2] = (float)(Zi + (n-1-i)*s/(n-1));
}
}
for (int k = 0; k < pow(n,2); k++) {
p[1][k][0] = Xi + Yi + s - p[0][k][1];
p[1][k][1] = Yi + p[0][k][0] - Xi;
p[1][k][2] = p[0][k][2];
}
for (int k = 0; k < pow(n,2); k++) {
p[2][k][0] = 2*Xi + s - p[0][k][0];
p[2][k][1] = p[0][k][1];
p[2][k][2] = p[0][k][2];
}
for (int k = 0; k < pow(n,2); k++) {
p[3][k][0] = p[1][k][0];
p[3][k][1] = Yi;
p[3][k][2] = p[1][k][2];
}
for (int k = 0; k < pow(n,2); k++) {
p[4][k][0] = Xi + Zi + s - p[1][k][2];
p[4][k][1] = p[0][k][1];
p[4][k][2] = Zi + s;
}
for (int k = 0; k < pow(n,2); k++) {
p[5][k][0] = p[4][k][0];
p[5][k][1] = p[4][k][1];
p[5][k][2] = Zi;
}
}
void draw() {
background(255);
if (reGen) {
btube.clear();
for (int i = 0; i < bezTubeNumber; i++) {
sIA = int(round(random(5)));
pIA = int(round(random(int(pow(n,2)-1))));
cSIA = opp(sIA);
cPIA = pIA;
cPSA = 1.0;
sIB = int(round(random(5)));
pIB = int(round(random(int(pow(n,2)-1))));
cSIB = opp(sIB);
cPIB = pIB;
cPSB = 1.0;
btube.add(makeBezTube(sIA, pIA, cSIA, cPIA, cPSA, cSIB, cPIB, cPSB, sIB, pIB));
}
reGen = false;
}
pushMatrix();
translate(Xi,Yi,Zi);
for (int i = 0; i < btube.size(); i++) {
((BezTube)btube.get(i)).drawMode(Shape3D.SOLID | Shape3D.WIRE);
((BezTube)btube.get(i)).draw();
}
popMatrix();
}
public BezTube makeBezTube(int sideIndexA, int pointIndexA, int controlSideIndexA, int controlPointIndexA, float controlPointStretchA,
int controlSideIndexB, int controlPointIndexB, float controlPointStretchB, int sideIndexB, int pointIndexB) {
PVector[] pV = new PVector[] {
new PVector(p[sideIndexA][pointIndexA][0], p[sideIndexA][pointIndexA][1], p[sideIndexA][pointIndexA][2]),
new PVector(controlPointStretchA*p[controlSideIndexA][controlPointIndexA][0], controlPointStretchA*p[controlSideIndexA][controlPointIndexA][1], controlPointStretchA*p[controlSideIndexA][controlPointIndexA][2]),
new PVector(controlPointStretchB*p[controlSideIndexB][controlPointIndexB][0], controlPointStretchB*p[controlSideIndexB][controlPointIndexB][1], controlPointStretchB*p[controlSideIndexB][controlPointIndexB][2]),
new PVector(p[sideIndexB][pointIndexB][0], p[sideIndexB][pointIndexB][1], p[sideIndexB][pointIndexB][2])
};
BezTube bt = new BezTube(this, new Bezier3D(pV, pV.length), vTRO, segs, slices);
bt.stroke(color(0,0,0));
bt.strokeWeight(2.0f);
return bt;
}
int opp(int inSide) {
int outSide = 0;
switch(inSide) {
case 0:
outSide = 2;
break;
case 1:
outSide = 3;
break;
case 2:
outSide = 0;
break;
case 3:
outSide = 1;
break;
case 4:
outSide = 5;
break;
case 5:
outSide = 4;
break;
}
return outSide;
}
public class VariableTubeRadius implements I_RadiusGen {
VariableTubeRadius() {
}
public float radius(float t) {
return 50*(t+0.00001)*(1-t);
}
public boolean hasConstantRadius() {
return false;
}
Object getController() {
return null;
}
}