1

I tried to programm a windmill with rotating rotor/head. The stem itself is fixed and drawn as a background onto a canvas (javafx). The rotor/head itself is another image. I thought I could rotate the image itself and draw it onto the graphicscontext. (Didn't work) Then I tried various things:

a. Drawing the image onto another canvas, rotate the canvas, make a snapshot of that canvas. (Didn't work)

b. Make an imageview, rotate the imageview, snapshot it and draw it (Didn't work) and

c. I tried to make a RotateTransition (Didn't work). Now I am back to b: an ImageView of the image which I rotate.

b sort of works, sort of! It somehow "bounces" and I don`t know why because the doc says that ImageView.setRotate(..) rotates the image around the center. The image itself has same height and length therefore it should bounce as if it were a rectangle.. I just want this bounce to stop.. see here (SO didnt allow me to post a gif)

All of these failed tries came from readings of this forum.

Source Code here or as text:

package sample;

import javafx.animation.AnimationTimer;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Scene;
import javafx.scene.SnapshotParameters;
import javafx.scene.canvas.Canvas;
import javafx.scene.canvas.GraphicsContext;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.layout.Pane;
import javafx.scene.paint.Color;
import javafx.stage.Stage;

import java.io.IOException;


public class Main extends Application {
    private Pane root;
    private Canvas canvas;
    private GraphicsContext gc;
    SnapshotParameters params = new SnapshotParameters();

    private final Image stem = new Image(getClass().getResource("windrad.png").toExternalForm());
    private final ImageView wheel = new ImageView(new Image(getClass().getResource("rad.png").toExternalForm()));

    private final int height = 720;
    private final int width = 720;
    private final double distanceWidth = 400.0 / 720.0;
    private final double distanceHeight = 240.0 / 720.0;
    private int degrees = 0;

    public static void main(String[] args) {
        launch(args);
    }

    @Override
    public void start(Stage primaryStage) throws Exception{
        params.setFill(Color.TRANSPARENT);

        FXMLLoader fxmlLoader = new FXMLLoader();
        fxmlLoader.setLocation(getClass().getResource("sample.fxml"));

        try {
            root = fxmlLoader.load();
            canvas = (Canvas) fxmlLoader.getNamespace().get("canvas");
            canvas.setHeight(height);
            canvas.setWidth(width);
            primaryStage.setHeight(height);
            primaryStage.setWidth(width);
            gc = canvas.getGraphicsContext2D();
        } catch (IOException e) {
            e.printStackTrace();
        }

        primaryStage.setTitle("Hello World");
        primaryStage.setScene(new Scene(root));
        primaryStage.show();

        animation().start();
    }

    private AnimationTimer animation() {
        return new AnimationTimer() {
            @Override
            public void handle(long now) {
                gc.clearRect(0,0, width, height);
                gc.drawImage(stem, 0, 0);
                degrees = degrees >= 360 ? 0 : ++degrees;
                wheel.setRotate(degrees);
                gc.drawImage(wheel.snapshot(params, null),  width * distanceWidth - (int) wheel.getImage().getWidth() / 2, height * distanceHeight - (int) wheel.getImage().getHeight() / 2);

            }
        };
    }
}

Ok, so I got it working! @James_D helped me a lot. Instead of drawing it onto a canvas I placed all objects in a scenegraph and moved it there. Since my rotor/head is a imageview I was able to use imageview.setRotate(). My issue (for which I posted this thread) originated by the use of the canvas. I still don`t know how the bouncing bug occured but my project aim is achieved. The new source code is in the answers.

Basti
  • 17
  • 5
  • Do you have to use a canvas? It would likely be easier to place nodes in a scene graph. – James_D Oct 02 '17 at 17:05
  • Also see https://meta.stackoverflow.com/questions/285551/why-not-upload-images-of-code-on-so-when-asking-a-question. Please [edit] your question and include the code directly. – James_D Oct 02 '17 at 17:06
  • @James_D How do I include the code directly? Just copy paste or a command within the text editor? I will read up ob scene graph! – Basti Oct 02 '17 at 17:13
  • https://meta.stackoverflow.com/questions/251361/how-do-i-format-my-code-blocks – James_D Oct 02 '17 at 17:15
  • @James_D I read up on scene graph and am a little confused. Isn‘t what I used the Javafx scene graph? – Basti Oct 02 '17 at 17:41
  • I meant place nodes in the scene graph *instead* of drawing on a canvas. Sure, you are (of course) placing the canvas in a scene graph. But it is inherently difficult to modify a canvas once drawn. – James_D Oct 02 '17 at 17:42
  • @James_D Aaaah! Now I get it! This is brilliant! I always tried to visualize my objects using a canvas but this really (might) be easier for my problem. I will try it and give you feedback :) – Basti Oct 02 '17 at 18:09
  • 1
    @James_D ok, it really worked! Thanks, problem solved. – Basti Oct 02 '17 at 19:35
  • 1
    Excellent. You could consider posting an answer to your own question (with code, etc), if you think it would be helpful to others. You can accept the answer after some grace period. – James_D Oct 02 '17 at 19:36
  • Perhaps this question is a duplicate of [How to draw image rotated on JavaFX Canvas?](https://stackoverflow.com/questions/18260421/how-to-draw-image-rotated-on-javafx-canvas), well perhaps a combination of that and [Moving shapes in JavaFX canvas](https://stackoverflow.com/questions/21396055/moving-shapes-in-javafx-canvas). Though, as has been pointed out before, the alternate solution of not using a Canvas at all and just drawing direct to the scene graph is likely the better solution in this case. – jewelsea Oct 02 '17 at 23:33
  • @jewelsea I read those two too and thought of mine as a duplicate too, but my problem was the bouncing image and not the moving part itself. Therefore I thought mine was eligible to ask. I will mark it as solved and check James_D answer as solution :) – Basti Oct 03 '17 at 07:45
  • Sure, makes sense Basti. Sometimes it is a good idea in your question to link to previous research or similar solutions you have found and explain how your question differs. Not necessary here anymore, but might be useful if applicable in a future question. – jewelsea Oct 03 '17 at 08:56
  • Best to put the source code for the answer in the answer rather than in an edited version of the question. In any case, thanks for posting it. – jewelsea Oct 03 '17 at 08:58

1 Answers1

0

I meant place nodes in the scene graph instead of drawing on a canvas. Sure, you are (of course) placing the canvas in a scene graph. But it is inherently difficult to modify a canvas once drawn. - @James_D

This comment helped and solved my problem. The new source code is listed in the question. Instead of drawing it onto a canvas I put all objects in a scene graph and moved an imageview instead of a canvas or image. Heres the new source code:

package sample;

import javafx.animation.AnimationTimer;
import javafx.application.Application;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.stage.Stage;

public class Main extends Application {
    private Group root;

    private final ImageView stem = new ImageView(new Image(getClass().getResource("windrad.png").toExternalForm()));
    private final ImageView wheel = new ImageView(new Image(getClass().getResource("rad.png").toExternalForm()));

    private final int height = 720;
    private final int width = 720;
    private final double distanceWidth = 360.0 / 720.0;
    private final double distanceHeight = 270.0 / 720.0;

    public static void main(String[] args) {
        launch(args);
    }

    @Override
    public void start(Stage primaryStage) throws Exception{
        root = new Group();
        root.getChildren().add(stem);
        root.getChildren().add(wheel);
        wheel.setX(width * distanceWidth - wheel.getImage().getWidth() / 2);
        wheel.setY(height * distanceHeight - wheel.getImage().getHeight() / 2);
        primaryStage.setTitle("Pinwheel");
        primaryStage.setScene(new Scene(root));
        primaryStage.show();
        primaryStage.getIcons().add(new Image(getClass().getResource("windrad.png").toExternalForm()));

        animation().start();
    }

    private AnimationTimer animation() {
        return new AnimationTimer() {
            @Override
            public void handle(long now) {
                wheel.setRotate(wheel.getRotate() + 1);
            }
        };
    }
}
Basti
  • 17
  • 5