import javafx.animation.KeyFrame;
import javafx.animation.KeyValue;
import javafx.animation.TimelineBuilder;
import javafx.application.Application;
import javafx.beans.property.DoubleProperty;
import javafx.beans.property.SimpleDoubleProperty;
import javafx.geometry.Point3D;
import javafx.scene.GroupBuilder;
import javafx.scene.Parent;
import javafx.scene.PerspectiveCameraBuilder;
import javafx.scene.Scene;
import javafx.scene.SceneBuilder;
import javafx.scene.paint.Color;
import javafx.scene.shape.Polygon;
import javafx.scene.shape.PolygonBuilder;
import javafx.scene.transform.Rotate;
import javafx.scene.transform.RotateBuilder;
import javafx.stage.Stage;
import javafx.util.Duration;
/**
* @reference: http://sett.ociweb.com/sett/settMay2012.html
*/
public class Tetrahedron extends Application {
public static final double DIHEDRAL_ANGLE = 70.53;
public static final double INRADIUS = 50 * Math.tan(DIHEDRAL_ANGLE / 2
/ 180 * Math.PI);
private DoubleProperty side2Angle = new SimpleDoubleProperty();
private DoubleProperty side3Angle = new SimpleDoubleProperty();
private DoubleProperty side4Angle = new SimpleDoubleProperty();
private DoubleProperty rootAngle = new SimpleDoubleProperty();
public static void main(String[] args) {
launch(args);
}
@Override
public void start(Stage stage) {
stage.setTitle("Tetrahedron");
stage.setScene(makeScene());
stage.show();
animate();
}
private Scene makeScene() {
return SceneBuilder.create().width(500).height(500).root(createRoot())
.camera(PerspectiveCameraBuilder.create().build())
.depthBuffer(true).build();
}
private Parent createRoot() {
double x[] = new double[3];
double y[] = new double[3];
double angle = 2 * Math.PI / 3;
for (int i = 0; i < 3; i++) {
x[i] = 100 * Math.cos(i * angle);
y[i] = 100 * Math.sin(i * angle);
}
final Polygon side1 = PolygonBuilder.create()
.points(x[0], y[0], x[1], y[1], x[2], y[2]).fill(Color.RED)
.opacity(0.9).build();
final Rotate side2Rotate = RotateBuilder.create().pivotX(x[0])
.pivotY(y[0]).pivotZ(0)
.axis(new Point3D(x[0] - x[1], y[0] - y[1], 0)).build();
side2Rotate.angleProperty().bind(side2Angle);
final Polygon side2 = PolygonBuilder.create()
.points(x[0], y[0], x[1], y[1], x[2], y[2]).fill(Color.GREEN)
.opacity(0.9).transforms(side2Rotate).build();
final Rotate side3Rotate = RotateBuilder.create().pivotX(x[1])
.pivotY(y[1]).pivotZ(0)
.axis(new Point3D(x[1] - x[2], y[1] - y[2], 0)).build();
side3Rotate.angleProperty().bind(side3Angle);
final Polygon side3 = PolygonBuilder.create()
.points(x[0], y[0], x[1], y[1], x[2], y[2]).fill(Color.BLUE)
.opacity(0.9).transforms(side3Rotate).build();
final Rotate side4Rotate = RotateBuilder.create().pivotX(x[2])
.pivotY(y[2]).pivotZ(0)
.axis(new Point3D(x[2] - x[0], y[2] - y[0], 0)).build();
side4Rotate.angleProperty().bind(side4Angle);
final Polygon side4 = PolygonBuilder.create()
.points(x[0], y[0], x[1], y[1], x[2], y[2]).fill(Color.CYAN)
.opacity(0.9).transforms(side4Rotate).build();
final Rotate rootRotate = RotateBuilder.create().pivotX(0).pivotY(0)
.pivotZ(-INRADIUS).axis(new Point3D(1, 1, 1)).build();
rootRotate.angleProperty().bind(rootAngle);
return GroupBuilder.create().children(side1, side2, side3, side4)
.translateX(250).translateY(250).translateZ(-INRADIUS)
.transforms(rootRotate).build();
}
private void animate() {
TimelineBuilder
.create()
.keyFrames(
new KeyFrame(Duration.seconds(0), new KeyValue(
side2Angle, 0), new KeyValue(side3Angle, 0),
new KeyValue(side4Angle, 0), new KeyValue(
rootAngle, -60)),
new KeyFrame(Duration.seconds(2), new KeyValue(
side2Angle, 0), new KeyValue(side3Angle, 0),
new KeyValue(side4Angle, DIHEDRAL_ANGLE),
new KeyValue(rootAngle, 60)),
new KeyFrame(Duration.seconds(4), new KeyValue(
side2Angle, 0), new KeyValue(side3Angle,
DIHEDRAL_ANGLE), new KeyValue(side4Angle,
DIHEDRAL_ANGLE), new KeyValue(rootAngle, 180)),
new KeyFrame(Duration.seconds(6), new KeyValue(
side2Angle, DIHEDRAL_ANGLE), new KeyValue(
side3Angle, DIHEDRAL_ANGLE), new KeyValue(
side4Angle, DIHEDRAL_ANGLE), new KeyValue(
rootAngle, 300))).build().play();
}
}