/* Title: Drawing Lines Between Points In A Circle Author: Samuel Wan Date: 9/28/03 Description: Moving on to polygon classes. Man, I can't believe how much java I'm starting to remember */ SegmentedTorus hourTorus, minuteTorus, secondTorus; // Mouse rotation variables float radPerPixelX, radPerPixelY, rotateYIncr, rotateXIncr, curRotateY, curRotateX, mouseDx, mouseDy; // Rotation interpolation variables float currentHourRadian = 0; float currentMinuteRadian = 0; float currentSecondRadian = 0; float targetHourRadian = 0; float targetMinuteRadian = 0; float targetSecondRadian = 0; final float radiansPerMinute = TWO_PI / 60; final float radiansPerHour = TWO_PI / 12; boolean pressed = false; // The setup function sets up your sketch void setup() { size(400, 380); // movie size = 400 width, 400 height radPerPixelX = TWO_PI / width; radPerPixelY = TWO_PI / height; curRotateY = curRotateX = 0; // radius, radiusDepth, segmentHeight, segmentCount, segmentSpacePercent, geotype hourTorus = new SegmentedTorus(140, 40, 10, 12, 0.9, SegmentedTorus.TETRAHEDRON_GEOMETRY); minuteTorus = new SegmentedTorus(100, 20, 10, 60, 0.4, SegmentedTorus.TETRAHEDRON_GEOMETRY); secondTorus = new SegmentedTorus(80, 20, 5, 60, 0.6, SegmentedTorus.TETRAHEDRON_GEOMETRY); } void loop() { background(#456174); translate(width/2, height/2); // Rotation of base transform matrix based on mouse cursor movement if pressed if(mousePressed) { mouseDx = mouseX - pmouseX; mouseDy = mouseY - pmouseY; curRotateY += mouseDx * radPerPixelX; curRotateX += mouseDy * radPerPixelY; } else { curRotateY *= 0.9; // interpolate back to original position curRotateX *= 0.9; } // Calculate target radians for each arm of the clock if(pressed) { targetHourRadian = targetMinuteRadian = targetSecondRadian = 0; } else { targetHourRadian = radiansPerHour * hour(); targetMinuteRadian = radiansPerMinute * minute(); targetSecondRadian = radiansPerMinute * second(); } rotateY(curRotateY); rotateX(curRotateX); // Prepare to draw fill(180, 80); //noStroke(); stroke(255, 30); push(); // Draw hours currentHourRadian += (targetHourRadian - currentHourRadian) * 0.1; // interpolation rotateZ(-HALF_PI + currentHourRadian); push(); rotateX(currentHourRadian); hourTorus.render(); pop(); pop(); push(); currentMinuteRadian += (targetMinuteRadian - currentMinuteRadian) * 0.1; rotateZ(-HALF_PI + currentMinuteRadian); push(); // Rotate and draw minutes rotateX(currentMinuteRadian); minuteTorus.render(); pop(); pop(); push(); currentSecondRadian += (targetSecondRadian - currentSecondRadian) * 0.1; rotateZ(-HALF_PI + currentSecondRadian); push(); rotateX(currentSecondRadian); secondTorus.render(); pop(); pop(); } void keyPressed() { if(!pressed) { pressed = true; int GEOTYPE = SegmentedTorus.BOX_GEOMETRY; hourTorus.setGeometry(GEOTYPE); minuteTorus.setGeometry(GEOTYPE); secondTorus.setGeometry(GEOTYPE); } } void keyReleased() { if(pressed) { pressed = false; int GEOTYPE = SegmentedTorus.TETRAHEDRON_GEOMETRY; hourTorus.setGeometry(GEOTYPE); minuteTorus.setGeometry(GEOTYPE); secondTorus.setGeometry(GEOTYPE); } } class SegmentedTorus { int radius, radiusDepth, segmentHeight, segmentCount; float segmentSpacePercent; Solid segmentList[]; static final int TETRAHEDRON_GEOMETRY = 0; static final int BOX_GEOMETRY = 1; SegmentedTorus(int radius, int radiusDepth, int segmentHeight, int segmentCount, float segmentSpacePercent, int GEOTYPE) { this.radius = radius; this.radiusDepth = radiusDepth; this.segmentHeight = segmentHeight; this.segmentCount = segmentCount; this.segmentSpacePercent = segmentSpacePercent; setGeometry(GEOTYPE); } void setGeometry(int GEOTYPE) { if(GEOTYPE == TETRAHEDRON_GEOMETRY) { generateTetrahedrons(); } else if(GEOTYPE == BOX_GEOMETRY) { generateBoxes(); } } void generateBoxes() { float slice = TWO_PI / segmentCount; // precalculate slices of a circle in radian units float halfslice = slice / 2; float halfDepth = radiusDepth / 2; float sliceSpace = slice * segmentSpacePercent / 2; segmentList = new Solid[segmentCount]; for(int i = 0; i < segmentCount; i++) { float beginRad = i * slice - halfslice + sliceSpace; // establish begin and end radians float endRad = i * slice + halfslice - sliceSpace; // The four bottom two-dimensional anchors for a basic polygon Point bottom_a = new Point(cos(beginRad) * radius, sin(beginRad) * radius, -halfDepth); Point bottom_b = new Point(cos(endRad) * radius, sin(endRad) * radius, -halfDepth); Point bottom_c = new Point(cos(endRad) * (radius - radiusDepth), sin(endRad) * (radius - radiusDepth), -halfDepth); Point bottom_d = new Point(cos(beginRad) * (radius - radiusDepth), sin(beginRad) * (radius - radiusDepth), -halfDepth); // Four top anchors for the top polygon Point top_a = new Point(bottom_a, 0, 0, radiusDepth); Point top_b = new Point(bottom_b, 0, 0, radiusDepth); Point top_c = new Point(bottom_c, 0, 0, radiusDepth); Point top_d = new Point(bottom_d, 0, 0, radiusDepth); // Polygons for top, bottom, front, back, left, right Polygon top = new Polygon(new Point[]{top_a, top_b, top_c, top_d}); Polygon bottom = new Polygon(new Point[]{bottom_a, bottom_b, bottom_c, bottom_d}); Polygon front = new Polygon(new Point[]{bottom_a, bottom_b, top_b, top_a}); Polygon back = new Polygon(new Point[]{bottom_c, bottom_d, top_d, top_c}); Polygon left = new Polygon(new Point[]{top_a, top_d, bottom_d, bottom_a}); Polygon right = new Polygon(new Point[]{top_b, top_c, bottom_c, bottom_b}); segmentList[i] = new Solid(new Polygon[]{top, bottom, front, back, left, right}); } } void generateTetrahedrons() { float slice = TWO_PI / segmentCount; // precalculate slices of a circle in radian units float halfslice = slice / 2; float halfDepth = segmentHeight / 2; float sliceSpace = slice * segmentSpacePercent / 2; segmentList = new Solid[segmentCount]; for(int i = 0; i < segmentCount; i++) { float beginRad = i * slice - halfslice + sliceSpace; // establish begin and end radians float endRad = i * slice + halfslice - sliceSpace; // The four front anchor points and the back central Point front_a = new Point(cos(beginRad) * radius, sin(beginRad) * radius, -halfDepth); Point front_b = new Point(cos(endRad) * radius, sin(endRad) * radius, -halfDepth); Point front_d = new Point(cos(beginRad) * radius, sin(beginRad) * radius, halfDepth); Point front_c = new Point(cos(endRad) * radius, sin(endRad) * radius, halfDepth); Point back_center = new Point(cos(i * slice) * (radius - radiusDepth), sin(i * slice) * (radius - radiusDepth), 0); // Polygons for top, bottom, front, back, left, right Polygon top = new Polygon(new Point[]{front_a, front_b, back_center}); Polygon bottom = new Polygon(new Point[]{front_c, front_d, back_center}); Polygon front = new Polygon(new Point[]{front_a, front_b, front_c, front_d}); Polygon left = new Polygon(new Point[]{front_a, back_center, front_d}); Polygon right = new Polygon(new Point[]{front_b, back_center, front_c}); segmentList[i] = new Solid(new Polygon[]{top, bottom, front, left, right}); } } void render() { for(int i = 0; i < segmentList.length; i++) { if(i > 0) { fill(255, 50); } else { fill(255, 153, 0, 255); } segmentList[i].drawFaces(POLYGON); } } } class Solid { Polygon polygons[]; Solid(Polygon polygons[]) { this.polygons = polygons; } void drawFaces(int shapeMode) { for(int i = 0; i < polygons.length; i++) { polygons[i].drawPolygon(shapeMode); } } void drawFaces() { // override with default argument if none provided drawFaces(POLYGON); } } class Polygon { Point vertices[]; Polygon(Point vertices[]) { this.vertices = vertices; } void drawPolygon(int shapeMode) { // override with default argument if none provided beginShape(shapeMode); for(int i = 0; i < vertices.length; i++) { vertices[i].doVertex(); } endShape(); } void drawPolygon() { drawPolygon(POLYGON); } } class Point { public float x, y, z; Point(float x, float y, float z) { // regular constructor this.x = x; this.y = y; this.z = z; } Point(Point p, float dx, float dy, float dz) { // translate from another point this.x = p.x + dx; this.y = p.y + dy; this.z = p.z + dz; } void doVertex() { vertex(x, y, z); } }