not as elegant as the other posts:
simple example showing Dodecahedron and
tetrahedron and pyramid - maybe you can form the shapes to crystals.
I just wanted to show some usages of vectors in 3D
Chrisir
/*
Demo program for a 3D class named ThreeD.
This class shows different solids to draw in 3D.
This class is not about one item (Car) but more a
collection of different commands for the realm / domain of 3D.
Among others Platonic solids.
It also features a small camera class named CameraClass.
Use mainly space key to change state and q to start/stop rotation.
Use also o/p to rotate cam manually.
Much better: shapes 3D library by quarks.
*/
// core class
ThreeD threeD = new ThreeD();
// ----------------------------------------------
void setup() {
size(1900, 950, P3D);
}
void draw() {
background(0);
lights();
pushMatrix();
noStroke();
fill(threeD.WHITE);
translate(width/2, 300, -210);
rotateY(map(millis()%5000, 0, 5000, 0, TWO_PI));
threeD.tetrahedron ( 0, 0, 0, 37 );
popMatrix();
// -------------------------------
pushMatrix();
fill(threeD.WHITE);
translate(width/2+300, 300, -210);
rotateY(map(millis()%5000, 0, 5000, 0, TWO_PI));
threeD.Octahedron();
popMatrix();
// -------------------------------
pushMatrix();
noStroke();
stroke(111);
fill(threeD.WHITE);
translate(width/2-390, 300, -410);
rotateY(map(millis()%5000, 0, 5000, 0, TWO_PI));
threeD.pyramid ( );
popMatrix();
// -------------------------------
pushMatrix();
noStroke();
// fill(threeD.WHITE);
translate(width/2-111, 500, 210);
rotateY(map(millis()%5000, 0, 5000, 0, TWO_PI));
threeD.dodecahedron();
popMatrix();
//
} // func
// ==============================================
class ThreeD {
/*
This class shows different solids to draw in 3D.
This class is not about one item (Car) but more a
collection of different commands for the realm of 3D.
section 1: reference section "2D Primitives" now in 3D
section 2: reference section "3D Primitives" now in enhanced version
section 3: Platonic solids
section 4: other, non platonic solids
section 5: coordinate system and related
section 6: HUD funcs / Head-up-Display funcs
section 7: floor
section 8: minor help functions
*/
// consts
final color RED = color (255, 0, 0);
final color GREEN = color (0, 255, 0);
final color BLUE = color (0, 0, 255);
final color WHITE = color (255);
final color BLACK = color (0);
final color GRAY = color (111);
final color YELLOW = color (255, 255, 0);
final color YELLOWWARM = color (255, 245, 49);
final color VIOLET = color (143, 0, 255);
final color INDIGO = color (111, 0, 255);
final color MAGENTA = color (255, 0, 255);
final color PINK = color (255, 192, 203);
final color ORANGE = color (255, 165, 0);
// vars
boolean crosshair;
boolean showAsStandard=true; // space bar toggles
// section 1:
// reference section "2D Primitives" now in 3D ----------------------
// read the ref there, they are just changed a bit to be 3D
void point(PVector pos) {
// version with PVector parameter.
// calls another method in the same class.
// See there for description.
point(pos.x, pos.y, pos.z);
}
void point(PVector pos, String str) {
// version with PVector parameter.
// calls another method in the same class.
// See there for description.
// With local text next to the point.
point(pos.x, pos.y, pos.z);
text(str, pos.x+6, pos.y+6, pos.z);
}
void point(float x, float y, float z) {
// point as a sphere, fixed size 5,
// fixed noStroke, no fill color, you
// must set the fill color before using
// this method.
noStroke();
pushMatrix();
translate(x, y, z);
sphere(5);
popMatrix();
}
void ellipse3D(float x, float y, float z, float size1) {
// point as a sphere, fixed size 5,
// fixed noStroke, no fill color, you
// must set the fill color before using
// this method.
noStroke();
pushMatrix();
translate(x, y, z);
ellipse(0, 0, size1, size1);
popMatrix();
}
void line3D(float x1, float y1, float z1,
float x2, float y2, float z2,
float weight, color colorLine)
// drawLine was programmed by James Carruthers
// see http://processing.org/discourse/yabb2/YaBB.pl?num=1262458611/0#9
{
// scale(90);
PVector p1 = new PVector(x1, y1, z1);
PVector p2 = new PVector(x2, y2, z2);
PVector v1 = new PVector(x2-x1, y2-y1, z2-z1);
float rho = sqrt(pow(v1.x, 2)+pow(v1.y, 2)+pow(v1.z, 2));
float phi = acos(v1.z/rho);
float the = atan2(v1.y, v1.x);
v1.mult(0.5);
pushMatrix();
PVector v2 = new PVector ( x1, y1, z1 );
translate(v2.x, v2.y, v2.z);
translate(v1.x, v1.y, v1.z);
rotateZ(the);
rotateY(phi);
noStroke();
fill(colorLine);
box(weight, weight, p1.dist(p2));
popMatrix();
} // method
void triangle(float x1, float y1, float z1,
float x2, float y2, float z2,
float x3, float y3, float z3) {
beginShape();
vertex(x1, y1, z1);
vertex(x2, y2, z2);
vertex(x3, y3, z3);
endShape(CLOSE);
}
void quad(
float x1, float y1, float z1,
float x2, float y2, float z2,
float x3, float y3, float z3,
float x4, float y4, float z4) {
beginShape();
vertex(x1, y1, z1);
vertex(x2, y2, z2);
vertex(x3, y3, z3);
vertex(x4, y4, z4);
endShape(CLOSE);
}
void rect(
float x1, float y1, float z1,
float w, float h) {
beginShape();
vertex(x1, y1, z1);
vertex(x1+w, y1, z1);
vertex(x1+w, y1+h, z1);
vertex(x1, y1+h, z1);
endShape(CLOSE);
}
// section 2:
// reference section "3D Primitives" now in enhanced version ----------------------
void box3D (float x, float y, float z,
float sizeBox,
color col ) {
fill(col);
pushMatrix();
translate(x, y, z);
box(sizeBox);
popMatrix();
}
void sphere3D (float x, float y, float z,
float sizeBox,
color col ) {
fill(col);
pushMatrix();
translate(x, y, z);
sphere(sizeBox);
popMatrix();
}
// section 3:
// Platonic solids ----------------------
// http://en.wikipedia.org/wiki/Platonic_solid
// also cube / box is a Platonic solid - see above
void tetrahedron(float x1, float y1, float z1, float size1 ) {
// tetrahedron
// A(1,1,–1), C(–1,–1,–1), F(–1,1,1) und H(1,–1,1).
// see http://en.wikipedia.org/wiki/Tetrahedron#Formulas_for_a_regular_tetrahedron
// see http://de.wikipedia.org/wiki/Datei:Tetraeder_animation_with_cube.gif
scale (size1);
// fill(GREEN);
beginShape();
vertex(1, 1, -1);
vertex(-1, -1, -1);
vertex(-1, 1, 1) ;
endShape();
// fill(BLUE);
beginShape();
vertex(1, -1, 1);
vertex(-1, -1, -1);
vertex(-1, 1, 1) ;
endShape();
// fill(PINK);
beginShape();
vertex(1, -1, 1);
vertex(-1, -1, -1);
vertex(1, 1, -1);
endShape();
// fill(YELLOW);
beginShape();
vertex(1, 1, -1);
vertex(1, -1, 1);
vertex(-1, 1, 1) ;
endShape();
//
// noFill();
// box(2);
//
}
void Octahedron() {
// (eight faces)
// see http://en.wikipedia.org/wiki/Octahedron
/*
( ±1, 0, 0 );
( 0, ±1, 0 );
( 0, 0, ±1 ).
*/
// define vertices
PVector [] list = new PVector[6];
list [0] = new PVector (1, 0, 0);
list [1] = new PVector (0, 0, 1);
list [2] = new PVector (0, -1, 0);
list [3] = new PVector (-1, 0, 0);
list [4] = new PVector (0, 0, -1);
list [5] = new PVector (0, 1, 0);
// scale (33);
for (int i = 0; i < list.length; i++) {
list[i].mult(49);
// point(list[i], str(i));
}
fillAndStroke (BLUE, BLACK);
// defines the shapes
// the lower half
makeShape (list [0], list [1], list [5] ) ;
makeShape (list [0], list [4], list [5] ) ;
makeShape (list [3], list [4], list [5] ) ;
makeShape (list [3], list [1], list [5] ) ;
// the upper half
makeShape (list [0], list [1], list [2] ) ;
makeShape (list [0], list [4], list [2] ) ;
makeShape (list [3], list [4], list [2] ) ;
makeShape (list [3], list [1], list [2] ) ;
} // method
//
// section 4:
// other, non platonic solids ----------------------
void pyramid () {
scale(88);
noStroke();
beginShape();
fill(threeD.WHITE);
vertex(-1, -1, -1);
vertex( 1, -1, -1);
vertex( 0, 0, 1);
endShape(CLOSE);
beginShape();
vertex( 1, -1, -1);
vertex( 1, 1, -1);
vertex( 0, 0, 1);
endShape(CLOSE);
beginShape();
vertex( 1, 1, -1);
vertex(-1, 1, -1);
vertex( 0, 0, 1);
endShape(CLOSE);
beginShape();
vertex(-1, 1, -1);
vertex(-1, -1, -1);
vertex( 0, 0, 1);
endShape(CLOSE);
}
// -------------------------------------------------------------------------
void dodecahedron() {
/*
regular dodecahedron = composed of twelve regular pentagonal faces, three meeting at each vertex.
A regular dodecahedron or pentagonal dodecahedron is a dodecahedron that is regular, which is composed of twelve regular pentagonal faces, three meeting at each vertex.
It is one of the five Platonic solids. It has 12 faces, 20 vertices, 30 edges, and 160 diagonals (60 face diagonals, 100 space diagonals).[1] It is represented by the Schläfli symbol {5,3}.
*/
boolean showPink = false; // 0
boolean showOrange = false; // 1
boolean showBlue = false; // 2
boolean showGreen = false; // 3
// size
float f1 = 19; // 19 is a good factor
float goldenRatio = (1 + sqrt(5)) / 2 ; // ~ 1.618;
//print (goldenRatio);
//println (" ~ 1.618");
// The orange vertices lie at (±1, ±1, ±1) and form a cube (dotted lines).
PVector [] orange = new PVector[8];
orange [0] = new PVector (1, 1, 1); // 0 times -
orange [1] = new PVector (-1, -1, -1); // 3 times -
orange [2] = new PVector (-1, 1, 1); // 1 time -
orange [3] = new PVector (1, -1, 1); // 1 time -
orange [4] = new PVector (1, 1, -1); // 1 time -
orange [5] = new PVector (-1, -1, 1);// 2 time -
orange [6] = new PVector (1, -1, -1);// 2 time -
orange [7] = new PVector (-1, 1, -1);// 2 time -
for (int i = 0; i < orange.length; i++) {
orange[i].mult(f1);
if (showOrange) {
fill(ORANGE);
pointPvStr(orange[i], str(i));
}
}
if (showOrange) {
stroke(ORANGE);
// //2536
linePV (orange [1], orange [5]);
linePV (orange [5], orange [3]);
linePV (orange [3], orange [6]);
linePV (orange [6], orange [1]);
//7204
linePV (orange [7], orange [2]);
linePV (orange [2], orange [0]);
linePV (orange [0], orange [4]);
linePV (orange [4], orange [7]);
// 17 and 25
linePV (orange [1], orange [7]);
linePV (orange [2], orange [5]);
// 30 and 64
linePV (orange [3], orange [0]);
linePV (orange [6], orange [4]);
}
// --------------------------------
// The green vertices lie at (0, ±ϕ, ±1/ϕ) and form a rectangle on the yz-plane.
PVector [] green = new PVector[4];
green [0] = new PVector (0, -goldenRatio, -1/goldenRatio); // 2 times -
green [1] = new PVector (0, goldenRatio, 1/goldenRatio); // 0 tmes -
green [2] = new PVector (0, -goldenRatio, 1/goldenRatio); // 1 time - [minus and then +]
green [3] = new PVector (0, goldenRatio, -1/goldenRatio); // 1 time - [+ and then minus]
for (int i = 0; i < green.length; i++) {
green[i].mult(f1);
if (showGreen) {
fill(GREEN);
pointPvStr(green[i], str(i));
}
}
if (showGreen) {
PVector[] pvGreenArrayForFunctionQuadArray =
{ green [1], green [2], green [0], green [3] };
stroke(GREEN);
quadArray(pvGreenArrayForFunctionQuadArray); //
}// if
// --------------------------------
// The blue vertices lie at (±1/ϕ, 0, ±ϕ) and form a rectangle on the xz-plane.
PVector [] blue = new PVector[4];
blue [0] = new PVector (-1/goldenRatio, 0, -goldenRatio); // 2 times -
blue [1] = new PVector ( 1/goldenRatio, 0, goldenRatio); // 0 tmes -
blue [2] = new PVector ( 1/goldenRatio, 0, -goldenRatio); // 1 time -
blue [3] = new PVector (-1/goldenRatio, 0, goldenRatio); // 1 time -
for (int i = 0; i < blue.length; i++) {
blue[i].mult(f1);
if (showBlue) {
fill(BLUE);
pointPvStr(blue[i], str(i));
}
}
if (showBlue) {
PVector[] pvArrayBlueForFunctionQuadArray =
{ blue [1], blue [2], blue [0], blue [3] };
stroke(BLUE);
quadArray(pvArrayBlueForFunctionQuadArray);
}
// -----------------------
//The pink vertices lie at (±ϕ, ±1/ϕ, 0) and form a rectangle on the xy-plane.
//The distance between adjacent vertices is 2/ϕ, and the distance from the origin to any vertex is √3.
//ϕ = (1 + √5) / 2 is the golden ratio.
PVector [] pink = new PVector[4];
pink [0] = new PVector ( -goldenRatio, -1/ goldenRatio, 0); // 2 times -
pink [1] = new PVector ( goldenRatio, 1/ goldenRatio, 0); // 0 tmes -
pink [2] = new PVector ( goldenRatio, -1/ goldenRatio, 0); // 1 time -
pink [3] = new PVector ( -goldenRatio, 1/ goldenRatio, 0); // 1 time -
for (int i = 0; i < pink.length; i++) {
pink[i].mult(f1);
if (showPink) {
fill(PINK);
pointPvStr(pink[i], str(i));
}
}
if (showPink) {
PVector[] pvArrayPinkForFunctionQuadArray =
{ pink [1], pink [2], pink [0], pink [3] };
stroke(PINK);
quadArray(pvArrayPinkForFunctionQuadArray);
}
// ----------------------------------------
// fill(RED, 110);
fill(RED);
stroke(WHITE);
makeShape5 ( blue[3], blue[1],
orange[0],
green [1],
orange[2]);
makeShape5 ( blue[1],
orange[0],
pink[1], pink[2],
orange[3]);
makeShape5 ( orange[0],
green [1], green [3],
orange[4],
pink[1] );
makeShape5( orange[2],
pink[3],
orange[7],
green[3], green[1]);
makeShape5( green[3],
orange[7],
blue[0], blue[2],
orange[4]);
makeShape5( pink[1],
orange[4],
blue[2],
orange[6],
pink[2]);
makeShape5( pink[0], //penta6.png
pink[3],
orange[7],
blue[0],
orange[1]);
makeShape5( blue[3], //penta7.png
orange[2],
pink[3], pink[0],
orange[5]);
makeShape5( orange[1], // penta8
blue[0], blue[2],
orange[6],
green[0] );
fill(GREEN);
makeShape5( orange[5], // penta9
pink[0],
orange[1],
green[0], green[2] );
// noFill();
strokeWeight(4);
makeShape5( orange[3], // penta 10
green[2], green[0],
orange[6],
pink[2]);
strokeWeight(1); // back to default
fill(YELLOW);
makeShape5( blue[1], blue[3], // penta 11
orange[5],
green[2],
orange[3] );
// to test a new pentagon
//fill(YELLOW);
//PVector [] c1 = {
// // vertices here
//};
//quadArray(c1);
// noLoop();
}//method
// ------------------------------
// section 5:
// coordinate system and related ----------------------
// by ofey
void coorWalls() {
// draw 3 walls in 3D which mark a coordinate systems.
// coordinate system wall
// by ofey
//
fill(BLUE);//blue left side
beginShape();
vertex(0, 0, 0);
vertex(0, 0, -400);
vertex(0, 400, -400);
vertex(0, 400, 0);
endShape(CLOSE);
fill(YELLOW);//yellow bottom
beginShape();
vertex(0, 400, 0);
vertex(0, 400, -400);
vertex(400, 400, -400);
vertex(400, 400, 0);
endShape(CLOSE);
fill(GREEN);//green back
beginShape();
vertex(0, 0, -400);
vertex(400, 0, -400);
vertex(400, 400, -400);
vertex(0, 400, -400);
endShape(CLOSE);
}
void ShowCoordinates () {
// Show Coordinates x, y and z as lines
//
// X
stroke (255, 0, 0);
line (0, 0, 0, 100, 0, 0 ) ;
sphere3D (100, 0, 0, 13, color (255, 0, 0) );
text ("X", 120, 60, 0);
// Y
stroke (0, 255, 0);
line (0, 0, 0, 0, 100, 0 ) ;
sphere3D(0, 100, 0, 13, GREEN);
text ("Y", 0, 180, 0);
// Z
stroke (0, 0, 255);
line (0, 0, 0, 0, 0, -300 ) ;
sphere3D (0, 0, -300, 33, BLUE);
text ("-Z", 30, 50, -300);
} // function
void show3DCursor( float theX, float theY, float theZ) {
// show 3D cursor
//
if (crosshair) {
// 3D crosshair
final int len = 15;
stroke(244, 2, 2); // red
line (theX, theY, theZ-len, theX, theY, theZ+len);
stroke(0, 0, 255);
line (theX, theY-len, theZ, theX, theY+len, theZ);
stroke(2, 244, 2);
line (theX-len, theY, theZ, theX+len, theY, theZ);
pushMatrix();
translate(theX, theY, theZ+len);
fill(244, 2, 2);
noStroke();
sphere(1);
popMatrix();
} else
{
// sphere
pushMatrix();
translate(theX, theY, theZ);
fill(WHITE);
noStroke();
sphere(10);
popMatrix();
} // else
} // func
// section 6:
// HUD funcs ----------------------
// Head-up-Display
// see http://de.wikipedia.org/wiki/Head-up-Display
void showTextInHUD(String str1) {
// A small 2D HUD for text in the
// upper left corner.
// This func may only be called a the very end of draw() afaik.
camera();
hint(DISABLE_DEPTH_TEST);
noLights();
textMode(MODEL);
if (str1!=null)
text(str1, 20, 20);
hint(ENABLE_DEPTH_TEST);
} // func
void showTextInHUD(String str1, float x, float y) {
// A small 2D HUD for text at
// free pos.
// This func may only be called a the very end of draw() afaik.
camera();
hint(DISABLE_DEPTH_TEST);
noLights();
textMode(MODEL);
if (str1!=null)
text(str1, x, y);
hint(ENABLE_DEPTH_TEST);
} // func
// section 7:
// floor (later walls (but see coordinate system wall above), sky sphere...) --------------------------------
void CheckeredFloor() {
noStroke();
for (int i = 0; i < 40; i = i+1) {
for (int j = 0; j < 40; j = j+1) {
// % is modulo, meaning rest of division
if (i%2 == 0) {
if (j%2 == 0) {
fill (255, 0, 0);
} else
{
fill ( 103 );
}
} else {
if (j%2 == 0) {
fill ( 103 );
} else
{
fill (255, 0, 0);
}
} // if
pushMatrix();
translate ( 40*i-500, 360, 40*j-640 );
box (40, 7, 40);
popMatrix();
} // for
} // for
} // function
// section 8:
// minor help functions ----------------------
//
// vertex ---
//
void pointPvStr(PVector pos, String str) {
// version with PVector parameter.
// calls another method in the same class.
// See there for description.
point(pos.x, pos.y, pos.z);
// pointSphere(pos.x, pos.y, pos.z);
text(str, pos.x+6, pos.y+6, pos.z);
}
void pointSpherePV(PVector pv) {
// PVector
pointSphere(pv.x, pv.y, pv.z);
}
void linePV ( PVector pv1, PVector pv2) {
line (pv1.x, pv1.y, pv1.z,
pv2.x, pv2.y, pv2.z);
}
void pointSphere(float x, float y, float z) {
// point as a sphere, fixed size 5,
// fixed noStroke, no fill color, you
// must set the fill color before using
// this method.
noStroke();
pushMatrix();
translate(x, y, z);
sphere(3);
popMatrix();
}
void vertexPVector ( PVector pos ) {
vertex(pos.x, pos.y, pos.z);
}
void makeShape( PVector p1, PVector p2, PVector p3 ) {
beginShape();
vertexPVector(p1);
vertexPVector(p2);
vertexPVector(p3);
endShape();
}
void makeShape5( PVector p1, PVector p2, PVector p3, PVector p4, PVector p5) {
/*
// too compensate optically for the different length of iPentagonCounter (it's either 0..9 or 10/11) we use either " : " (one space more) or " : " (one space sign less)
// to get all : underneath each other
if (iPentagonCounter<=9)
print("Pentagon #"+iPentagonCounter+" : ");
else
print("Pentagon #"+iPentagonCounter+" : ");
print(p1);
print(p2);
print(p3);
print(p4);
print(p5);
println("");
iPentagonCounter++;
*/
if (showAsStandard) {
beginShape();
vertexPVector(p1);
vertexPVector(p2);
vertexPVector(p3);
vertexPVector(p4);
vertexPVector(p5);
endShape( CLOSE );
} else {
noFill();
stroke(GRAY);
strokeWeight(4);
// show shape
beginShape();
vertexPVector(p1);
vertexPVector(p2);
vertexPVector(p3);
vertexPVector(p4);
vertexPVector(p5);
endShape( CLOSE );
// show corners
fill(RED);
pointSpherePV(p1);
pointSpherePV(p2);
pointSpherePV(p3);
pointSpherePV(p4);
pointSpherePV(p5);
strokeWeight(1); // back to default
}//else
}//method
void quadArray(PVector[] a1) {
if (a1==null)
return;
if (a1.length==0)
return;
beginShape();
for (PVector pv : a1)
vertex(pv.x, pv.y, pv.z);
// vertex(a1[0].x, a1[0].y, a1[0].z);
endShape(CLOSE);
}
// colors ---
//
void fillAndStroke( color f, color s ) {
// set both colors at once (but different)
fill(f);
stroke(s);
}
void fillAndStroke( color c ) {
// set both at once (same color)
fill(c);
stroke(c);
}
void fillAndNoStroke(color f) {
// set fill color and switch stroke off
fill(f);
noStroke();
}
void strokeAndNoFill(color s) {
// set stroke color and switch fill off
noFill();
stroke(s);
}
// crosshair ---
void toogleCrosshair() {
crosshair = !crosshair;
}
void crosshairOn() {
crosshair=true;
}
void crosshairOff() {
crosshair=false;
}
boolean crosshairState() {
return crosshair;
}
//
} // class ThreeD
//