class Vec3D extends PVector {
public Vec3D() {
super(0,0,0);
}
public Vec3D(float x, float y, float z) {
super(x,y,z);
}
public Vec3D(PVector old) {
super(old.x, old.y, old.z);
}
public Vec3D cross(Vec3D p) {
Vec3D r = new Vec3D(super.cross(p));
return r;
}
public Vec3D normalized() {
float mag = (float) Math.sqrt(x * x + y * y + z * z);
if (mag > 0) {
mag = 1f / mag;
x *= mag;
y *= mag;
z *= mag;
}
return this;
}
}
class VivianiCurve {
int curve_length = 100; // number of points that represent the curve
Vec3D points[];
float a = 50;
VivianiCurve(int l) {
curve_length = l;
points = new Vec3D[curve_length];
sample();
}
void sample() {
float theta = 0.1;
float p = 2.4;
float q = 1.6;
float dt = ((TWO_PI) / 100)*3;
for (int i=0; i<curve_length; i++) {
points[i] = sample(theta);
theta += dt;
}
}
float getPeriod() {
return TWO_PI*3;
}
Vec3D sample(float theta) {
float x = a*(1+cos(theta));
float y = a*sin(theta);
float z = 2*a*sin( theta/2 );
return new Vec3D(x,y,z);
}
Vec3D[] getPoints() {
return points;
}
public Vec3D derivateI(float t) {
Vec3D r = new Vec3D();
r.x = - a * sin(t);
r.y = cos(t);
r.z = a * cos( t/2 );
return r;
}
public Vec3D derivateII(float t) {
Vec3D r = new Vec3D();
r.x = cos(t);
r.y = - sin(t);
r.z = - sin( t/2 );
return r;
}
Vec3D getTangent(float t) {
Vec3D tangentVector = derivateI(t);
return tangentVector.normalized();
}
Vec3D getNormal(float t) {
return getBinormal(t).cross(getTangent(t)).normalized();
}
Vec3D getBinormal(float t) {
Vec3D derivataI = derivateI(t);
Vec3D derivataII = derivateII(t);
Vec3D binormalVector = derivataI.cross(derivataII);
return binormalVector.normalized();
}
}
void drawFrenetFrame() {
float t = map(mouseX, 0, width, 0, viviani.getPeriod());
Vec3D point = viviani.sample(t);
Vec3D temp = viviani.getTangent(t);
drawVector(point.x, point.y, point.z, point.x+temp.x*10, point.y+temp.y*10, point.z+temp.z*10);
temp = viviani.getBinormal(t);
drawVector(point.x, point.y, point.z, point.x+temp.x*10, point.y+temp.y*10, point.z+temp.z*10);
temp = viviani.getNormal(t);
drawVector(point.x, point.y, point.z, point.x+temp.x*10, point.y+temp.y*10, point.z+temp.z*10);
}
void drawAxis() {
stroke(150);
drawVector(0,0,0, 10, 0, 0);
stroke(150);
beginShape();
drawVector(0,0,0, 0, 10, 0);
endShape();
stroke(150);
beginShape();
drawVector(0,0,0, 0, 0, 10);
endShape();
}
void drawVector(float v1x, float v1y, float v1z,float v2x, float v2y, float v2z) {
beginShape();
vertex(v1x,v1y,v1z);
vertex(v2x,v2y,v2z);
endShape();
}
void drawCurve(Vec3D points[]) {
beginShape();
for(int i=0; i<points.length; i++) {
vertex(points[i].x, points[i].y, points[i].z);
}
endShape();
}
import processing.opengl.*;
import javax.media.opengl.*;
PFont font;
VivianiCurve viviani;
float rotx=0, roty=0, mX=0, mY=0;
void setup() {
size(600,400, OPENGL);
smooth();
font = loadFont("font.vlw");
textFont(font, 14);
viviani = new VivianiCurve(100);
}
void draw() {
background(230);
noFill();
lights();
stroke(80);
fill(80);
text("Viviani's curve."+
"\n move the mouse to change Frenet-frame position"+
"\n drag to rotate",
20, 20);
translate(width/2, height/2);
rotateX(rotx);
rotateY(roty);
drawAxis();
stroke(80);
noFill();
drawCurve(viviani.getPoints());
drawFrenetFrame();
}
void mousePressed() {
mX = mouseX;
mY = mouseY;
}
void mouseDragged() {
rotx += (mY-mouseY) * 0.01;
roty += (mX-mouseX) * 0.01;
mousePressed();
}
Viviani's curve, move the mouse to move Frenet frame, drag to rotate