0

Java program. Using latest version of eclipse and java. Program works just as it should but I cant figure out why I cannot see the circle at the bottom of the pendulum. The program should show the pendulum as a line connecting a top and bottom circle. I've tried moving around the setFill() and setStroke() code and still can't figure this one out...probably something small and simple but I'm missing it. Let me know whats right in front of me please!

import javafx.animation.PathTransition;
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.Pane;
import javafx.scene.layout.VBox;
import javafx.scene.paint.Color;
import javafx.scene.shape.Arc;
import javafx.scene.shape.Circle;
import javafx.scene.shape.Line;
import javafx.stage.Stage;
import javafx.util.Duration;

public class Ch15PA2 extends Application {
    
    public void start(Stage primaryStage) {
        
        BorderPane pane = new BorderPane();
        VBox vbox = new VBox();
        pane.getChildren().add(vbox);
        
        Pendulum pendulum = new Pendulum(500, 300);
        pane.setCenter(pendulum);   
        
        Scene scene = new Scene(pane,500,500);
        primaryStage.setTitle("Chapter 15 Programming Assignemnt 2");
        primaryStage.setScene(scene);
        pendulum.resume();
        primaryStage.show();
        
        scene.setOnKeyPressed(e -> {
            switch (e.getCode()) {
            case UP: pendulum.increase(); break;
            case DOWN: pendulum.decrease(); break;
            case R: pendulum.resume(); break;
            case S: pendulum.stop(); break;
            }
        });
    }

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

}

class Pendulum extends Pane {
    private double w=300;
    private double h;
    
    PathTransition pt;
    Circle topCircle = new Circle();
    Circle bottomCircle = new Circle();
    Line line;
    Arc arc;
    
    public Pendulum(double width,double height) {
        w = width;
        h = height;
        
        arc = new Arc(w/2,h*.8,w*.15,w*.15,180,180);
        topCircle = new Circle(arc.getCenterX()-arc.getRadiusX(),arc.getCenterY(),10);
        bottomCircle = new Circle(arc.getCenterX(),arc.getCenterY()-h/2,bottomCircle.getRadius()/2);
        arc = new Arc(topCircle.getCenterX(),topCircle.getCenterY(),w/2,h/2,240,60);
        arc.setFill(Color.TRANSPARENT);
        line = new Line(topCircle.getCenterX(),topCircle.getCenterY(),bottomCircle.getCenterX(),bottomCircle.getCenterY());
        pt = new PathTransition();
        pt.setDuration(Duration.seconds(2.0));
        pt.setPath(arc);
        pt.setNode(bottomCircle);
        pt.setOrientation(PathTransition.OrientationType.NONE);
        pt.setCycleCount(PathTransition.INDEFINITE);
        pt.setAutoReverse(true);
        topCircle.setStroke(Color.BLACK);
        topCircle.setFill(Color.BLACK);
        bottomCircle.setStroke(Color.BLACK);
        bottomCircle.setFill(Color.BLACK);
        line.setStroke(Color.BLACK);
        line.endXProperty().bind(bottomCircle.translateXProperty().add(bottomCircle.getCenterX()));
        line.endYProperty().bind(bottomCircle.translateYProperty().add(bottomCircle.getCenterY()));

        getChildren().add(line);
        getChildren().add(bottomCircle);
        getChildren().add(topCircle);
        getChildren().add(arc);
        
    }
    
    public void increase() {
        pt.setRate(pt.getRate()+1);
    }
    
    public void decrease() {
        pt.setRate(pt.getRate()-1);
    }
    
    public void resume() {
        pt.play();
    }
    
    public void stop() {
        pt.stop();
    }
}
  • 1
    Stepping through your code with a debugger might help. However, this portion seems odd when creating the bottom circle: `bottomCircle.getRadius()/2` seems to be defining the radius. 1) Why are you creating empty circles like `Circle bottomCircle = new Circle();` and then replace them with the actual circle? 2) If my assumption is correct then `bottomCircle.getRadius()` returns 0 which means the new bottom circle with have a radius of 0 as well. And can we see circles with no radius? :) – Thomas Oct 12 '22 at 15:43
  • An alternate approach is shown [here](https://stackoverflow.com/a/38031826/230513). – trashgod Oct 12 '22 at 16:18
  • ah ha! no, we cannot! –  Oct 12 '22 at 17:43

2 Answers2

4

You're setting the radius of bottomCircle to zero.

First you do:

Circle bottomCircle = new Circle();

which creates a circle with centerX=0, centerY=0, and (importantly) radius=0. Then in the constructor you do:

bottomCircle = new Circle(arc.getCenterX(),arc.getCenterY()-h/2,bottomCircle.getRadius()/2);

Since bottomCircle.getRadius() returns 0, this re-initializes bottomCircle to a circle with radius 0. Since the radius is zero, there is no actual circle to see.

Since your only constructor initializes both topCircle and bottomCircle, it really makes no sense to initialize them inline with their declarations (since you simply replace those objects immediately anyway). Just declare them as

Circle topCircle;
Circle bottomCircle;

This would give you a null pointer exception with your current code, alerting you to the fact that setting bottomCircle.radius to bottomCircle.radius/2 is almost certainly not what you want to do.

Generally, it's confusing to assign something a value and to then immediately assign it another value. You can just do something like

class Pendulum extends Pane {
    private double w;
    private double h;

    PathTransition pt;
    Circle topCircle;
    Circle bottomCircle;
    Line line;
    Arc arc;

    public Pendulum(double width,double height) {
        w = width;
        h = height;

//        arc = new Arc(w/2,h*.8,w*.15,w*.15,180,180);
        topCircle = new Circle(w/2-w*.15,h*.8,10);
        bottomCircle = new Circle(w/2,h*.8-h/2,5);
        arc = new Arc(topCircle.getCenterX(),topCircle.getCenterY(),w/2,h/2,240,60);
        arc.setFill(Color.TRANSPARENT);
        
        // ...

    }

    // ...
}
James_D
  • 201,275
  • 16
  • 291
  • 322
  • 2
    I think you need a small correction. As of now it looks like the pendulum is stretching when it goes to the far ends. This is because of the radiusX & radiusY of arc are different. Technically the pendulum arc will be part of a circle ( which means the radiusX & Y should be same). You can correct it by setting the radiusX to h/2.. something like `arc = new Arc(topCircle.getCenterX(),topCircle.getCenterY(),h/2,h/2,240,60);` – Sai Dandem Oct 12 '22 at 20:15
  • 1
    @SaiDandem thanks...i noticed that as well and was wondering about it –  Oct 12 '22 at 23:33
2

Expanding on @James_D's insight, your Pendulum is a Pane, suitable for "absolute positioning of children." At the same time, as @SaiDandem observes, you need a 1:1 radial aspect ratio to make the arc circular. As a result, a single size parameter may suffice:

Pendulum pendulum = new Pendulum(500);

Use this parameter to derive subsequent geometry and define the pane's preferred size, confident that surrounding layout will cause it to adopt the desired size:

public Pendulum(double size) {
    this.w = size;
    this.h = size;
    setPrefSize(w, h);

In the variation below, the arc is positioned at half the width and one fourth the height; the radii are half the size. Moreover, the bottom circle is moved down by the same radial distance and made visible. Set the arc's fill to an opaque color to see the effect.

Pendulum

import javafx.animation.PathTransition;
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.layout.Pane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Arc;
import javafx.scene.shape.Circle;
import javafx.scene.shape.Line;
import javafx.stage.Stage;
import javafx.util.Duration;

/** @see https://stackoverflow.com/q/74044277/230513 */
public class Ch15PA2 extends Application {

    @Override
    public void start(Stage primaryStage) {
        primaryStage.setTitle("Chapter 15 Programming Assignemnt 2");
        Pendulum pendulum = new Pendulum(500);
        Scene scene = new Scene(pendulum);
        primaryStage.setScene(scene);
        primaryStage.show();
        pendulum.play();
        scene.setOnKeyPressed(e -> {
            switch (e.getCode()) {
                case UP ->
                    pendulum.increase();
                case DOWN ->
                    pendulum.decrease();
                case R ->
                    pendulum.play();
                case S ->
                    pendulum.stop();
            }
        });
    }

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

class Pendulum extends Pane {

    private final double w;
    private final double h;

    private final PathTransition pT;
    private final Circle topCircle;
    private final Circle botCircle;
    private final Line line;
    private final Arc arc;

    public Pendulum(double size) {
        this.w = size;
        this.h = size;
        setPrefSize(w, h);
        arc = new Arc(w / 2, h / 4, w / 2, h / 2, 240, 60);
        arc.setFill(Color.TRANSPARENT);
        topCircle = new Circle(arc.getCenterX(), arc.getCenterY(), 8);
        botCircle = new Circle(arc.getCenterX(), arc.getCenterY() + h / 2, 16);
        line = new Line(topCircle.getCenterX(), topCircle.getCenterY(),
            botCircle.getCenterX(), botCircle.getCenterY());
        topCircle.setStroke(Color.BLACK);
        topCircle.setFill(Color.BLACK);
        botCircle.setStroke(Color.BLACK);
        botCircle.setFill(Color.BLACK);
        line.setStroke(Color.BLACK);
        line.endXProperty().bind(
            botCircle.translateXProperty().add(botCircle.getCenterX()));
        line.endYProperty().bind(
            botCircle.translateYProperty().add(botCircle.getCenterY()));
        pT = new PathTransition();
        pT.setDuration(Duration.seconds(2.0));
        pT.setPath(arc);
        pT.setNode(botCircle);
        pT.setOrientation(PathTransition.OrientationType.NONE);
        pT.setCycleCount(PathTransition.INDEFINITE);
        pT.setAutoReverse(true);
        getChildren().addAll(arc, line, botCircle, topCircle);
    }

    public void increase() {
        pT.setRate(pT.getRate() + 1);
    }

    public void decrease() {
        pT.setRate(pT.getRate() - 1);
    }

    public void play() {
        pT.play();
    }

    public void stop() {
        pT.stop();
    }
}
trashgod
  • 203,806
  • 29
  • 246
  • 1,045