# Space Time (updated!)

My entry is called ‘Space Time‘. A 3D cube clock. The full source code that is readable is below the article.

Wow, it is amazing at what you can you do in 30 lines of JavaFX code or 3000 characters.   JFXStudio is running a contest and the theme has to do with “TIME”. Although I posted my entry very last minute, there will be other chances for you to enter. Please visit http://jfxstudio.wordpress.com/2009/08/31/jfxstudio-challenge-small-is-the-new-big/

My entry including the import statements are just at 30 lines with each line containing less than or equal to 100 characters.  Click on the image to launch the demo.

Instructions:

• Observe the cube rotating as each tick a second.
• Observe the Space Time Title’s Distant lighting effect as seconds go by
• Use mouse drag to rotate 3D cube
• ```import javafx.animation.*;import javafx.scene.*;import javafx.scene.paint.Color;import javafx.scene
.effect.*;import javafx.scene.text.*;import javafx.scene.shape.*;import javafx.scene.input.
MouseEvent;import javafx.util.Math;class P{var x:Number;var y:Number;var z:Number;var sX:Number;var
sY:Number;}class E{var a:Integer;var b:Integer;}var w:Number=800;var h:Number=600;var a:Number=30;
var e:Number=30;var vs:P[]=[];function av(x:Integer,y:Integer,z:Integer){insert P{x:x,y:y,z:z}into
vs;}av(-1,-1,-1);av(-1,-1,1);av(-1,1,-1);av(-1,1,1);av(1,-1,-1);av(1,-1,1);av(1,1,-1);av(1,1,1);var
es:E[]=[];function aE(a:Integer,b:Integer){insert E{a:a,b:b}into es;}aE(0,1);aE(0,2);aE(0,4);aE(1,3
);aE(1,5);aE(2,3);aE(2,6);aE(3,7);aE(4,5);aE(4,6);aE(5,7);aE(6,7);var ps:Circle[]=[];var ls:Line[]=
[];function mps(c:Boolean):Void{var th:Number=bind 0.017453*a;var ph=0.017453*e;var cT=Math.cos(th)
;var sT=Math.sin(th);var cP=Math.cos(ph);var sP=Math.sin(ph);var cTcP=cT*cP;var cTsP=cT*sP;var sTcP
=sT*cP;var sTsP=sT*sP;var sf=bind w/4;for(i in[0..sizeof vs-1]){var x0=vs[i].x;var y0=vs[i].y;var
z0=vs[i].z;var x1=cT*x0+sT*z0;var y1=-sTsP*x0+cP*y0+cTsP*z0;var z1=cTcP*z0-sTcP*x0-sP*y0;x1=x1*3/(
z1+4.5);y1=y1*3/(z1+4.5);vs[i].sX=x1;vs[i].sY=y1;if(c)insert Circle{centerX:bind w/2+sf*vs[i].sX+.5
,centerY: bind h/2-sf*vs[i].sY+.5,radius:2 fill:Color.BLUE}into ps;}if(c)for(e in es){insert Line{
startX:bind ps[e.a].centerX startY:bind ps[e.a].centerY endX:bind ps[e.b].centerX endY:bind ps[e.b]
.centerY strokeWidth:2,stroke:Color.BLUE}into ls;}}mps(true);var mx:Number;var my:Number;var g:
Rectangle=Rectangle{x:0,y:0 width:bind w,height:bind h fill:Color.BLACK onMousePressed:function(me:
MouseEvent):Void{mx=me.x;my=me.y;}onMouseDragged:function(me:MouseEvent):Void{var new_mx=me.x;a-=
new_mx-mx;var new_my=me.y;e+=new_my-my;mx=new_mx;my=new_my;mps(false);}}var ct:String=new java.util
.Date().toString();var tz:Integer=-125;var t=Group{content:[Text{effect:Lighting{light:javafx.scene
.effect.light.DistantLight{azimuth:bind tz elevation:40}surfaceScale:5} x:10 y:50 content:"Space "
"Time" fill:Color.RED font:Font{name:"Arial Bold" letterSpacing:0.20 size:50}},Text{x:10 y:80
content:bind ct fill:Color.BLUE font:Font{name:"Arial Bold" letterSpacing:0.20 size:20}}]}var bc=
Group{content:[Rectangle{x:10,y:bind h-85,arcHeight:5,arcWidth:5,width:bind w-30,height:30,fill:
opacity:.5 x:15,y:bind h-65,content:"by Carl Dea - carlfx.wordpress.com"fill:Color.WHITE font:Font{
name:"Arial Bold"letterSpacing:.20 size:20}}]}var scene:Scene=Scene{content:bind[g,ps,ls,t,bc]};var
anim=Timeline{keyFrames:[KeyFrame{time:1s action:function():Void{a-=1;mps(false);ct=new java.util.
Date().toString();if(tz>125){tz=-125;}tz+=2;}}]repeatCount:Timeline.INDEFINITE};anim.play();javafx.
stage.Stage{width:bind w with inverse height:bind h with inverse scene:scene}```

Enjoy!
Let me know what you think. 🙂

Here is the readable source code below:

```/**
* Main.fx
*
* for all the math.
* Created on Dec 20, 2009, 11:06:15 PM
*/

package bigsmall.part8;

import javafx.animation.*;
import javafx.scene.*;
import javafx.scene.paint.Color;
import javafx.scene.effect.*;
import javafx.scene.effect.light.DistantLight;
import javafx.scene.text.*;
import javafx.scene.shape.*;
import javafx.scene.input.MouseEvent;
import javafx.stage.*;
import java.util.Date;
import javafx.util.Math;

class Point3D {
var x: Number;
var y: Number;
var z: Number;
var screenX: Number;
var screenY: Number;
}

class Edge {
var a: Integer;
var b: Integer;
}
var width: Number = 800;
var height: Number = 600;
var azimuth: Number = 30;
var elevation: Number = 30;
var vertices: Point3D[] = [];

function addVertex(x: Integer, y: Integer, z: Integer) {
insert
Point3D {
x: x,
y: y,
z: z
}
into vertices;
}

var edges: Edge[] = [];

function addEdge(a: Integer, b: Integer) {
insert
Edge {
a: a,
b: b
}
into edges;
}

var points: Circle[] = [];
var lines: Line[] = [];

function movePoints(createFirstTime: Boolean): Void {
var theta: Number = bind 0.017453 * azimuth;
var phi = 0.017453 * elevation;
var cosTheta = Math.cos(theta);
var sinTheta = Math.sin(theta);
var cosPhi = Math.cos(phi);
var sinPhi = Math.sin(phi);
var cosThetaCosPhi = cosTheta * cosPhi;
var cosThetaSinPhi = cosTheta * sinPhi;
var sinThetaCosPhi = sinTheta * cosPhi;
var sinThetaSinPhi = sinTheta * sinPhi;
var scaleFactor = bind width / 4;
for (i in [0..sizeof vertices - 1]) {
var x0 = vertices[i].x;
var y0 = vertices[i].y;
var z0 = vertices[i].z;
var x1 = cosTheta * x0 + sinTheta * z0;
var y1 = -sinThetaSinPhi * x0 + cosPhi * y0 + cosThetaSinPhi * z0;
var z1 = cosThetaCosPhi * z0 - sinThetaCosPhi * x0 - sinPhi * y0;
x1 = x1 * 3 / (z1 + 4.5);
y1 = y1 * 3 / (z1 + 4.5);
vertices[i].screenX = x1;
vertices[i].screenY = y1;
if (createFirstTime) {
insert
Circle {
centerX: bind width / 2 + scaleFactor * vertices[i].screenX + 0.5,
centerY: bind height / 2 - scaleFactor * vertices[i].screenY + 0.5,
fill: Color.BLUE
}
into points;
}
}

if (createFirstTime) {
for (edge in edges) {
insert
Line {
startX: bind points[edge.a].centerX
startY: bind points[edge.a].centerY
endX: bind points[edge.b].centerX
endY: bind points[edge.b].centerY
strokeWidth: 2,
stroke: Color.BLUE
}
into lines;
}
}
}

// create the first time; draw cube.
movePoints(true);

var mouseX: Number;
var mouseY: Number;

// Space region that changes the azimuth and recalculates the cube
var galaxy: Rectangle = Rectangle {
x: 0,
y: 0
width: bind width,
height: bind height
fill: Color.BLACK
onMousePressed: function (me: MouseEvent): Void {
mouseX = me.x;
mouseY = me.y;
}
onMouseDragged: function (me: MouseEvent): Void {
var new_mx = me.x;
azimuth -= new_mx - mouseX;
var new_my = me.y;
elevation += new_my - mouseY;
mouseX = new_mx;
mouseY = new_my;
movePoints(false);
}
} // galaxy

var currentTime: String = new Date().toString();
var initialAzimuth: Integer = -125;

// Title with current time seconds.
var titleDisplay = Group {
content: [
Text {
effect: Lighting {
light: DistantLight {
azimuth: bind initialAzimuth
elevation: 40
}
surfaceScale: 5
}
x: 10
y: 50
content: "Space Time"
fill: Color.RED
font: Font {
name: "Arial Bold"
letterSpacing: 0.20
size: 50
}
},
Text {
x: 10
y: 80
content: bind currentTime
fill: Color.BLUE
font: Font {
name: "Arial Bold"
letterSpacing: 0.20
size: 20
}
}
]
}; // titleDisplay Group

// This is the bottom display credits
var byCarl = Group {
content: [
Rectangle {
x: 10,
y: bind height - 85,
arcHeight: 5,
arcWidth: 5,
width: bind width - 30,
height: 30,
fill: Color.RED,
opacity: .5
},
Text {
offsetX: 10,
offsetY: 10,
color: Color.BLACK,
}
opacity: .5
x: 15,
y: bind height - 65,
content: "by Carl Dea - carlfx.wordpress.com"
fill: Color.WHITE
font: Font {
name: "Arial Bold"
letterSpacing: .20
size: 20
}
}
] // byCarl contents Group
}; // by Carl

var scene: Scene = Scene {
content: bind [
galaxy,
points,
lines,
titleDisplay,
byCarl]
};

// this is the ticking motion of the cube.
var anim = Timeline {
keyFrames: [
KeyFrame {
time: 1s
action: function (): Void {
azimuth -= 1;
movePoints(false);
currentTime = new Date().toString();
if (initialAzimuth &gt; 125) {
initialAzimuth = -125;
}
initialAzimuth += 2;
}
}
] // keyFrames
repeatCount: Timeline.INDEFINITE
}; // animation

anim.play();

Stage {
title: "Space Time"
width: bind width with inverse
height: bind height with inverse
scene: scene
}

```

## 10 thoughts on “30 Lines of JavaFX Coding Challenge Theme – Time”

1. Matthew

Looks good. Any chance you can post the formatted source code?

2. carldea Post author

Mathew,

Sure. By coincidence I was going to not enter the contest and play with 3D Math and create a blog entry for my game programming habit. So, I thought the code could be short enough to enter the contest. But, if you don’t mind I will create similar source code and my intended blog entry to help others learn about 3D programming (so, stay tuned during the week)(It will be simple without all the bells and whistles). My goal is to re-learn my old math skills. I plan to play with graphics in general (texture mapping, 3D surfaces, animation, collision, etc).

Carl

3. Matthew

Sure – look forward to reading the future posts

4. maksim

Looks great!!! I am a novice in JFX and am trying to study it. Your blog helps me on my way. Thank you!

5. Kishore

Great work, It runs so smooth.

6. Binky

Can you explain the use of the number 3 and the 4.5 in line 106 and 107. I was trying to expand the box to actual pixels and until I changed both numbers by a factor of 100 the display was quite strange.

7. Binky

Also the constant of 0.017453 on line 88 and 89. Thanks

8. carldea Post author

Brinkley,

line 88 is supposed to be: ` var theta:Number = Math.PI * azimuth / 180.0;`
line 89 is supposed to be: `var phi = Math.PI * elevation / 180.0;`

Taking Math.PI / 180 will give you 0.017453
My attempt to squish the code as small as possible.

9. carldea Post author

Binky,
In the processes of making the the code smaller I lost the original code. So, I was trying to make the code readable by getting it back to what it was. So, I missed those lines you mentioned. Yes I hope my explanation below will help.

`var eyeToNearPlane= 3; // distance from eye to near plane`
`var nearToCenterOfObj:Number = 1.5; // distance from near plane to center of object`

`x1 = x1*eyeToNearPlane/(z1+eyeToNearPlane+nearToCenterOfObj);`
`y1 = y1*eyeToNearPlane/(z1+eyeToNearPlane+nearToCenterOfObj);`

My silly attempt to squish the code.
Thanks!
-Carl