From 93adc494c2d046f553be386221e366448d97389d Mon Sep 17 00:00:00 2001 From: wompmacho Date: Tue, 3 Nov 2020 14:59:03 -0500 Subject: [PATCH] add initial files added files from own repo, updated readme --- Controller.java | 205 ++++++++++++++++++++++++++++++++++++++++++++++++ Main.java | 27 +++++++ README.md | 11 ++- scene.fxml | 39 +++++++++ style.css | 19 +++++ 5 files changed, 299 insertions(+), 2 deletions(-) create mode 100644 Controller.java create mode 100644 Main.java create mode 100644 scene.fxml create mode 100644 style.css diff --git a/Controller.java b/Controller.java new file mode 100644 index 0000000..915b557 --- /dev/null +++ b/Controller.java @@ -0,0 +1,205 @@ +package fractalTreeDraw; + +import javafx.event.ActionEvent; +import javafx.fxml.FXML; +import javafx.fxml.Initializable; +import javafx.scene.canvas.Canvas; +import javafx.scene.canvas.GraphicsContext; +import javafx.scene.control.CheckBox; +import javafx.scene.control.Slider; +import javafx.scene.control.TextField; +import javafx.scene.control.Tooltip; +import javafx.scene.input.KeyCode; +import javafx.scene.input.KeyEvent; +import javafx.scene.input.MouseEvent; +import javafx.scene.layout.AnchorPane; +import javafx.scene.paint.Color; +import javafx.scene.shape.StrokeLineCap; + +import java.net.URL; +import java.util.ResourceBundle; +import java.util.concurrent.TimeUnit; + +public class Controller extends Canvas implements Initializable { + + @FXML + private Canvas CANVAS = new Canvas(); + + @FXML + private AnchorPane ANCHORPANE = new AnchorPane(); + + @FXML + private Slider ANGLE_SLIDER = new Slider(); + + @FXML + private Slider LENGTH_SLIDER = new Slider(); + + @FXML + private TextField TEXTFIELD = new TextField(); + + @FXML + private CheckBox CHECKBOX_RANDOM = new CheckBox(); + + private GraphicsContext GRAPHICSCONTEXT; + private double ANGLE = 25; + private double TRUNK_LENGTH = 165; + private double TRUNK_WIDTH = 15; + private double DEPTH = 10; + private double RIGHT_BRANCH_RANDOM_NUMBER = 1; + private double LEFT_BRANCH_RANDOM_NUMBER = 1; + //private double GOLDEN_RATIO = (1 - Math.sqrt(5)) / 2; + + // Clears canvas, moves to drawing position, calls branch(), moves back to start + private void drawFractalTree(double TRUNK_LENGTH, double TRUNK_WIDTH, double DEPTH) { + + // set center translation + double width = CANVAS.getWidth(); + double height = CANVAS.getHeight(); + + // Clear Canvas + GRAPHICSCONTEXT.clearRect(0, 0, width, height); + + // move to Start position + GRAPHICSCONTEXT.translate(width / 2, height); + + // create tree + GRAPHICSCONTEXT.setLineWidth(1); + branch(TRUNK_LENGTH, TRUNK_WIDTH, DEPTH); + + // return to Start + GRAPHICSCONTEXT.translate(0, TRUNK_LENGTH); + + // return to 0,0 + GRAPHICSCONTEXT.translate(-(width / 2), -height); + } + + // draws branches + private void branch(double TRUNK_LENGTH, double TRUNK_WIDTH, double DEPTH) { + + // Set trunk width + GRAPHICSCONTEXT.setLineWidth(TRUNK_WIDTH); + + GRAPHICSCONTEXT.setLineCap(StrokeLineCap.ROUND); + + // Set color based on trunkSize + if (DEPTH <= 2) { + GRAPHICSCONTEXT.setStroke(Color.rgb(0, 50, 0)); + } else { + GRAPHICSCONTEXT.setStroke(Color.rgb(50, 25, 0)); + } + + // draw line + GRAPHICSCONTEXT.strokeLine(0, 0, 0, -TRUNK_LENGTH); + + // translate to end of line drawn + GRAPHICSCONTEXT.translate(0, -TRUNK_LENGTH); + + // return if at end of depth + if (DEPTH < 1) { + GRAPHICSCONTEXT.setStroke(Color.rgb(50, 150, 0)); + GRAPHICSCONTEXT.strokeOval(-TRUNK_WIDTH, -TRUNK_WIDTH, 5, 10); + return; + } + + // Right Branch + GRAPHICSCONTEXT.rotate(ANGLE * RIGHT_BRANCH_RANDOM_NUMBER); + branch(TRUNK_LENGTH * 2/3, TRUNK_WIDTH * 2/3, DEPTH - 1); + GRAPHICSCONTEXT.translate(0, TRUNK_LENGTH * 2/3); + GRAPHICSCONTEXT.rotate(-ANGLE * RIGHT_BRANCH_RANDOM_NUMBER); + + // Left Branch + GRAPHICSCONTEXT.rotate(-ANGLE * LEFT_BRANCH_RANDOM_NUMBER); + branch(TRUNK_LENGTH * 2/3, TRUNK_WIDTH * 2/3, DEPTH - 1); + GRAPHICSCONTEXT.translate(0, TRUNK_LENGTH * 2/3); + GRAPHICSCONTEXT.rotate(ANGLE * LEFT_BRANCH_RANDOM_NUMBER); + + } + + private void sleep(int i) { + try { + TimeUnit.MICROSECONDS.sleep(100); + } catch (Exception e) { + e.printStackTrace(); + } + } + + public void handleKeyPressed(KeyEvent keyEvent) { + //System.out.println(keyEvent.getCode()); + if (keyEvent.getCode().equals(KeyCode.ENTER)) { + + try { + double MESSAGE = Integer.parseInt(TEXTFIELD.getText()); + DEPTH = MESSAGE; + drawFractalTree(TRUNK_LENGTH, TRUNK_WIDTH, DEPTH); + } catch (NumberFormatException nfe) { + TEXTFIELD.setText("# please"); + System.out.println("NumberFormatException: " + nfe.getMessage()); + } + } + } + + public void handleMouseClicked(MouseEvent mouseEvent) { + TEXTFIELD.setText("Children: " + DEPTH); + + drawFractalTree(TRUNK_LENGTH, TRUNK_WIDTH, DEPTH); + System.out.println("Mouse click"); + } + + public void handleSliderDrag(MouseEvent mouseEvent) { + ANGLE = ANGLE_SLIDER.getValue(); + TRUNK_LENGTH = LENGTH_SLIDER.getValue(); + drawFractalTree(TRUNK_LENGTH, TRUNK_WIDTH, DEPTH); + System.out.println("DRAGGED. Angle :" + ANGLE + "| LENGTH: " + TRUNK_LENGTH); + } + + public void handleCheckBox(ActionEvent event) { + + // If box checked + if (CHECKBOX_RANDOM.isSelected()) { + CHECKBOX_RANDOM.setText("Asymmetrical"); + randomNumber(); + System.out.println("Asymmetrical: " + RIGHT_BRANCH_RANDOM_NUMBER + "|" + LEFT_BRANCH_RANDOM_NUMBER); + } else { + CHECKBOX_RANDOM.setText("Symmetrical"); + RIGHT_BRANCH_RANDOM_NUMBER = 1; + LEFT_BRANCH_RANDOM_NUMBER = 1; + ANGLE = ANGLE_SLIDER.getValue(); + System.out.println("Binary tree selected"); + } + drawFractalTree(TRUNK_LENGTH, TRUNK_WIDTH, DEPTH); + } + + private void randomNumber() { + // define the range + double min = 1; + double max = Math.PI; + double range = max - min + 1; + + // generate random number within range + RIGHT_BRANCH_RANDOM_NUMBER = (Math.random() * range) + min; + LEFT_BRANCH_RANDOM_NUMBER = (Math.random() * range) + min; + } + + @Override + public void initialize(URL url, ResourceBundle resourceBundle) { + // Set angle slider Defaults + ANGLE_SLIDER.setMax(90); + ANGLE_SLIDER.setValue(25); + ANGLE_SLIDER.setTooltip(new Tooltip("0-180")); + + // Set length slider Defaults + LENGTH_SLIDER.setMax(1000); + LENGTH_SLIDER.setValue(165); + LENGTH_SLIDER.setTooltip(new Tooltip("0-1000")); + + // Tooltip for depth + Tooltip tip = new Tooltip("Careful... this is recursive..."); + TEXTFIELD.setTooltip(tip); + + // Resizable Canvas + CANVAS.widthProperty().bind(ANCHORPANE.widthProperty()); + CANVAS.heightProperty().bind(ANCHORPANE.heightProperty()); + GRAPHICSCONTEXT = CANVAS.getGraphicsContext2D(); + System.out.println("INIT"); + } +} \ No newline at end of file diff --git a/Main.java b/Main.java new file mode 100644 index 0000000..3dc8c1c --- /dev/null +++ b/Main.java @@ -0,0 +1,27 @@ +package fractalTreeDraw; + +import javafx.application.Application; +import javafx.fxml.FXMLLoader; +import javafx.scene.Parent; +import javafx.scene.Scene; +import javafx.stage.Stage; + +public class Main extends Application { + + @Override + public void start(Stage stage) throws Exception { + Parent root = FXMLLoader.load(getClass().getResource("scene.fxml")); + root.getStylesheets().add(getClass().getResource("style.css").toExternalForm()); + stage.setTitle("Fractal Tree Viewer"); + stage.setScene(new Scene(root)); + stage.show(); + } + + /** + * @param args the command line arguments + */ + public static void main(String[] args) { + launch(args); + } + +} \ No newline at end of file diff --git a/README.md b/README.md index feed42b..69c1224 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,9 @@ -# fractal-tree-draw -Simple Java application that demonstrates recursion by visualizing a fractal tree. +# Fractal Tree Viewer + +This is a simple Java application that demonstrates recursion by visualizing a fractal tree. It takes in an input for +length, angle and the number of child nodes and draws to a canvas. These inputs can then be manipulated by the sliders +and text field. It utilizes Java, JavaFX, FXML and CSS. + +// TODO: +make object oriented for multiple tree and shape types +remove canvas from controller so that we can resize canvas to parent but also draw on init \ No newline at end of file diff --git a/scene.fxml b/scene.fxml new file mode 100644 index 0000000..9879596 --- /dev/null +++ b/scene.fxml @@ -0,0 +1,39 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/style.css b/style.css new file mode 100644 index 0000000..6780323 --- /dev/null +++ b/style.css @@ -0,0 +1,19 @@ +#ANCHORPANE{ +-fx-background-color: #87ceeb; +} + +#BRANCH_ANGLE_LABEL{ +-fx-color: white; +} + +.slider{ +-fx-color: blue; +} + +.slider .axis .axis-tick-mark{ +-fx-stroke: green; +} + +.slider .axis .axis-minor-tick-mark { + -fx-stroke: grey; +} \ No newline at end of file