Uploaded image for project: 'JDK'
  1. JDK
  2. JDK-8117599

FX 8 3D : Hierarchical RotateTransitions result in uneven rotation

XMLWordPrintable

    • Icon: Bug Bug
    • Resolution: Not an Issue
    • Icon: P4 P4
    • None
    • 8
    • javafx
    • JDK 8.0-b94, Linux, Mac, Windows

      Rotation of each cylinder is centric. Rotation of the cube (2x2x2) is centric, also. If both rotations are active the entire model 'jumps' around the center point.

      package jiraissue;

      import javafx.animation.Interpolator;
      import javafx.animation.RotateTransition;
      import javafx.animation.Timeline;
      import javafx.application.Application;
      import javafx.event.ActionEvent;
      import javafx.beans.value.ChangeListener;
      import javafx.beans.value.ObservableValue;
      import javafx.collections.ObservableList;
      import javafx.event.EventHandler;
      import javafx.geometry.BoundingBox;
      import javafx.scene.AmbientLight;
      import javafx.scene.Group;
      import javafx.scene.Node;
      import javafx.scene.PerspectiveCamera;
      import javafx.scene.PointLight;
      import javafx.scene.Scene;
      import javafx.scene.SubScene;
      import javafx.scene.control.Button;
      import javafx.scene.control.CheckBox;
      import javafx.scene.layout.BorderPane;
      import javafx.scene.layout.HBox;
      import javafx.scene.paint.Color;
      import javafx.scene.shape.Cylinder;
      import javafx.scene.transform.Affine;
      import javafx.scene.transform.Rotate;
      import javafx.scene.transform.Translate;

      import javafx.stage.Stage;
      import javafx.stage.WindowEvent;

      import javafx.util.Duration;

      public class HierarchicalRotateTransitions extends Application {

          public static void main(String[] args) {
              launch(args);
          }
          
          private Affine viewingRotate = new Affine();
          private Translate viewingTranslate = new Translate();
          
          private RotateTransition cylCubeRotTransition = null;
          private RotateTransition[] cylRotTransAll = null;

          @Override public void start(Stage stage) {
              
              // SubScene & Root

              final Group subSceneRoot = new Group();

              final SubScene subScene = new SubScene(subSceneRoot, 800, 800, true, false);
              subScene.setFill(Color.YELLOWGREEN);

              // Viewing : Camera & Light
              
              // SubScene's camera
              final PerspectiveCamera perspectiveCamera = new PerspectiveCamera(true);
              perspectiveCamera.setFarClip(25);
              perspectiveCamera.setNearClip(0.1);
              perspectiveCamera.setFieldOfView(44);
              
              subScene.setCamera(perspectiveCamera);
             
              // SubScene's lights
              final PointLight pointLight = new PointLight(Color.WHITE);
              pointLight.setTranslateZ(-20000);
              
              final AmbientLight ambLight = new AmbientLight(Color.color(0.3, 0.3, 0.3));
                
              // Viewing group: camera and headlight
              final Group viewingGroup = new Group(perspectiveCamera, pointLight);
              viewingGroup.getTransforms().setAll(viewingRotate, viewingTranslate);
              
              // View from top (+Y)
              viewingRotate.setToTransform(new Rotate(-90, Rotate.X_AXIS));
              viewingTranslate.setZ(-8);
              
              //
              // Group hierarchy of the cube
              //
              
              // Centers the entire cube at (0,0,0)
              final Group cylCubeCenterGroup = new Group();
              
              // Cube rotation target
              final Group cylCubeRotGroup = new Group(cylCubeCenterGroup);

              cylCubeRotTransition = new RotateTransition();
              cylCubeRotTransition.setNode(cylCubeRotGroup);
              cylCubeRotTransition.setAxis(Rotate.Y_AXIS);
              cylCubeRotTransition.setCycleCount(Timeline.INDEFINITE);
              cylCubeRotTransition.setAutoReverse(false);
              cylCubeRotTransition.setInterpolator(Interpolator.LINEAR);
              cylCubeRotTransition.setByAngle(360);
              cylCubeRotTransition.setDuration(Duration.millis(10000));
              
              // Add all to SubScene
              subSceneRoot.getChildren().addAll(cylCubeRotGroup, viewingGroup, ambLight);
              
              final int xDist = 2;
              final int yDist = 2;
              final int zDist = 2;
              
              long delay = 4;
              final long delayIncr = 4;
              
              Group cylCenterGroup = null; // center Tux at (0,y,0)
              Group cylRotationGroup = null; // target for rotate transition
              Group cylPositionGroup = null; // position Tux within the cube
              
              // Cube's size
              final int dim = 2;
              
              final int numTux = dim*dim*dim;
              final double maxTux = 10*10*10;
                      
              int n = 0;
              
              float xTrans = 0;
              float yTrans = 0;
              float zTrans = 0;
              
              cylRotTransAll = new RotateTransition[numTux];
              
              final ObservableList<Node> children = cylCubeCenterGroup.getChildren();
              
              for (int i=0; i < dim; i++) { // z axis
                  for (int j=0; j < dim; j++) { // y axis
                      for (int k=0; k < dim; k++) { // x axis
                          
                          Cylinder cylinder = new Cylinder(0.25, 1.5);
                          
                          // group hierarchy from bottom to top
                          // 1.
                          cylCenterGroup = new Group(cylinder);
                          cylCenterGroup.setRotationAxis(Rotate.X_AXIS);
                          cylCenterGroup.setRotate(90);
                          
                          // 2.
                          cylRotationGroup = new Group(cylCenterGroup);
                                                                         
                          RotateTransition rotateTransition = new RotateTransition();
                          rotateTransition.setNode(cylRotationGroup);
                          rotateTransition.setAxis(Rotate.Y_AXIS);
                          rotateTransition.setDelay(Duration.millis(delay));
                          rotateTransition.setDuration(Duration.millis(5000 - 2*n*(maxTux/numTux)));
                          rotateTransition.setCycleCount(Timeline.INDEFINITE);
                          rotateTransition.setAutoReverse(false);
                          rotateTransition.setInterpolator(Interpolator.LINEAR);
                          rotateTransition.setByAngle(360);
                          cylRotTransAll[n] = rotateTransition;
              
                          // 3.
                          cylPositionGroup = new Group(cylRotationGroup);
                          cylPositionGroup.setTranslateX(xTrans);
                          cylPositionGroup.setTranslateY(yTrans);
                          cylPositionGroup.setTranslateZ(zTrans);
                          children.add(cylPositionGroup);
                          
                          xTrans += xDist;
                          delay = delayIncr * n;
                          n++;
                      } // x axis
                      
                      xTrans = 0;
                      yTrans += yDist;
                  } // y axis
                  
                  yTrans = 0;
                  zTrans += zDist;
              } // z axis cylCubeCenterTranslate
              
              final BoundingBox cylCubeBinL = (BoundingBox)cylCubeCenterGroup.getBoundsInLocal();
      System.out.println("cylCubeBinL " + cylCubeBinL);
              
              cylCubeCenterGroup.setTranslateX(-(cylCubeBinL.getMinX()+cylCubeBinL.getMaxX())/2.0);
              cylCubeCenterGroup.setTranslateY(-(cylCubeBinL.getMinY()+cylCubeBinL.getMaxY())/2.0);
              cylCubeCenterGroup.setTranslateZ(-(cylCubeBinL.getMinZ()+cylCubeBinL.getMaxZ())/2.0);
              
              final BoundingBox cylCubeBinP = (BoundingBox)cylCubeCenterGroup.getBoundsInParent();
      System.out.println("cylCubeBinP " + cylCubeBinP);

              // Scene

              final CheckBox cylRotCheck = new CheckBox("Cylinders play/pause");
              cylRotCheck.selectedProperty().addListener(new ChangeListener<Boolean>() {
                  @Override
                  public void changed(ObservableValue<? extends Boolean> ov, Boolean old_val, Boolean new_val) {
                      playPauseCylRotation(new_val);
                  }
              });
              final Button cylRotStopButton = new Button("stop");
              cylRotStopButton.setOnAction(new EventHandler<ActionEvent>() {
                  @Override public void handle(final ActionEvent e) {
                      cylRotCheck.setSelected(false);
                      for (RotateTransition rot : cylRotTransAll) {
                          rot.stop();
                          rot.getNode().setRotate(0);
                      }
                  }
              });

              final CheckBox cubeRotCheck = new CheckBox("Cube play/pause");
              cubeRotCheck.selectedProperty().addListener(new ChangeListener<Boolean>() {
                  @Override
                  public void changed(ObservableValue<? extends Boolean> ov, Boolean old_val, Boolean new_val) {
                      playPauseCubeRotation(new_val);
                  }
              });
              final Button cubeRotStopButton = new Button("stop");
              cubeRotStopButton.setOnAction(new EventHandler<ActionEvent>() {
                  @Override public void handle(final ActionEvent e) {
                      cubeRotCheck.setSelected(false);
                      cylCubeRotTransition.stop();
                      cylCubeRotTransition.getNode().setRotate(0);
                  }
              });
              
              final HBox hBox = new HBox();
              hBox.setSpacing(20);
              hBox.getChildren().addAll(cylRotCheck, cylRotStopButton, cubeRotCheck, cubeRotStopButton);
             
              final BorderPane borderPane = new BorderPane();
              borderPane.setMinHeight(0);
              borderPane.setMinWidth(0);
              borderPane.setCenter(subScene);
              borderPane.setBottom(hBox);
                 
              final Scene scene = new Scene(borderPane, 850, 850, true);
             
              stage.setOnCloseRequest(new EventHandler<WindowEvent>() {
                  @Override public void handle(WindowEvent event) {
                      System.exit(0);
                  }
              });
              stage.setScene(scene);
              stage.setTitle("HierarchicalRotateTransitions");
              
              stage.show();
          }
          
          private void playPauseCylRotation(boolean play) {
              if (play) {
                  for (RotateTransition rot : cylRotTransAll) {
                      rot.play();
                  }
              }
              else {
                  for (RotateTransition rot : cylRotTransAll) {
                      rot.pause();
                  }
              }
          }
          
          private void playPauseCubeRotation(boolean play) {
              if (play) {
                  cylCubeRotTransition.play();
              }
              else {
                  cylCubeRotTransition.pause();
              }
          }
      }

            psafrata Pavel Ĺ afrata
            alammersdjfx August Lammersdorf (Inactive)
            Votes:
            1 Vote for this issue
            Watchers:
            4 Start watching this issue

              Created:
              Updated:
              Resolved:
              Imported: