Posted by

malenkov on October 27, 2009 at 6:44 AM PDT

I've made the decision to participate in the JFXstudio Challenge competition. The subject of the competition is **Five**. Therefore, I decided to replace the squares with the pentagons in one of my applications. Do you remeber the sample that rotates the cube?

I've made the decision to participate in the JFXstudio Challenge competition. The subject of the competition is **Five**. Therefore, I decided to replace the squares with the pentagons in one of my applications. Do you remeber the sample that rotates the cube?

There is a limitation that is set for the competition: you may have only 30 lines or 3000 characters of code to do something cool. However, readability is still important to me, and I think, it should not be sacrificed. Therefore, my rotating dodecahedron sample consists of 3000 symbols and 130 lines. Consider the **script** now.

`class Point {`

var x: Number;

var y: Number;

var z: Number;

function rotateX(cos,sin) {

def tmp = cos*y - sin*z;

z = cos*z + sin*y;

y = tmp

}

function rotateY(cos,sin) {

def tmp = cos*x + sin*z;

z = cos*z - sin*x;

x = tmp

}

function rotateZ(cos,sin) {

def tmp = cos*x - sin*y;

y = cos*y + sin*x;

x = tmp

}

}

The `Point`

class contains the coordinates of a point in the three-dimensional space, and it provides methods to rotate the point around the coordinate basis for each axis. A class is exactly the same as the `Point`

class in the rotating cube sample.

`class Face extends Polygon {`

override var stroke = RED;

override var strokeLineJoin = ROUND;

override var strokeWidth = 2;

var ps: Point[];

function update() {

var z: Number;

points = for (p in ps) {

z += p.z;

[p.x,p.y]

}

visible = z > 0

}

}

The `Face`

class is the polygon used to define a dodecahedron face. I do not use binding here to improve performance and to minimize the number of lines. When the update method is called, the sequence of the polygon points is changed and the required faces are become visible.

`def g = 1 + Math.sqrt(5);`

def r = 100;

def a = r*2/g;

def b = r*g/2;

def ps = [

Point { x:r y: r z: r }

Point { x:r y: r z:-r }

Point { x:r y:-r z: r }

Point { x:r y:-r z:-r }

Point { x:0 y: a z: b }

Point { x:0 y: a z:-b }

Point { x:a y: b z: 0 }

Point { x:a y:-b z: 0 }

Point { x:b y: 0 z: a }

Point { x:b y: 0 z:-a }

];

def qs = for (p in ps) Point { x:bind-p.x y:bind-p.y z:bind-p.z }

Wikipedia describes the vertices of a dodecahedron in detail. I'd like to mention that each vertice of a dodecahedron has a paired vertice that is symmetric relative to the coordinate basis. That's why I used two sequences of points. The `ps`

sequence is initialized and rotated by the application. The `qs`

sequence contains the symmetric vertices which are initialized and changed automatically by using the binding mechanism.

`def fs = [`

Face { ps:[qs[1],qs[6],ps[7],ps[2],qs[5]] }

Face { ps:[qs[0],qs[6],ps[7],ps[3],qs[4]] }

Face { ps:[qs[0],qs[6],qs[1],qs[9],qs[8]] }

Face { ps:[ps[2],ps[7],ps[3],ps[9],ps[8]] }

Face { ps:[qs[1],qs[5],ps[4],qs[3],qs[9]] }

Face { ps:[qs[0],qs[4],ps[5],qs[2],qs[8]] }

Face { ps:[ps[2],ps[8],ps[0],ps[4],qs[5]] }

Face { ps:[ps[3],ps[9],ps[1],ps[5],qs[4]] }

Face { ps:[qs[8],qs[9],qs[3],qs[7],qs[2]] }

Face { ps:[ps[8],ps[9],ps[1],ps[6],ps[0]] }

Face { ps:[ps[4],ps[0],ps[6],qs[7],qs[3]] }

Face { ps:[ps[5],ps[1],ps[6],qs[7],qs[2]] }

];

The dodecahedron surface consists of 12 faces. I wanted to add visual identification to each vertice, however, I couldn't, because of the competition's limitation that limits the amount of code lines.

`var x = 0.002;`

var y = 0.006;

The code fragment above defines the angles by which rotation occurs around the `x`

and `y`

axes accordingly.

`Stage {`

title: "Dodecahedron (JavaFX sample)"

style: TRANSPARENT

resizable: false

scene: Scene {

fill: null

width: 6*r

height: 6*r

content: Group {

translateX: 3*r

translateY: 3*r

content: fs

cursor: HAND

blocksMouse: true

onMouseDragged: function(event) {

x = if (-5 y = if (-5 }

}

}

}

The code that declares the scene is very simple. A transparent window is created and the group of the dodecahedron faces is located in the center of the window. Basically, the code doesn't differ much from a rotating cube sample.

`Timeline {`

repeatCount: Timeline.INDEFINITE

keyFrames: KeyFrame {

time: 40ms

action: function() {

if (x != 0) {

def cos = Math.cos(x);

def sin = Math.sin(x);

for (p in ps) p.rotateX(cos,sin)

}

if (y != 0) {

def cos = Math.cos(y);

def sin = Math.sin(y);

for (p in ps) p.rotateY(cos,sin)

}

for (f in fs) f.update()

}

}

}.playFromStart()

Each 40 milliseconds the animation timeline rotates a half of a dodecahedron points along the `x`

axis and then along the `y`

axis. After the rotation occurred all the dodecahedron faces are updated.