• fullscreen
• Vec3D.pde
• VivianiCurve.pde
• draws.pde
• viviani.pde
• ```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();

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();
}

```

### tweaks (0)

This sketch is running as Java applet, exported from Processing.