|  | 
| 1 | 1 | package ch_15; | 
| 2 | 2 | 
 | 
|  | 3 | +import javafx.animation.PathTransition; | 
| 3 | 4 | import javafx.application.Application; | 
|  | 5 | +import javafx.collections.ObservableList; | 
|  | 6 | +import javafx.scene.Scene; | 
|  | 7 | +import javafx.scene.input.MouseButton; | 
|  | 8 | +import javafx.scene.layout.Pane; | 
|  | 9 | +import javafx.scene.shape.Circle; | 
|  | 10 | +import javafx.scene.shape.Line; | 
|  | 11 | +import javafx.scene.shape.Polyline; | 
|  | 12 | +import javafx.scene.text.Font; | 
|  | 13 | +import javafx.scene.text.Text; | 
| 4 | 14 | import javafx.stage.Stage; | 
|  | 15 | +import javafx.util.Duration; | 
| 5 | 16 | 
 | 
| 6 | 17 | /** | 
| 7 | 18 |  * **15.25 (Animation: ball on curve) Write a program that animates a ball moving along | 
|  | 
| 10 | 21 |  * a click on the left/right mouse button. | 
| 11 | 22 |  */ | 
| 12 | 23 | public class Exercise15_25 extends Application { | 
|  | 24 | + private final double sceneWidth = 600; | 
|  | 25 | + private final double sceneHeight = 260; | 
|  | 26 | + private final int fontSize = 16; | 
|  | 27 | + | 
|  | 28 | + private final double centerX; | 
|  | 29 | + private final double centerY; | 
|  | 30 | + | 
|  | 31 | + public Exercise15_25() { | 
|  | 32 | + centerX = sceneWidth / 2; | 
|  | 33 | + centerY = sceneHeight / 2; | 
|  | 34 | + } | 
|  | 35 | + | 
| 13 | 36 |  @Override | 
| 14 | 37 |  public void start(Stage primaryStage) throws Exception { | 
|  | 38 | + Pane pane = new Pane(); | 
|  | 39 | + Polyline xAxis = new Polyline(); | 
|  | 40 | + Polyline yAxis = new Polyline(); | 
|  | 41 | + drawYAxis(pane, yAxis); | 
|  | 42 | + drawXAxis(pane, xAxis); | 
|  | 43 | + | 
|  | 44 | + Polyline polyline1 = new Polyline(); | 
|  | 45 | + ObservableList<Double> list = polyline1.getPoints(); | 
|  | 46 | + int startXValue = -170; | 
|  | 47 | + int endXValue = 170; | 
|  | 48 | + for (int x = startXValue; x <= endXValue; x++) { | 
|  | 49 | + list.add(x + centerX); | 
|  | 50 | + double y = calculateY(x, centerY); | 
|  | 51 | + list.add(y); | 
|  | 52 | + if (isYIntersectingXAxis(y, centerY)) { | 
|  | 53 | + Text text = new Text(x + centerX, centerY / 0.9, getXAxisLabel(x)); | 
|  | 54 | + pane.getChildren().add(text); | 
|  | 55 | + } | 
|  | 56 | + | 
|  | 57 | + } | 
|  | 58 | + Circle point = new Circle(list.get(0), list.get(1), 10); | 
|  | 59 | + PathTransition path = new PathTransition(Duration.millis(4000), polyline1, point); | 
|  | 60 | + path.setCycleCount(PathTransition.INDEFINITE); | 
|  | 61 | + pane.getChildren().addAll(xAxis, yAxis, polyline1, point); | 
|  | 62 | + pane.setOnMouseClicked(e -> { | 
|  | 63 | + if (e.getButton() == MouseButton.PRIMARY) { | 
|  | 64 | + path.play(); | 
|  | 65 | + } else if (e.getButton() == MouseButton.SECONDARY) { | 
|  | 66 | + path.pause(); | 
|  | 67 | + } | 
|  | 68 | + }); | 
|  | 69 | + primaryStage.setScene(new Scene(pane, sceneWidth, sceneHeight)); | 
|  | 70 | + primaryStage.setTitle(getClass().getName()); | 
|  | 71 | + primaryStage.show(); | 
|  | 72 | + | 
|  | 73 | + } | 
|  | 74 | + | 
|  | 75 | + private double calculateY(int x, double centerY) { | 
|  | 76 | + return centerY - 50 * Math.sin((x / 100.0) * 2 * Math.PI); | 
|  | 77 | + } | 
|  | 78 | + | 
|  | 79 | + private boolean isYIntersectingXAxis(double y, double centerY) { | 
|  | 80 | + return y - centerY < 0.01 && y - centerY > -0.01; | 
|  | 81 | + } | 
|  | 82 | + | 
|  | 83 | + private void drawXAxis(Pane pane, Polyline xAxis) { | 
|  | 84 | + ObservableList<Double> xAxisList = xAxis.getPoints(); | 
|  | 85 | + double limit = sceneWidth * 0.95; | 
|  | 86 | + | 
|  | 87 | + for (double x = 0; x < limit; x++) { | 
|  | 88 | + xAxisList.add(x); | 
|  | 89 | + xAxisList.add(centerY); | 
|  | 90 | + } | 
| 15 | 91 | 
 | 
|  | 92 | + Line line1 = new Line(limit, centerY, limit - sceneWidth * 0.05, centerY * 0.875); | 
|  | 93 | + Line line2 = new Line(limit, centerY, limit - sceneWidth * 0.05, centerY / 0.875); | 
|  | 94 | + Text text = new Text(limit + (sceneWidth * 0.02), centerY, "X"); | 
|  | 95 | + text.setFont(Font.font(fontSize)); | 
|  | 96 | + pane.getChildren().addAll(line1, line2, text); | 
| 16 | 97 |  } | 
|  | 98 | + | 
|  | 99 | + private void drawYAxis(Pane pane, Polyline yAxis) { | 
|  | 100 | + | 
|  | 101 | + ObservableList<Double> yAxisList = yAxis.getPoints(); | 
|  | 102 | + double limit = sceneHeight * 0.95; | 
|  | 103 | + | 
|  | 104 | + for (double y = 0; y < limit; y++) { | 
|  | 105 | + yAxisList.add(centerX); | 
|  | 106 | + yAxisList.add(y + sceneHeight * 0.1); | 
|  | 107 | + | 
|  | 108 | + } | 
|  | 109 | + Line line1 = new Line(centerX, sceneHeight * 0.1, centerX - sceneWidth * 0.03, sceneHeight * 0.22); | 
|  | 110 | + Line line2 = new Line(centerX, sceneHeight * 0.1, centerX + sceneWidth * 0.03, sceneHeight * 0.22); | 
|  | 111 | + Text text = new Text(limit + (sceneWidth * 0.2), sceneHeight * 0.1, "Y"); | 
|  | 112 | + text.setFont(Font.font(fontSize)); | 
|  | 113 | + pane.getChildren().addAll(line1, line2, text); | 
|  | 114 | + } | 
|  | 115 | + | 
|  | 116 | + private String getXAxisLabel(double x) { | 
|  | 117 | + if (isRoughlyEqual(x, 0)) { | 
|  | 118 | + return "0"; | 
|  | 119 | + } else if (isRoughlyEqual(x, 50)) { | 
|  | 120 | + return "π"; | 
|  | 121 | + } else if (isRoughlyEqual(x, -50)) { | 
|  | 122 | + return "-π"; | 
|  | 123 | + } else if (isRoughlyEqual(x, 100)) { | 
|  | 124 | + return "2π"; | 
|  | 125 | + } else if (isRoughlyEqual(x, -100)) { | 
|  | 126 | + return "-2π"; | 
|  | 127 | + } | 
|  | 128 | + | 
|  | 129 | + return ""; | 
|  | 130 | + | 
|  | 131 | + } | 
|  | 132 | + | 
|  | 133 | + private boolean isRoughlyEqual(double a, double b) { | 
|  | 134 | + return a - b < 0.01 && a - b > -0.01; | 
|  | 135 | + } | 
|  | 136 | + | 
| 17 | 137 | } | 
|  | 138 | + | 
0 commit comments