Skip to main content

Dodecahedron

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?

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.

original post

Related Topics >>

Comments

Infinite loading box...again...

No applet for me on WinXP 32 bit with latest JDK 6. FYI.

me too, and the source code

me too, and the source code link is broken(dead link)

Thanks!

Seems it is Java.net problem. All necessary sources are published but not available as usual. I'm investigating...