private List<Point2D> maxScale(List<Point2D> points, double factor) { List<Point2D> scaledList = new ArrayList<>(); if (!drawPath.getElements().isEmpty()) { // scale and center Bounds b0 = drawPath.getBoundsInParent(); if (b0.getWidth() > 0 && b0.getHeight() > 0) { final double w = drawPane.getWidth() - 2 * factor * MARGIN; final double h = drawPane.getHeight() - 2 * factor * MARGIN; final double scale = Math.min(w / b0.getWidth(), h / b0.getHeight()); affine = new Affine(new Scale(scale, scale, factor * MARGIN, factor * MARGIN)); affine.append(new Translate(factor * MARGIN - b0.getMinX() + (w - scale * b0.getWidth()) / 2d / scale, factor * MARGIN - b0.getMinY() + (h - scale * b0.getHeight()) / 2d / scale)); for (Point2D p : points) { scaledList.add(affine.transform(p)); } } } return scaledList; }
public void updateArrow(String face, boolean hover){ boolean bFaceArrow = !(face.startsWith("X") || face.startsWith("Y") || face.startsWith("Z")); MeshView arrow = bFaceArrow ? faceArrow : axisArrow; if (hover && onRotation.get()) { return; } arrow.getTransforms().clear(); if (hover) { double d0 = arrow.getBoundsInParent().getHeight() / 2d; Affine aff = Utils.getAffine(dimCube, d0, bFaceArrow, face); arrow.getTransforms().setAll(aff); arrow.setMaterial(Utils.getMaterial(face)); if (previewFace.get().isEmpty()) { previewFace.set(face); onPreview.set(true); rotateFace(face, true, false); } } else if (previewFace.get().equals(face)) { rotateFace(Utils.reverseRotation(face), true, true); } else if (previewFace.get().equals("V")) { previewFace.set(""); onPreview.set(false); } }
public StageInfo( final int w, final int h, final Tile[] data ) throws CorruptDataException { this.w = w; this.h = h; this.data = data; if (data.length != w * h) throw new CorruptDataException("Incorrect number of tiles in stage"); // set the camera angle rotations final double xPivot = ((double) this.w) / 2.0d; final double yPivot = ((double) this.h) / 2.0d; rUL = new Rotate(); rLL = new Rotate(90, xPivot, yPivot); rLR = new Rotate(180, xPivot, yPivot); rUR = new Rotate(270, xPivot, yPivot); // compute the iso coordinate transformation // note that javafx transformations appear to compose backwards isoTransform = new Affine(); isoTransform.appendTranslation((0 - TILEW) / 2, 0); isoTransform.appendScale(TILEW / Math.sqrt(2), TILEH / Math.sqrt(2)); isoTransform.appendRotation(45, 0, 0); }
@Override public void reset() { // Reset the camera to its initial angles x.setAngle(0); y.setAngle(0); // Create an empty affine transformation, add the default angles to it, // and replace the node's transformations with it affine = new Affine(); affine.append(defaultX); affine.append(defaultY); affine.append(defaultZ); xform.getTransforms().setAll(affine); // Zoom the camera back to a default distance from the origin. camera.setTranslateZ(-2000); }
private TileGrid getTileGrid() { MapBase map = getMap(); int tileZoomLevel = Math.max(0, (int) Math.floor(map.getZoomLevel() + zoomLevelOffset)); double tileScale = (1 << tileZoomLevel); double scale = tileScale / (Math.pow(2d, map.getZoomLevel()) * TileSource.TILE_SIZE); Point2D tileCenter = getTileCenter(tileScale); Affine transform = new Affine(); transform.prependTranslation(-map.getWidth() / 2d, -map.getHeight() / 2d); transform.prependScale(scale, scale); transform.prependRotation(-map.getHeading()); transform.prependTranslation(tileCenter.getX(), tileCenter.getY()); // get tile index values of viewport rectangle Point2D p1 = transform.transform(new Point2D(0d, 0d)); Point2D p2 = transform.transform(new Point2D(map.getWidth(), 0d)); Point2D p3 = transform.transform(new Point2D(0d, map.getHeight())); Point2D p4 = transform.transform(new Point2D(map.getWidth(), map.getHeight())); return new TileGrid(tileZoomLevel, (int) Math.floor(Math.min(Math.min(p1.getX(), p2.getX()), Math.min(p3.getX(), p4.getX()))), (int) Math.floor(Math.min(Math.min(p1.getY(), p2.getY()), Math.min(p3.getY(), p4.getY()))), (int) Math.floor(Math.max(Math.max(p1.getX(), p2.getX()), Math.max(p3.getX(), p4.getX()))), (int) Math.floor(Math.max(Math.max(p1.getY(), p2.getY()), Math.max(p3.getY(), p4.getY())))); }
private void setTransform() { MapBase map = getMap(); double tileScale = (1 << tileGrid.getZoomLevel()); double scale = Math.pow(2d, map.getZoomLevel()) / tileScale; Point2D tileCenter = getTileCenter(tileScale); double tileOriginX = TileSource.TILE_SIZE * (tileCenter.getX() - tileGrid.getXMin()); double tileOriginY = TileSource.TILE_SIZE * (tileCenter.getY() - tileGrid.getYMin()); Affine transform = new Affine(); transform.prependTranslation(-tileOriginX, -tileOriginY); transform.prependScale(scale, scale); transform.prependRotation(map.getHeading()); transform.prependTranslation(map.getWidth() / 2d, map.getHeight() / 2d); getTransforms().set(0, transform); }
private void updateLayout() { Affine viewportTransform = null; Bounds bounds = null; MapBase map = getMap(); MapBoundingBox boundingBox = getBoundingBox(); if (map != null && boundingBox != null) { bounds = map.getProjection().boundingBoxToBounds(boundingBox); viewportTransform = map.getProjection().getViewportTransform(); } if (bounds != null) { getTransforms().setAll(viewportTransform, Transform.scale(1d, -1d, 0d, bounds.getMaxY())); setX(bounds.getMinX()); setY(bounds.getMaxY()); setFitWidth(bounds.getWidth()); setFitHeight(bounds.getHeight()); } else { getTransforms().clear(); setX(0); setY(0); setFitWidth(0); setFitHeight(0); } }
public void setViewportTransform(Location projectionCenter, Location mapCenter, Point2D viewportCenter, double zoomLevel, double heading) { viewportScale = getViewportScale(zoomLevel); Point2D center = locationToPoint(mapCenter); Affine transform = new Affine(); transform.prependTranslation(-center.getX(), -center.getY()); transform.prependScale(viewportScale, -viewportScale); transform.prependRotation(heading); transform.prependTranslation(viewportCenter.getX(), viewportCenter.getY()); viewportTransform.setToTransform(transform); try { transform.invert(); } catch (NonInvertibleTransformException ex) { throw new RuntimeException(ex); // this will never happen } inverseViewportTransform.setToTransform(transform); }
/** * Draw the Links on Canvas to the Childs */ public void drawLink() { GraphicsContext gc = gbv.getGraphicsContext2D(); gc.setStroke(Color.BLACK); children.forEach(nodeView -> { int x1 = x + this.width / 2; int y1 = y + this.height / 2; int x2 = nodeView.x + nodeView.width / 2; int y2 = nodeView.y + nodeView.height / 2; gc.strokeLine(x1, y1, x2, y2); double linkMidX = (x1 + x2) / 2.0; nodeView.midLinkX = (int) linkMidX; double linkMidY = (y1 + y2) / 2.0; nodeView.midLinkY = (int) linkMidY; double rotate = Math.toDegrees(Math.atan2(y2 - y1, x2 - x1)) + 225; gc.setTransform(new Affine(new Rotate(rotate, linkMidX, linkMidY))); double arrowX = linkMidX - (arrow.getWidth() * 3 / 4); double arrowY = linkMidY - (arrow.getWidth() / 4); gc.drawImage(arrow, arrowX, arrowY); gc.setTransform(new Affine()); }); }
public void updateArrow(String face, boolean hover){ boolean bFaceArrow=!(face.startsWith("X")||face.startsWith("Y")||face.startsWith("Z")); MeshView arrow=bFaceArrow?faceArrow:axisArrow; if(hover && onRotation.get()){ return; } arrow.getTransforms().clear(); if(hover){ double d0=arrow.getBoundsInParent().getHeight()/2d; Affine aff=Utils.getAffine(dimCube, d0, bFaceArrow, face); arrow.getTransforms().setAll(aff); arrow.setMaterial(Utils.getMaterial(face)); if(previewFace.get().isEmpty()) { previewFace.set(face); onPreview.set(true); rotateFace(face,true,false); } } else if(previewFace.get().equals(face)){ rotateFace(Utils.reverseRotation(face),true,true); } else if(previewFace.get().equals("V")){ previewFace.set(""); onPreview.set(false); } }
public ZoomPane(Node... nodes) { super(); zoomGroup = new Group(nodes); getChildren().addAll(zoomGroup); transform = new Affine(); workTransform = new Affine(); getChildren().get(0).getTransforms().setAll(transform); setOnZoomStarted(e -> start(e.getX(), e.getY())); setOnScrollStarted(e -> start(e.getX(), e.getY())); setOnMousePressed(e -> start(e.getX(), e.getY())); setOnZoomFinished(e -> finish()); setOnMouseReleased(e -> finish()); setOnScrollFinished(e -> finish()); setOnZoom(this::zooming); setOnScroll(this::scrolling); setOnMouseDragged(this::dragging); }
public void render(Bullet bullet, GraphicsContext gc) { gc.save(); gc.translate(bullet.getX(), bullet.getY()); gc.transform(new Affine(new Rotate(bullet.getAngle()))); //Rotate the gc to the angle of the bullet's path //TODO increase bullet size in general if (this == STANDARD) { gc.translate(-2, -3); //Move SVG to center of Bullet gc.setFill(Color.GRAY); gc.beginPath(); gc.appendSVGPath("M 0 3 Q 0 1 2 0 Q 4 1 4 3 L 4 7 L 0 7 Z"); //SVG PATH OF BULLET gc.fill(); gc.closePath(); } else if (this == ROCKET) { //TODO create rocket SVG gc.setFill(Color.GRAY); gc.beginPath(); gc.appendSVGPath("M 0 3 Q 0 1 2 0 Q 4 1 4 3 L 4 7 L 0 7 Z"); //SVG PATH OF BULLET gc.fill(); gc.closePath(); } else if (this == BOUNCY) { gc.setFill(Color.GRAY); gc.fillOval(bullet.getX() - bullet.getRadius(), bullet.getY() - bullet.getRadius(), bullet.getRadius() * 2, bullet.getRadius() * 2); } gc.restore(); }
public void update(GraphicsContext gc) { angle += rotation; x += Math.sin(Math.toRadians(-angle)) * velocity; y += Math.cos(Math.toRadians(-angle)) * velocity; bounds.setLocation(x, y, 64, 64, angle); //RENDER gc.save(); Affine transform = new Affine(new Rotate(angle, x, y)); gc.transform(transform); gc.setFill(Color.GREY); gc.fillRoundRect(x - 32, y - 32, 64, 64, 3, 3); gc.setFill(color); gc.fillRect(x - 32 + 12, y - 32, 64 - 24, 64); gc.restore(); //Update turret turret.update(gc); if (currentPickUp != null && currentPickUp.getTime() == 0) { currentPickUp = null; bulletType = BulletType.STANDARD; } }
public void update(GraphicsContext gc) { gc.save(); gc.transform(new Affine(new Rotate(angle, tank.getX(), tank.getY()))); gc.setFill(tank.getColor().brighter()); gc.fillRoundRect(tank.getX() - 16, tank.getY() - 16, 32, 32, 7, 7); gc.setFill(Color.LIGHTGRAY); gc.fillRect(tank.getX() - 2, tank.getY() - 40, 4, 25); gc.restore(); }
public void render() { //Tank tracks if (updates == 7) { for (Tank tank : framework.getTanks()) { gc.save(); gc.transform(new Affine(new Rotate(tank.getAngle(), tank.getX(), tank.getY()))); gc.setFill(Color.rgb(229, 229, 211, 0.8)); gc.fillRect(tank.getX() - 32, tank.getY(), 16, 5); gc.fillRect(tank.getX() + 32 - 16, tank.getY(), 16, 5); gc.restore(); } updates = 0; } }
public AffineEvent(EventType<? extends Event> eventType, Affine affine, Affine previous, Dimension2D targetDimension) { super(eventType); this.affine = affine; this.previous = previous; this.targetDimension = targetDimension; }
/** * @return a copy of the current affine transformation subtract the previous transformation. * This is the same as direct matrix subtraction: Mat(previous)-Mat(current) */ public Affine difference() { Affine c = this.affine; Affine p = this.previous; if (p == null) return current(); return new Affine( c.getMxx() - p.getMxx(), c.getMxy() - p.getMxy(), c.getMxz() - p.getMxz(), c.getTx() - p.getTx(), c.getMyx() - p.getMyx(), c.getMyy() - p.getMyy(), c.getMyz() - p.getMyz(), c.getTy() - p.getTy(), c.getMzx() - p.getMzx(), c.getMzy() - p.getMzy(), c.getMzz() - p.getMzz(), c.getTz() - p.getTz()); }
/** * Calculates the {@link Transform Transformation} from children node coordinates to * parent node coordinates. * <p> * {@code child} must be a direct or indirect child of {@code rootOfCalculation}. * * @param rootOfCalculation Any node in a scene graph * @param child A direct/indirect child of rootOfCalculation * @return A Transformation between coordinates of child and rootOfCalculation */ public static Transform calculateTransformRelativeTo(Node rootOfCalculation, Node child) { if (child.getScene() == null) { throw new IllegalStateException("Child is not displayed in any scene currently."); } if (child.getParent() == null) { throw new IllegalStateException( "rootOfCalculation is not in the scenegraph between root node and child."); } if (child == rootOfCalculation) { return new Affine(); } Transform parentTransform = calculateTransformRelativeTo(rootOfCalculation, child.getParent()); return child.getLocalToParentTransform().createConcatenation(parentTransform); }
@SuppressWarnings("boxing") @Override public void messageArrived(String topic, MqttMessage message) { System.out.println("messageArrived(" + topic + ")"); ByteBuffer buffer = ByteBuffer.wrap(message.getPayload()); double[] compass = new double[] { buffer.getDouble(), buffer.getDouble(), buffer.getDouble() }; double[] accel = new double[] { buffer.getDouble(), buffer.getDouble(), buffer.getDouble() }; double[] gyro = new double[] { buffer.getDouble(), buffer.getDouble(), buffer.getDouble() }; double[] quat = new double[] { buffer.getDouble(), buffer.getDouble(), buffer.getDouble(), buffer.getDouble() }; double[] ypr = new double[] { buffer.getDouble(), buffer.getDouble(), buffer.getDouble() }; double w = quat[QUAT_SCALER]; double x = quat[QUAT_X]; double y = quat[QUAT_Y]; double z = quat[QUAT_Z]; System.out.format("Got IMU data: compass=[%f, %f, %f], accel=[%f, %f, %f], " + "gyro=[%f, %f, %f], quat=[%f, %f, %f, %f], ypr=[%f, %f, %f]%n", compass[0], compass[1], compass[2], accel[0], accel[1], accel[2], gyro[0], gyro[1], gyro[2], quat[0], quat[1], quat[2], quat[3], ypr[0], ypr[1], ypr[2]); Rotate rx = new Rotate(Math.toDegrees(ypr[0]), Rotate.X_AXIS); Rotate ry = new Rotate(Math.toDegrees(ypr[1]), Rotate.Y_AXIS); Rotate rz = new Rotate(Math.toDegrees(ypr[2]), Rotate.Z_AXIS); double[] idt = { 1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1 }; Affine matrix = new Affine(idt, MatrixType.MT_3D_3x4, 0); // http://www.j3d.org/matrix_faq/matrfaq_latest.html#Q54 matrix.setMxx(1 - (2*y*y + 2*z*z)); matrix.setMxy(2*x*y + 2*z*w); matrix.setMxz(2*x*z - 2*y*w); matrix.setMyx(2*x*y - 2*z*w); matrix.setMyy(1 - (2*x*x + 2*z*z)); matrix.setMyz(2*y*z + 2*x*w); matrix.setMzx(2*x*z + 2*y*w); matrix.setMzy(2*y*z - 2*x*w); matrix.setMzz(1 - (2*x*x + 2*y*y)); if (! Platform.isFxApplicationThread()) { Platform.runLater(() -> { testObject.getTransforms().setAll(matrix); //testObject.getTransforms().clear(); //testObject.getTransforms().addAll(rx, ry, rz); } ); } }
@Override public void render(double x, double y) { double scale = State.getCurrentState().scale(); g.save(); g.setTransform((new Affine(new Rotate(-(acceleration.getDirection().getDegrees() - 90), x + ((getWidth() * (Grid.SIZE * scale)) / 2), y + (getHeight() * (Grid.SIZE * scale)))))); g.drawImage(image, x * scale, y * scale, Grid.SIZE * scale, Grid.SIZE * scale); g.restore(); }
private static Point3D getMeshNormal(MeshView mesh){ TriangleMesh tm = (TriangleMesh) mesh.getMesh(); float[] fPoints = new float[tm.getPoints().size()]; tm.getPoints().toArray(fPoints); Point3D BA = new Point3D(fPoints[3] - fPoints[0], fPoints[4] - fPoints[1], fPoints[5] - fPoints[2]); Point3D CA = new Point3D(fPoints[6] - fPoints[0], fPoints[7] - fPoints[1], fPoints[8] - fPoints[2]); Point3D normal = BA.crossProduct(CA); Affine a = new Affine(mesh.getTransforms().get(0)); return a.transform(normal.normalize()); }
private void updateScreenTransform() { screenTransform = new Affine(); screenTransform.appendTranslation(lx, ly); screenTransform.appendScale( viewportW / ISO_VIEWPORTW, viewportH / ISO_VIEWPORTH); totalScreenTransform = screenTransform.clone(); totalScreenTransform.appendTranslation(-x, -y); innerPane.getTransforms().clear(); innerPane.getTransforms().addAll(screenTransform, scrollTransform); scrollTransform.setX(-x); scrollTransform.setY(-y); }
@Override public void reset() { // Handle the rotations if they exist if (x != null) { // Reset the camera to its initial angles x.setAngle(defaultX.getAngle()); y.setAngle(defaultY.getAngle()); z.setAngle(defaultZ.getAngle()); } // Zoom the camera back to a default distance from the origin. affine = new Affine(); affine.appendTranslation(0, 0, -1000); // If x, y, and z exist, apply them to the camera if (x != null) { xform.getTransforms().setAll(x, y, z, affine); } // Otherwise only apply the affine to the camera else { xform.getTransforms().setAll(affine); } camera.setTranslateZ(-1000); }
@Override public void reset() { // Create a new affine transformation, set it to the default position, // and apply it to the camera affine = new Affine(); affine.appendTranslation(0, 0, -85); xform.getTransforms().setAll(affine); }
/** * <p> * Converts an ICE Geometry Transformation data structure to a JavaFX * Transform. * </p> * * @param transform * ICE Transformation data structure * @return a JavaFX transformation that is analagous to the Transformation */ public static Transform convertTransformation( Transformation transformation) { Affine transform = new Affine(); if (transformation == null) { return transform; } double size = transformation.getSize(); double[] scale = transformation.getScale(); double[] rotation = transformation.getRotation(); double[] translation = transformation.getTranslation(); Scale sizeXform = new Scale(size, size, size); Scale scaleXform = new Scale(scale[0], scale[1], scale[2]); Rotate rotateXform = eulerToRotate(rotation[0], rotation[1], rotation[2]); Translate translateXform = new Translate(translation[0], translation[1], translation[2]); Transform transformOutput = transform .createConcatenation(translateXform) .createConcatenation(rotateXform).createConcatenation(sizeXform) .createConcatenation(scaleXform); return transformOutput; }
public Transform toTransform() { return new Affine( matrix[0][0], matrix[0][1], matrix[0][2], matrix[0][3], matrix[1][0], matrix[1][1], matrix[1][2], matrix[1][3], matrix[2][0], matrix[2][1], matrix[2][2], matrix[2][3] ); }
public MapTileLayer(ITileImageLoader tileImageLoader) { getStyleClass().add("map-tile-layer"); getTransforms().add(new Affine()); setMouseTransparent(true); this.tileImageLoader = tileImageLoader; tileSourceProperty.addListener(observable -> updateTiles(true)); updateTimeline.getKeyFrames().add(new KeyFrame(getUpdateDelay(), e -> updateTileGrid())); updateDelayProperty.addListener(observable -> updateTimeline.getKeyFrames().set(0, new KeyFrame(getUpdateDelay(), e -> updateTileGrid()))); }
private static Point3D getMeshNormal(MeshView mesh){ TriangleMesh tm=(TriangleMesh)mesh.getMesh(); float[] fPoints=new float[tm.getPoints().size()]; tm.getPoints().toArray(fPoints); Point3D BA=new Point3D(fPoints[3]-fPoints[0],fPoints[4]-fPoints[1],fPoints[5]-fPoints[2]); Point3D CA=new Point3D(fPoints[6]-fPoints[0],fPoints[7]-fPoints[1],fPoints[8]-fPoints[2]); Point3D normal=BA.crossProduct(CA); Affine a=new Affine(mesh.getTransforms().get(0)); return a.transform(normal.normalize()); }
@Override public Affine getContentTransform() { // TODO Auto-generated method stub return null; }
@Override public void setContentTransform(Affine totalTransform) { // TODO Auto-generated method stub }
void fireAffineEvent(EventType<AffineEvent> type) { Dimension2D dimension = new Dimension2D(getTargetWidth(), getTargetHeight()); Affine snapshot = new Affine(this.affine); fireEvent(new AffineEvent(type, snapshot, lastAffine, dimension)); lastAffine = snapshot; }
@Override public Affine getScale() { return new Affine(new Scale(SCALE, SCALE)); }
/** * @return The scale used to scale the contents of the {@link AbstractView}. */ public Affine getScale() { return new Affine(new Scale(SCALE, SCALE)); }
/** * Gets the transformation from cartesian map coordinates to viewport coordinates. */ public Affine getViewportTransform() { return viewportTransform; }
/** * Gets the transformation from viewport coordinates to cartesian map coordinates. */ public Affine getInverseViewportTransform() { return inverseViewportTransform; }
public final Affine getScaleRotateTransform() { return scaleRotateTransform; }
public Rubik(){ /* Import Rubik's Cube model and arrows */ Model3D model=new Model3D(); model.importObj(); mapMeshes=model.getMapMeshes(); faceArrow=model.getFaceArrow(); axisArrow=model.getAxisArrow(); cube.getChildren().setAll(mapMeshes.values()); cube.getChildren().addAll(faceArrow); cube.getChildren().addAll(axisArrow); dimCube=cube.getBoundsInParent().getWidth(); /* Create content subscene, add cube, set camera and lights */ content = new ContentModel(800,600,dimCube); content.setContent(cube); /* Initialize 3D array of indexes and a copy of original/solved position */ rot=new Rotations(); order=rot.getCube(); // System.out.println(""+order.stream().mapToLong(o->mapMeshes.keySet().stream().filter(k->k.contains(o.toString())).count()).sum()); // save original position mapMeshes.forEach((k,v)->mapTransformsOriginal.put(k, v.getTransforms().get(0))); orderOriginal=order.stream().collect(Collectors.toList()); /* Listener to perform an animated face rotation. Note: by prepending the rotations it is not possible to create the animation with a timeline like this: Rotate r=new Rotate(0,axis); v.getTransforms().add(r); Timeline timeline=new Timeline(); timeline.getKeyFrames().add(new KeyFrame(Duration.Seconds(2),new KeyValue(rotation.angle,90))); that takes care of the values: 0<=angle<=90º and transforms the cubies smoothly. So we create the timeline, and listen to how internally it interpolate rotate.angle and perform small rotations between the increments of the angle that the timeline generates: */ rotMap=(ov,angOld,angNew)->{ mapMeshes.forEach((k,v)->{ layer.stream().filter(l->k.contains(l.toString())) .findFirst().ifPresent(l->{ Affine a=new Affine(v.getTransforms().get(0)); a.prepend(new Rotate(angNew.doubleValue()-angOld.doubleValue(),axis)); v.getTransforms().setAll(a); }); }); }; }
public void importObj(){ try {// cube.obj ObjImporter reader = new ObjImporter(getClass().getResource("Cube.obj").toExternalForm()); meshes=reader.getMeshes(); // set with the names of 117 meshes /* Since the model is oriented with White to the right and blue in the bottom, two rotations are required: - first rotate -90ºX B->F (Rx[-Pi/2]) - then + 90º Z W->U (Rz[Pi/2]) Mathematically, 2nd rotation matrix multiplies on the left the 1st matrix: Rz[Pi/2].Rx[-Pi/2] Check this link to notice the difference of add/append or prepend a transformation: http://hg.openjdk.java.net/openjfx/8/master/rt/file/f89b7dc932af/modules/graphics/src/main/java/javafx/scene/transform/Affine.java Notice this will be wrong: * cubiePart.getTransforms().addAll(new Rotate(-90, Rotate.X_AXIS),new Rotate(90, Rotate.Z_AXIS)); as it will perform this: Rx[-Pi/2].Rz[Pi/2] ->Red on top, yellow front! Also this is wrong: * cubiePart.getTransforms().addAll(new Rotate(90, Rotate.Z_AXIS),new Rotate(-90, Rotate.X_AXIS)); It does the right rotations, but then it will require for further rotations of any cubie to be rotated from its original position, which is quite more complicated than rotating always from the last state. PREPEND is the right way to proceed here, so we just need to prepend the last R matrix to the Affine matrix of the cubie with all the previous rotations stored there. */ Affine affineIni=new Affine(); affineIni.prepend(new Rotate(-90, Rotate.X_AXIS)); affineIni.prepend(new Rotate(90, Rotate.Z_AXIS)); meshes.stream().forEach(s-> { MeshView cubiePart = reader.buildMeshView(s); // every part of the cubie is transformed with both rotations: cubiePart.getTransforms().add(affineIni); // since the model has Ns=0 it doesn't reflect light, so we change it to 1 PhongMaterial material = (PhongMaterial) cubiePart.getMaterial(); material.setSpecularPower(1); cubiePart.setMaterial(material); // finally, add the name of the part and the cubie part to the hashMap: mapMeshes.put(s,cubiePart); }); } catch (IOException e) { System.out.println("Error loading model "+e.toString()); } }