diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000000000000000000000000000000000000..94a25f7f4cb416c083d265558da75d457237d671 --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ +<?xml version="1.0" encoding="UTF-8"?> +<project version="4"> + <component name="VcsDirectoryMappings"> + <mapping directory="$PROJECT_DIR$" vcs="Git" /> + </component> +</project> \ No newline at end of file diff --git a/src/main/java/org/example/chaosgame/Main.java b/src/main/java/org/example/chaosgame/Main.java index c053b4bfc7cf7007734026bad2e4e9e45fa4a8af..2e188dd5c1e626f16eed47f1693d428d4f341e21 100644 --- a/src/main/java/org/example/chaosgame/Main.java +++ b/src/main/java/org/example/chaosgame/Main.java @@ -1,5 +1,10 @@ package org.example.chaosgame; +/** + * Main class for the application. + * This is the entry point for the application. + * It delegates the application start to the MainApp class. + */ public class Main { public static void main(String[] args) { MainApp.main(args); diff --git a/src/main/java/org/example/chaosgame/MainApp.java b/src/main/java/org/example/chaosgame/MainApp.java index e27382c6cafc34072b54d37b911fb616a6c4d7aa..e4c3ae764236b875119446a6909722ef9cbfd68a 100644 --- a/src/main/java/org/example/chaosgame/MainApp.java +++ b/src/main/java/org/example/chaosgame/MainApp.java @@ -1,5 +1,6 @@ package org.example.chaosgame; +import java.util.Objects; import javafx.application.Application; import javafx.scene.Scene; import javafx.scene.layout.StackPane; @@ -8,12 +9,14 @@ import org.example.chaosgame.controller.ChaosGameController; import org.example.chaosgame.controller.ExploreGameController; import org.example.chaosgame.controller.PageController; -import java.util.Objects; - - +/** + * This is the main class for the JavaFX application. + * It sets up the primary stage and the main pane. + * It also sets up the controllers. + */ public class MainApp extends Application { @Override - public void start(Stage primaryStage) throws Exception { + public void start(Stage primaryStage) { StackPane mainPane = new StackPane(); ExploreGameController exploreGameController = new ExploreGameController(); @@ -23,7 +26,8 @@ public class MainApp extends Application { Scene scene = new Scene(mainPane, 1200, 800); mainPane.prefWidthProperty().bind(scene.widthProperty()); mainPane.prefHeightProperty().bind(scene.heightProperty()); - scene.getStylesheets().add(Objects.requireNonNull(getClass().getResource("/global.css")).toExternalForm()); + scene.getStylesheets().add(Objects.requireNonNull( + getClass().getResource("/global.css")).toExternalForm()); primaryStage.setMinWidth(800); primaryStage.setMinHeight(600); diff --git a/src/main/java/org/example/chaosgame/controller/ChaosGameController.java b/src/main/java/org/example/chaosgame/controller/ChaosGameController.java index f35c5b7893d0f580b2138992730dbbea115a634b..df747d710cc1e611b2c646f39f101b47cd310b5d 100644 --- a/src/main/java/org/example/chaosgame/controller/ChaosGameController.java +++ b/src/main/java/org/example/chaosgame/controller/ChaosGameController.java @@ -1,32 +1,43 @@ package org.example.chaosgame.controller; +import java.io.File; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; +import java.util.Optional; import javafx.scene.canvas.Canvas; -import javafx.scene.control.*; - +import javafx.scene.control.TextField; import javafx.scene.layout.StackPane; import javafx.scene.paint.Color; import javafx.stage.FileChooser; import javafx.util.Pair; -import org.example.chaosgame.controller.observer.Observer; -import org.example.chaosgame.controller.observer.Subject; -import org.example.chaosgame.controller.observer.GameController; -import org.example.chaosgame.model.chaos.*; +import org.example.chaosgame.controller.interfaces.GameController; +import org.example.chaosgame.controller.interfaces.Observer; +import org.example.chaosgame.controller.interfaces.Subject; +import org.example.chaosgame.model.chaos.ChaosGame; +import org.example.chaosgame.model.chaos.ChaosGameDescription; +import org.example.chaosgame.model.chaos.ChaosGameDescriptionFactory; +import org.example.chaosgame.model.chaos.ChaosGameFileHandler; +import org.example.chaosgame.model.chaos.ChaosGameType; import org.example.chaosgame.model.linalg.Complex; -import org.example.chaosgame.model.linalg.Matrix2x2; import org.example.chaosgame.model.linalg.Vector2D; import org.example.chaosgame.model.transformations.AffineTransform2D; import org.example.chaosgame.model.transformations.JuliaTransform; import org.example.chaosgame.model.transformations.Transform2D; import org.example.chaosgame.view.ChaosPage; -import org.example.chaosgame.view.components.*; - -import java.io.File; -import java.io.IOException; -import java.util.ArrayList; -import java.util.List; -import java.util.Objects; -import java.util.Optional; - +import org.example.chaosgame.view.components.AlertUtility; +import org.example.chaosgame.view.components.CreateFractalDialog; +import org.example.chaosgame.view.components.MinMaxDialog; + +/** + * Controller class for the chaos game. + * Handles the logic from the view to the model. + * + * <p>Implements the Observer and Subject interfaces for the observer pattern. + * + * <p>Implements the GameController interface. + */ public class ChaosGameController implements Observer, Subject, GameController { private final ChaosGame chaosGame; private final ChaosPage chaosPage; @@ -35,6 +46,13 @@ public class ChaosGameController implements Observer, Subject, GameController { private static final int HEIGHT = 800; private Canvas canvas; + /** + * Constructor for the ChaosGameController. + * + * <p>Initializes the ChaosGame and ChaosPage. + * Register the ChaosGame as an observer. + * + */ public ChaosGameController() { this.chaosGame = ChaosGame.getInstance(Objects.requireNonNull( ChaosGameDescriptionFactory.get(ChaosGameType.JULIA)), @@ -45,18 +63,28 @@ public class ChaosGameController implements Observer, Subject, GameController { chaosGame.registerObserver(this); } - public ChaosGame getChaosGame() { - return chaosGame; - } - public ChaosPage getGamePage() { return chaosPage; } + public void setCanvas(Canvas canvas) { + this.canvas = canvas; + } + + /** + * Method responsible for changing ChaosGameDescription. + * + * @param description Description of the chaos game + */ private void updateChaosGame(ChaosGameDescription description) { chaosGame.setChaosGameDescription(description); } + /** + * Method for selecting a new ChaosGameDescription. + * + * @param selectedGame Name of the selected game + */ public void gameSelection(String selectedGame) { try { ChaosGameType gameType = ChaosGameType.valueOf(selectedGame); @@ -66,6 +94,12 @@ public class ChaosGameController implements Observer, Subject, GameController { } } + /** + * Method for running the chaos game. + * Validates the input from the user. + * + * @param stepsField TextField for the number of steps + */ public void runStepsValidation(TextField stepsField) { String input = stepsField.getText(); try { @@ -80,10 +114,17 @@ public class ChaosGameController implements Observer, Subject, GameController { } catch (NumberFormatException ex) { stepsField.clear(); stepsField.getStyleClass().add("text-field-invalid"); - AlertUtility.showErrorDialog("Invalid input", "Please enter a number between 1 - 10 000 000."); + AlertUtility.showErrorDialog( + "Invalid input", "Please enter a number between 1 - 10 000 000."); } } + /** + * Method for setting the min and max coordinates for the chaos game. + * + * <p>Opens a dialog for the user to enter the coordinates. + * + */ public void setMaxMinCoords() { MinMaxDialog dialog = new MinMaxDialog(); Optional<List<String>> result = dialog.showAndWait(); @@ -91,26 +132,37 @@ public class ChaosGameController implements Observer, Subject, GameController { if (result.isPresent()) { try { List<String> coords = result.get(); - Vector2D min = new Vector2D(Double.parseDouble(coords.get(0)), Double.parseDouble(coords.get(1))); - Vector2D max = new Vector2D(Double.parseDouble(coords.get(2)), Double.parseDouble(coords.get(3))); + Vector2D min = new Vector2D(Double.parseDouble(coords.get(0)), + Double.parseDouble(coords.get(1))); + Vector2D max = new Vector2D(Double.parseDouble(coords.get(2)), + Double.parseDouble(coords.get(3))); if (validateCoordinates(min) && validateCoordinates(max)) { updateChaosGame(new ChaosGameDescription( min, max, chaosGame.getDescription().getTransforms())); } else { - AlertUtility.showErrorDialog("Invalid input", "Please enter a double between -50 and 50."); + AlertUtility.showErrorDialog("Invalid input", + "Please enter a double between -50 and 50."); } } catch (NumberFormatException e) { - AlertUtility.showErrorDialog("Invalid input", "Please enter a valid number."); + AlertUtility.showErrorDialog("Invalid input", + "Please enter a valid number."); } catch (IndexOutOfBoundsException e) { - AlertUtility.showErrorDialog("Invalid input", "Please enter all coordinates."); + AlertUtility.showErrorDialog("Invalid input", + "Please enter all coordinates."); } } } + /** + * Method for validating the coordinates. + * + * @param vector Vector2D with the coordinates + * @return boolean True if the coordinates are valid, false otherwise + */ private boolean validateCoordinates(Vector2D vector) { try { System.out.println("parsing" + vector.getX() + " " + vector.getY()); @@ -125,9 +177,17 @@ public class ChaosGameController implements Observer, Subject, GameController { return true; } + /** + * Method for opening a file with a chaos game description. + * + * <p>Opens a file chooser dialog for the user to select a file. + * Read the file and update the chaos game. + * + */ public void openFromFile() { FileChooser fileChooser = new FileChooser(); - fileChooser.getExtensionFilters().add(new FileChooser.ExtensionFilter("TXT files (*.txt)", "*.txt")); + fileChooser.getExtensionFilters().add( + new FileChooser.ExtensionFilter("TXT files (*.txt)", "*.txt")); File selectedFile = fileChooser.showOpenDialog(null); if (selectedFile != null) { @@ -142,11 +202,12 @@ public class ChaosGameController implements Observer, Subject, GameController { } } - public void updateFractalColor(Color color) { - chaosPage.setFractalColor(color); - chaosPage.updateCanvas(chaosGame.getCanvas()); - } - + /** + * Method for creating a new fractal. + * + * <p>Opens a dialog for the user to create a new fractal. + * + */ public void createOwnFractal() { CreateFractalDialog dialog = new CreateFractalDialog(); Optional<Object> result = dialog.showAndWait(); @@ -168,7 +229,8 @@ public class ChaosGameController implements Observer, Subject, GameController { double imaginary = Double.parseDouble(userInput.getValue()); if (real < -1 || real > 1 || imaginary < -1 || imaginary > 1) { - AlertUtility.showErrorDialog("Invalid input", "Please enter a double between -1 and 1. No letters are allowed."); + AlertUtility.showErrorDialog("Invalid input", + "Please enter a double between -1 and 1. No letters are allowed."); } else { updateChaosGame(new ChaosGameDescription( new Vector2D(-1.6, -1), @@ -182,7 +244,8 @@ public class ChaosGameController implements Observer, Subject, GameController { double imaginary = Double.parseDouble(userInput.getValue()); if (real < -1 || real > 1 || imaginary < -1 || imaginary > 1) { - AlertUtility.showErrorDialog("Invalid input", "Please enter a double between -1 and 1. No letters are allowed."); + AlertUtility.showErrorDialog("Invalid input", + "Please enter a double between -1 and 1. No letters are allowed."); } else { updateChaosGame(new ChaosGameDescription( new Vector2D(-1.6, -1), @@ -193,29 +256,63 @@ public class ChaosGameController implements Observer, Subject, GameController { } } + @Override + public void setBind(StackPane mainPane) { + canvas.widthProperty().bind(mainPane.widthProperty().multiply(0.85)); + canvas.heightProperty().bind(mainPane.heightProperty().multiply(0.85)); + mainPane.heightProperty().addListener((observable, oldValue, newValue) -> { + if (mainPane.getHeight() > 0 && mainPane.getWidth() > 0) { + chaosGame.notifyObservers(); + } + }); + mainPane.widthProperty().addListener((observable, oldValue, newValue) -> { + if (mainPane.getHeight() > 0 && mainPane.getWidth() > 0) { + chaosGame.notifyObservers(); + } + }); + } + + /** + * Method for resetting the chaos game. + */ public void resetGame() { chaosGame.resetTotalSteps(); - update(); + chaosPage.updateInformation(chaosGame.getDescription().getTransforms().getFirst(), + chaosGame.getTotalSteps(), + chaosGame.getDescription().getMinCoords(), + chaosGame.getDescription().getMaxCoords()); chaosPage.clearCanvas(); } @Override public void updateJuliaValue(String partType, double value) { - JuliaTransform juliaTransform = (JuliaTransform) chaosGame.getDescription().getTransforms().getFirst(); - double realPart = partType.equals("real") ? value : juliaTransform.getComplex().getX(); - double imaginaryPart = partType.equals("imaginary") ? value : juliaTransform.getComplex().getY(); + JuliaTransform juliaTransform = + (JuliaTransform) chaosGame.getDescription().getTransforms().getFirst(); + double realPart = partType.equals("real") + ? value : juliaTransform.getComplex().getX(); + double imaginaryPart = partType.equals("imaginary") + ? value : juliaTransform.getComplex().getY(); updateChaosGame(new ChaosGameDescription( - new Vector2D(chaosGame.getDescription().getMinCoords().getX(), chaosGame.getDescription().getMinCoords().getY()), - new Vector2D(chaosGame.getDescription().getMaxCoords().getX(), chaosGame.getDescription().getMaxCoords().getY()), + new Vector2D(chaosGame.getDescription().getMinCoords().getX(), + chaosGame.getDescription().getMinCoords().getY()), + new Vector2D(chaosGame.getDescription().getMaxCoords().getX(), + chaosGame.getDescription().getMaxCoords().getY()), List.of(new JuliaTransform(new Complex(realPart, imaginaryPart), 1)))); chaosGame.setTotalSteps(chaosGame.getSteps()); chaosGame.runSteps(); } + /** + * Method for saving the fractal to a file. + * + * <p>Opens a file chooser dialog for the user to select a file. + * Write the fractal to the file using FileHandler class. + */ public void saveFractal() { FileChooser fileChooser = new FileChooser(); - fileChooser.getExtensionFilters().add(new FileChooser.ExtensionFilter("TXT files (*.txt)", "*.txt")); + fileChooser.getExtensionFilters().add( + new FileChooser.ExtensionFilter("TXT files (*.txt)", "*.txt")); File selectedFile = fileChooser.showSaveDialog(null); if (selectedFile != null) { @@ -229,11 +326,21 @@ public class ChaosGameController implements Observer, Subject, GameController { } } + @Override + public void updateFractalColor(Color color) { + chaosPage.setFractalColor(color); + chaosPage.updateCanvas(chaosGame.getCanvas()); + } + @Override public void homeButtonClicked() { notifyObservers(); } + /** + * Method for updating the view. + * Notified from the ChaosGame (model). + */ @Override public void update() { chaosPage.updateInformation(chaosGame.getDescription().getTransforms().getFirst(), @@ -243,42 +350,33 @@ public class ChaosGameController implements Observer, Subject, GameController { chaosPage.updateCanvas(chaosGame.getCanvas()); } + /** + * Method for registering observers. + * + * @param observer Observer to register + */ @Override public void registerObserver(Observer observer) { pageObservers.add(observer); } + /** + * Method for removing observers. + * + * @param observer Observer to remove + */ @Override public void removeObserver(Observer observer) { pageObservers.remove(observer); } + /** + * Method for notifying observers. + */ @Override public void notifyObservers() { for (Observer pageObserver : pageObservers) { pageObserver.update(); } } - - public void setCanvas(Canvas canvas) { - this.canvas = canvas; - } - - public void setBind(StackPane mainPane) { - canvas.widthProperty().bind(mainPane.widthProperty().multiply(0.85)); - canvas.heightProperty().bind(mainPane.heightProperty().multiply(0.85)); - mainPane.heightProperty().addListener((observable, oldValue, newValue) -> { - // Update the canvas height here - if (mainPane.getHeight() > 0 && mainPane.getWidth() > 0) { - chaosGame.notifyObservers(); - } - }); - // Add a change listener to the width property - mainPane.widthProperty().addListener((observable, oldValue, newValue) -> { - // Update the canvas width here - if (mainPane.getHeight() > 0 && mainPane.getWidth() > 0) { - chaosGame.notifyObservers(); - } - }); - } } diff --git a/src/main/java/org/example/chaosgame/controller/ExploreGameController.java b/src/main/java/org/example/chaosgame/controller/ExploreGameController.java index c06685145d7ab2f3f35a28c6df0cdf3782ba2431..90a1ba0998309b7cc4be8abf2980f6b85b7ea080 100644 --- a/src/main/java/org/example/chaosgame/controller/ExploreGameController.java +++ b/src/main/java/org/example/chaosgame/controller/ExploreGameController.java @@ -1,36 +1,31 @@ package org.example.chaosgame.controller; -import javafx.concurrent.Task; -import javafx.event.ActionEvent; +import java.util.ArrayList; +import java.util.List; import javafx.scene.canvas.Canvas; import javafx.scene.input.MouseEvent; import javafx.scene.input.ScrollEvent; -import javafx.scene.input.ZoomEvent; import javafx.scene.layout.StackPane; import javafx.scene.paint.Color; -import javafx.scene.transform.Transform; - -import org.example.chaosgame.controller.observer.Observer; -import org.example.chaosgame.controller.observer.Subject; -import org.example.chaosgame.controller.observer.GameController; +import org.example.chaosgame.controller.interfaces.GameController; +import org.example.chaosgame.controller.interfaces.Observer; +import org.example.chaosgame.controller.interfaces.Subject; import org.example.chaosgame.model.chaos.ChaosCanvas; -import org.example.chaosgame.model.chaos.ChaosGame; -import javafx.scene.Node; import org.example.chaosgame.model.chaos.ChaosGameDescription; import org.example.chaosgame.model.chaos.ExploreGame; import org.example.chaosgame.model.linalg.Complex; import org.example.chaosgame.model.linalg.Vector2D; import org.example.chaosgame.model.transformations.ExploreJulia; -import org.example.chaosgame.model.transformations.JuliaTransform; import org.example.chaosgame.model.transformations.Transform2D; import org.example.chaosgame.view.ExplorePage; -import java.util.ArrayList; -import java.util.List; -import java.util.Set; -import java.util.Vector; - - +/** + * Controller class for the ExploreGame. + * The controller is responsible for handling events from the view and updating the model. + * The controller is also responsible for updating the view when the model changes. + * + * <p>The controller implements the GameController, and is a Subject and Observer. + */ public class ExploreGameController implements Observer, Subject, GameController { private ExploreGame exploreGame; private final ExplorePage explorePage; @@ -39,23 +34,18 @@ public class ExploreGameController implements Observer, Subject, GameController private List<Transform2D> trans; private ChaosGameDescription description; private final List<Observer> pageObservers; - private Vector2D dragStart; private Vector2D dragStartTemp; - private double cumulativeScaleFactor = 1; - - private double mouseX; - private double mouseY; - private double scaleFactor; - private Task task; - private ExploreJulia exploreJulia; - private static final int WIDTH = 1200; private static final int HEIGHT = 800; + /** + * Constructor for ExploreGameController. + * Initializes the ExploreGame and ExplorePage. + */ public ExploreGameController() { - this.exploreJulia = new ExploreJulia(new Complex(-0.835, 0.2321)); + ExploreJulia exploreJulia = new ExploreJulia(new Complex(-0.835, 0.2321)); this.trans = List.of(exploreJulia); this.description = new ChaosGameDescription( new Vector2D(-1.6, -1), @@ -65,10 +55,18 @@ public class ExploreGameController implements Observer, Subject, GameController this.pageObservers = new ArrayList<>(); exploreGame.registerObserver(this); this.explorePage = new ExplorePage(this); -// exploreGame.exploreFractals(); -// updateExploreGame(); + } + public void setCanvas(Canvas canvas) { + this.canvas = canvas; } + + /** + * Method for handling mouse pressed events. + * Saves the starting position of the drag. + * + * @param event MouseEvent + */ public void mousePressed(MouseEvent event) { double mouseX = event.getX(); double mouseY = event.getY(); @@ -76,6 +74,12 @@ public class ExploreGameController implements Observer, Subject, GameController dragStartTemp = new Vector2D(mouseX, canvas.getHeight() - mouseY); } + /** + * Method for handling mouse dragged events. + * Moves the canvas based on the distance dragged. + * + * @param event MouseEvent + */ public void mouseDragged(MouseEvent event) { Vector2D dragEnd = new Vector2D(event.getX(), event.getY()); Vector2D dragDistance = dragEnd.subtract(dragStart); @@ -85,53 +89,62 @@ public class ExploreGameController implements Observer, Subject, GameController dragStart = dragEnd; } + + /** + * Method for handling mouse released events. + * Updates the position of the canvas based on the drag distance. + * + * @param event MouseEvent + */ public void mouseReleased(MouseEvent event) { - Vector2D dragDistance = new Vector2D(event.getX(), canvas.getHeight() - event.getY()).subtract(dragStartTemp); -// Reset the position where the drag started + Vector2D dragDistance = new Vector2D(event.getX(), + canvas.getHeight() - event.getY()).subtract(dragStartTemp); Vector2D fractalRange = description.getMaxCoords().subtract(description.getMinCoords()); - Vector2D adjustedDragDistance = dragDistance.multiply(fractalRange).divide(new Vector2D(canvas.getWidth(), canvas.getHeight())); + Vector2D adjustedDragDistance = dragDistance.multiply(fractalRange) + .divide(new Vector2D(canvas.getWidth(), canvas.getHeight())); Vector2D newMinCoords = description.getMinCoords().subtract(adjustedDragDistance); Vector2D newMaxCoords = description.getMaxCoords().subtract(adjustedDragDistance); description = new ChaosGameDescription(newMinCoords, newMaxCoords, trans); -// /* exploreGame.setGameDescription(new ChaosGameDescription(newMinCoords, newMaxCoords, trans), -// (int) canvas.getWidth(),(int) canvas.getHeight());*/ -// exploreGame = new ExploreGame(description, (int) canvas.getWidth(),(int) canvas.getHeight()); -// exploreGame.exploreFractals(); -// this.chaosCanvas = exploreGame.getCanvas(); - updateExplorePage(); -// description = exploreGame.getDescription(); } + + /** + * Method for handling zoom button clicks. + * Zooms in or out based on the scale factor. + * + * @param scaleFactor Scale factor + */ public void zoomButtonClicked(double scaleFactor) { cumulativeScaleFactor *= scaleFactor; - Vector2D canvasCenter = chaosCanvas.transformIndicesToCoords(chaosCanvas.getWidth() / 2, chaosCanvas.getHeight() / 2); - Vector2D newMinCoords = canvasCenter.subtract(canvasCenter.subtract(description.getMinCoords()).scale(scaleFactor)); - Vector2D newMaxCoords = canvasCenter.add(description.getMaxCoords().subtract(canvasCenter).scale(scaleFactor)); + Vector2D canvasCenter = chaosCanvas.transformIndicesToCoords( + chaosCanvas.getWidth() / 2, chaosCanvas.getHeight() / 2); + Vector2D newMinCoords = canvasCenter.subtract( + canvasCenter.subtract(description.getMinCoords()).scale(scaleFactor)); + Vector2D newMaxCoords = canvasCenter.add( + description.getMaxCoords().subtract(canvasCenter).scale(scaleFactor)); description = new ChaosGameDescription(newMinCoords, newMaxCoords, trans); updateExplorePage(); -// description = exploreGame.getDescription(); } - private void stopTask() { - if (task != null) { - task.cancel(); - task = null; - } - } - public void onScroll(ScrollEvent event) throws Exception { -// stopTask(); - mouseX = event.getX(); - mouseY = event.getY(); + /** + * Method for handling scroll events. + * Zooms in or out based on the scroll direction. + * + * @param event ScrollEvent + */ + public void onScroll(ScrollEvent event) { + double mouseX = event.getX(); + double mouseY = event.getY(); double scaleBase = event.isControlDown() ? 2 : 1.1; - scaleFactor = 1; + double scaleFactor = 1; double zoomInLimit = Math.pow(10, -15); double zoomOutLimit = 8; - if(event.getDeltaY() > 0 && cumulativeScaleFactor > zoomInLimit){ + if (event.getDeltaY() > 0 && cumulativeScaleFactor > zoomInLimit) { // Zoom in scaleFactor = 1 / scaleBase; - }else if(event.getDeltaY() < 0 && cumulativeScaleFactor < zoomOutLimit){ + } else if (event.getDeltaY() < 0 && cumulativeScaleFactor < zoomOutLimit) { // Zoom out scaleFactor = scaleBase; } @@ -145,7 +158,6 @@ public class ExploreGameController implements Observer, Subject, GameController canvas.setScaleX(canvas.getScaleX() * scaleFactor); canvas.setScaleY(canvas.getScaleY() * scaleFactor); - double newTranslateX = (middleMouseX - translateX) * (scaleFactor - 1); double newTranslateY = (middleMouseY - translateY) * (scaleFactor - 1); double setTranslateX = translateX - newTranslateX; @@ -153,110 +165,61 @@ public class ExploreGameController implements Observer, Subject, GameController canvas.setTranslateX(setTranslateX); canvas.setTranslateY(setTranslateY); - Vector2D canvasCenter = chaosCanvas.transformIndicesToCoords((int) mouseX, (int) mouseY); - Vector2D newMinCoords = canvasCenter.subtract(canvasCenter.subtract(description.getMinCoords()).scale(scaleFactor)); - Vector2D newMaxCoords = canvasCenter.add(description.getMaxCoords().subtract(canvasCenter).scale(scaleFactor)); - -// updateExploreGame(newMinCoords, newMaxCoords,trans); -// juliaTask = new SetJuliaTask(real, img, exploreGame, explorePage); + Vector2D newMinCoords = canvasCenter.subtract( + canvasCenter.subtract(description.getMinCoords()).scale(scaleFactor)); + Vector2D newMaxCoords = canvasCenter.add( + description.getMaxCoords().subtract(canvasCenter).scale(scaleFactor)); -// task = exploreGame.call(canvas); description = new ChaosGameDescription(newMinCoords, newMaxCoords, trans); updateExplorePage(); -// description = exploreGame.getDescription(); } -// private class SetJuliaTask extends Task<Task> { -// private final double real; -// private final double img; -// private final ExploreGame exploreGame; -// private final ExplorePage explorePage; -// -// public SetJuliaTask(double real, double img, ExploreGame exploreGame, ExplorePage explorePage) { -// this.real = real; -// this.img = img; -// this.exploreGame = exploreGame; -// this.explorePage = explorePage; -// } -// -//// @Override -// protected Task call() throws Exception { -//// exploreGame.setJuliaValue(real, img); -// exploreGame.exploreFractals(); -// explorePage.updateCanvas(this.exploreGame.getCanvas()); -// -// return this; -// } -// } - - private void updateExplorePage() { -// System.out.println("Update Explore Game"); -// exploreGame.setExploreGame(description, (int) canvas.getWidth(),(int) canvas.getHeight()); exploreGame.removeObserver(this); - exploreGame = new ExploreGame(description, (int) canvas.getWidth(),(int) canvas.getHeight()); + exploreGame = new ExploreGame(description, (int) canvas.getWidth(), (int) canvas.getHeight()); exploreGame.registerObserver(this); this.chaosCanvas = exploreGame.getCanvas(); exploreGame.exploreFractals(); explorePage.updateCanvas(this.chaosCanvas); -// explorePage.updateCanvas(this.chaosCanvas); + canvas.setTranslateX(0); canvas.setTranslateY(0); canvas.setScaleY(1); canvas.setScaleX(1); } + public void homeButtonClicked() { notifyObservers(); } + public ExplorePage getGamePage() { return explorePage; } - public void updateFractalColor(Color color){ - explorePage.setFractalColor(color); - explorePage.updateCanvas(exploreGame.getCanvas()); - } + /** + * Method for updating the fractal color. + * + * @param color New fractal color + */ @Override - public void update() { + public void updateFractalColor(Color color) { + explorePage.setFractalColor(color); explorePage.updateCanvas(exploreGame.getCanvas()); - explorePage.updateInformation(description.getTransforms().getFirst(), description.getMinCoords(), description.getMaxCoords()); - } - - @Override - public void registerObserver(Observer observer) { - pageObservers.add(observer); - } - - @Override - public void removeObserver(Observer observer) { - pageObservers.remove(observer); - } - - @Override - public void notifyObservers() { - for (Observer pageObserver : pageObservers) { - pageObserver.update(); - } } + /** + * Method for resetting the image. + * Resets the image to the default position and scale. + */ public void resetImage() { Vector2D newMinCoords = new Vector2D(-1.6, -1); Vector2D newMaxCoords = new Vector2D(1.6, 1); description = new ChaosGameDescription( newMinCoords, newMaxCoords, trans); -// exploreGame.removeObserver(this); -// exploreGame = new ExploreGame(description, (int) canvas.getWidth(),(int) canvas.getHeight()); -// exploreGame.registerObserver(this); -// updateExploreGame(description); cumulativeScaleFactor = 1; updateExplorePage(); -// description = exploreGame.getDescription(); - } - - public void setCanvas(Canvas canvas) { - this.canvas = canvas; } @Override @@ -269,7 +232,6 @@ public class ExploreGameController implements Observer, Subject, GameController updateExplorePage(); } }); - // Add a change listener to the width property mainPane.widthProperty().addListener((observable, oldValue, newValue) -> { // Update the canvas width here if (mainPane.getHeight() > 0 && mainPane.getWidth() > 0) { @@ -280,16 +242,57 @@ public class ExploreGameController implements Observer, Subject, GameController @Override public void updateJuliaValue(String partType, double value) { - ExploreJulia exploreTransform = (ExploreJulia) exploreGame.getDescription().getTransforms().getFirst(); - double realPart = partType.equals("real") ? value : exploreTransform.getComplex().getX(); - double imaginaryPart = partType.equals("imaginary") ? value : exploreTransform.getComplex().getY(); + ExploreJulia exploreTransform = + (ExploreJulia) exploreGame.getDescription().getTransforms().getFirst(); + double realPart = partType.equals("real") + ? value : exploreTransform.getComplex().getX(); + double imaginaryPart = partType.equals("imaginary") + ? value : exploreTransform.getComplex().getY(); trans = List.of(new ExploreJulia(new Complex(realPart, imaginaryPart))); description.setTransforms(trans); updateExplorePage(); -// exploreGame = new ExploreGame(description, (int) canvas.getWidth(),(int) canvas.getHeight()); -// this.chaosCanvas = exploreGame.getCanvas(); -// exploreGame.exploreFractals(); -// explorePage.updateCanvas(this.chaosCanvas); + } + + /** + * Method for updating the view. + * Notified from the model when the model changes. + */ + @Override + public void update() { + explorePage.updateCanvas(exploreGame.getCanvas()); + explorePage.updateInformation( + description.getTransforms().getFirst(), + description.getMinCoords(), description.getMaxCoords()); + } + + /** + * Method for registering an observer. + * + * @param observer Observer + */ + @Override + public void registerObserver(Observer observer) { + pageObservers.add(observer); + } + + /** + * Method for removing an observer. + * + * @param observer Observer + */ + @Override + public void removeObserver(Observer observer) { + pageObservers.remove(observer); + } + + /** + * Method for notifying observers. + */ + @Override + public void notifyObservers() { + for (Observer pageObserver : pageObservers) { + pageObserver.update(); + } } } diff --git a/src/main/java/org/example/chaosgame/controller/HomeController.java b/src/main/java/org/example/chaosgame/controller/HomeController.java index 065a28ecf08c011f16adb9b5698077d4484bc80f..8695475a5698cb6c6eb0f06d34b94fe70cb37ad8 100644 --- a/src/main/java/org/example/chaosgame/controller/HomeController.java +++ b/src/main/java/org/example/chaosgame/controller/HomeController.java @@ -9,30 +9,49 @@ import javafx.scene.text.Text; import javafx.util.Duration; import org.example.chaosgame.view.HomePage; +/** + * Controller for the home page. + * Handles mouse events for the home page. + */ public class HomeController { - private final HomePage homePage; + private final HomePage homePage; - public HomeController(PageController pageController) { - this.homePage = new HomePage(pageController, this); - } - - public HomePage getHomePage() { - return homePage; - } + /** + * Constructor for the HomeController. + * + * @param pageController the page controller + */ + public HomeController(PageController pageController) { + this.homePage = new HomePage(pageController, this); + } + public HomePage getHomePage() { + return homePage; + } - public void mouseEvent(EventType<MouseEvent> mouseEvent, MediaPlayer video, MediaView view, Text header, ColorAdjust colorAdjust, ColorAdjust headerAdjust) { - if (mouseEvent == MouseEvent.MOUSE_ENTERED) { - video.play(); - view.setEffect(colorAdjust); - header.setEffect(headerAdjust); - header.setOpacity(0.2); - } else { - video.seek(Duration.seconds(0)); - video.pause(); - view.setEffect(colorAdjust); - header.setEffect(headerAdjust); - header.setOpacity(1.0); - } + /** + * Handles mouse events for the home page. + * + * @param mouseEvent the mouse event + * @param video the video + * @param view the media view + * @param header the header text + * @param colorAdjust the color adjust effect + * @param headerAdjust the header adjust effect + */ + public void mouseEvent(EventType<MouseEvent> mouseEvent, MediaPlayer video, MediaView view, + Text header, ColorAdjust colorAdjust, ColorAdjust headerAdjust) { + if (mouseEvent == MouseEvent.MOUSE_ENTERED) { + video.play(); + view.setEffect(colorAdjust); + header.setEffect(headerAdjust); + header.setOpacity(0.2); + } else { + video.seek(Duration.seconds(0)); + video.pause(); + view.setEffect(colorAdjust); + header.setEffect(headerAdjust); + header.setOpacity(1.0); } + } } diff --git a/src/main/java/org/example/chaosgame/controller/PageController.java b/src/main/java/org/example/chaosgame/controller/PageController.java index f0816f295302143596f161234be5cbff0eb9dc85..e8883f59932f90e390439bb4d34d2c6be884f8c1 100644 --- a/src/main/java/org/example/chaosgame/controller/PageController.java +++ b/src/main/java/org/example/chaosgame/controller/PageController.java @@ -1,26 +1,38 @@ package org.example.chaosgame.controller; +import java.util.HashMap; +import java.util.Map; import javafx.scene.Node; import javafx.scene.layout.StackPane; -import org.example.chaosgame.controller.observer.Observer; +import org.example.chaosgame.controller.interfaces.Observer; import org.example.chaosgame.view.HomePage; -import java.util.HashMap; -import java.util.Map; - +/** + * Controller for the different pages in the application. + * + * <p>Implements the Observer interface to listen for changes in the game controllers. + */ public class PageController implements Observer { private final StackPane mainPane; private final Map<String, Node> pages = new HashMap<>(); private final ChaosGameController chaosGameController; private final ExploreGameController exploreGameController; private final HomePage homePage; - private final HomeController homeController; - public PageController(StackPane mainPane, ChaosGameController chaosGameController, ExploreGameController exploreGameController) { + /** + * Constructor for the PageController. + * Initializes the different pages and sets the main pane. + * + * @param mainPane the main pane + * @param chaosGameController the chaos game controller + * @param exploreGameController the explore game controller + */ + public PageController(StackPane mainPane, ChaosGameController chaosGameController, + ExploreGameController exploreGameController) { this.mainPane = mainPane; this.chaosGameController = chaosGameController; this.exploreGameController = exploreGameController; - this.homeController = new HomeController(this); + HomeController homeController = new HomeController(this); this.homePage = homeController.getHomePage(); this.homePage.setBind(mainPane); @@ -32,30 +44,55 @@ public class PageController implements Observer { exploreGameController.registerObserver(this); } - private void initPages(ChaosGameController chaosGameController, ExploreGameController exploreGameController) { + /** + * Initializes the different pages in the application. + * + * @param chaosGameController the chaos game controller + * @param exploreGameController the explore game controller + */ + private void initPages(ChaosGameController chaosGameController, + ExploreGameController exploreGameController) { pages.put("home", homePage); pages.put("chaos", chaosGameController.getGamePage()); pages.put("explore", exploreGameController.getGamePage()); goToPage("home"); } + /** + * Navigates to the specified page. + * Removes all children from the main pane and adds the specified page. + * + * @param page the page to navigate to + */ public void navigateToPage(Node page) { mainPane.getChildren().clear(); mainPane.getChildren().add(page); } + /** + * Navigates to the specified page. + * + * @param page the page to navigate to + */ public void goToPage(String page) { navigateToPage(pages.get(page)); } + /** + * Exits the application. + */ public void exitGame() { chaosGameController.removeObserver(this); exploreGameController.removeObserver(this); System.exit(0); } + /** + * Updates the page controller. + * Navigates to the home page. + */ @Override public void update() { - navigateToPage(pages.get("home")); + navigateToPage(pages.get("home")); } } \ No newline at end of file diff --git a/src/main/java/org/example/chaosgame/controller/interfaces/GameController.java b/src/main/java/org/example/chaosgame/controller/interfaces/GameController.java new file mode 100644 index 0000000000000000000000000000000000000000..7c29ebd4be12149da3dad240806c1eecbf30ff48 --- /dev/null +++ b/src/main/java/org/example/chaosgame/controller/interfaces/GameController.java @@ -0,0 +1,41 @@ +package org.example.chaosgame.controller.interfaces; + +import javafx.scene.layout.StackPane; +import javafx.scene.paint.Color; +import org.example.chaosgame.view.GamePage; + +/** + * Interface for the GameController. + */ +public interface GameController { + + GamePage getGamePage(); + + /** + * Method for binding the canvas to the main pane. + * + * @param mainPane Main pane of the application + */ + void setBind(StackPane mainPane); + + /** + * Method for updating the Julia value with slider components. + * + * @param partType Type of the part to update (real or imaginary) + * @param value New value for the part + */ + void updateJuliaValue(String partType, double value); + + /** + * Goes to HomePage. + */ + void homeButtonClicked(); + + /** + * Method to update color of the fractal. + * + * @param color the new color. + */ + void updateFractalColor(Color color); + +} diff --git a/src/main/java/org/example/chaosgame/controller/observer/Observer.java b/src/main/java/org/example/chaosgame/controller/interfaces/Observer.java similarity index 66% rename from src/main/java/org/example/chaosgame/controller/observer/Observer.java rename to src/main/java/org/example/chaosgame/controller/interfaces/Observer.java index 89101c7fce0d9cb3447d8b51b4825a346cd417c8..e20769649faa155b914b79bee914a6f32543018e 100644 --- a/src/main/java/org/example/chaosgame/controller/observer/Observer.java +++ b/src/main/java/org/example/chaosgame/controller/interfaces/Observer.java @@ -1,4 +1,4 @@ -package org.example.chaosgame.controller.observer; +package org.example.chaosgame.controller.interfaces; /** * Observer interface for the observer pattern. diff --git a/src/main/java/org/example/chaosgame/controller/observer/Subject.java b/src/main/java/org/example/chaosgame/controller/interfaces/Subject.java similarity index 78% rename from src/main/java/org/example/chaosgame/controller/observer/Subject.java rename to src/main/java/org/example/chaosgame/controller/interfaces/Subject.java index 3fc75be105233e2046208998fcfbcc1d85838caf..9c0605d4fb3e3c1a5a36c6f925b9ab060be5e63b 100644 --- a/src/main/java/org/example/chaosgame/controller/observer/Subject.java +++ b/src/main/java/org/example/chaosgame/controller/interfaces/Subject.java @@ -1,10 +1,12 @@ -package org.example.chaosgame.controller.observer; +package org.example.chaosgame.controller.interfaces; /** * Subject interface for the observer pattern. */ public interface Subject { void registerObserver(Observer observer); + void removeObserver(Observer observer); + void notifyObservers(); } diff --git a/src/main/java/org/example/chaosgame/controller/observer/GameController.java b/src/main/java/org/example/chaosgame/controller/observer/GameController.java deleted file mode 100644 index 1ae4fc77e6511600b65c2a0afc6f0d4a63959ee8..0000000000000000000000000000000000000000 --- a/src/main/java/org/example/chaosgame/controller/observer/GameController.java +++ /dev/null @@ -1,15 +0,0 @@ -package org.example.chaosgame.controller.observer; - -import javafx.scene.layout.StackPane; -import org.example.chaosgame.view.GamePage; - -public interface GameController { - void setBind(StackPane mainPane); - - GamePage getGamePage(); - - void updateJuliaValue(String partType, double value); - - void homeButtonClicked(); - -} diff --git a/src/main/java/org/example/chaosgame/model/chaos/ChaosCanvas.java b/src/main/java/org/example/chaosgame/model/chaos/ChaosCanvas.java index 56e41349c27292ec62f9703086e50faac57b6f6a..8ec988181845edd96b9cc2dd6ee804e86ed3b172 100644 --- a/src/main/java/org/example/chaosgame/model/chaos/ChaosCanvas.java +++ b/src/main/java/org/example/chaosgame/model/chaos/ChaosCanvas.java @@ -1,6 +1,5 @@ package org.example.chaosgame.model.chaos; -import javafx.scene.canvas.Canvas; import org.example.chaosgame.model.linalg.Matrix2x2; import org.example.chaosgame.model.linalg.Vector2D; import org.example.chaosgame.model.transformations.AffineTransform2D; @@ -50,6 +49,52 @@ public class ChaosCanvas { this.canvas = new double[height][width]; } + public double[][] getCanvasArray() { + return canvas; + } + + public int getWidth() { + return width; + } + + public int getHeight() { + return height; + } + + public Vector2D getMinCoords() { + return minCoords; + } + + public Vector2D getMaxCoords() { + return maxCoords; + } + + public void setMinCoords(Vector2D minCoords) { + this.minCoords = minCoords; + } + + public void setMaxCoords(Vector2D maxCoords) { + this.maxCoords = maxCoords; + } + + public void setTransformCoordsToIndices() { + this.transformCoordsToIndices = calculateTransformCoordsToIndices(); + } + + public void setWidth(int width) { + this.width = width; + } + + public void setHeight(int height) { + this.height = height; + } + + /** + * Calculates the Affine transformation that maps coordinates to indices in the canvas array. + * The transformation is calculated based on the width, height, minimum and maximum coordinates. + * + * @return The Affine transformation that maps coordinates to indices in the canvas array + */ private AffineTransform2D calculateTransformCoordsToIndices() { return new AffineTransform2D( new Matrix2x2( @@ -62,21 +107,13 @@ public class ChaosCanvas { )); } - public double getPixel(Vector2D point){ - Vector2D indices = transformCoordsToIndices.transform(point); - int x = (int) indices.getX(); - int y = (int) indices.getY(); - return canvas[x][y]; - } - - /** * Increments the pixel value at the given point by 1. * If the point is outside the canvas, the method does nothing. * * @param point The point to put a pixel at */ - public void putPixel(Vector2D point) { + public void putPixelChaos(Vector2D point) { Vector2D indices = transformCoordsToIndices.transform(point); int x = (int) indices.getX(); int y = (int) indices.getY(); @@ -84,6 +121,7 @@ public class ChaosCanvas { canvas[x][y] += 1; } } + /** * Sets the pixel value at the given point to the given value. * If the point is outside the canvas, the method does nothing. @@ -94,17 +132,17 @@ public class ChaosCanvas { * * @param iter The iteration value to set the pixel to */ - public void putPixel(int x, int y, double iter){ + public void putPixelExplore(int x, int y, double iter) { if (y >= 0 && y < height && x >= 0 && x < width) { canvas[y][x] = iter; } } /** - * Transforms indices in the canvas array to coordinates. + * Transforms indices in the canvas array to coordinate. * The method calculates the x-coordinate and y-coordinate based on the indices, * the width, height, minimum and maximum coordinates. - * Used in the ExploreGame class to map indices to coordinates which iterates through each pixel. + * Used in the ExploreGame class to map indices to coordinate that iterates through each pixel. * * @param i The x-coordinate in the canvas array * @@ -118,37 +156,9 @@ public class ChaosCanvas { return new Vector2D(x, y); } - public double[][] getCanvasArray() { - return canvas; - } - - public int getWidth() { - return width; - } - - public int getHeight() { - return height; - } - - public Vector2D getMinCoords() { - return minCoords; - } - - public Vector2D getMaxCoords() { - return maxCoords; - } - - public void setMinCoords(Vector2D minCoords) { - this.minCoords = minCoords; - } - public void setMaxCoords(Vector2D maxCoords) { - this.maxCoords = maxCoords; - } - - public void setTransformCoordsToIndices() { - this.transformCoordsToIndices = calculateTransformCoordsToIndices(); - } - + /** + * Clears the canvas by setting all pixel values to 0. + */ public void clearCanvas() { for (int i = 0; i < height; i++) { for (int j = 0; j < width; j++) { @@ -156,12 +166,4 @@ public class ChaosCanvas { } } } - - public void setWidth(int width) { - this.width = width; - } - - public void setHeight(int height) { - this.height = height; - } } diff --git a/src/main/java/org/example/chaosgame/model/chaos/ChaosGame.java b/src/main/java/org/example/chaosgame/model/chaos/ChaosGame.java index 8d6502e963a338c7b1f52d2e6e2ad378d3d9a83f..19a06e0757301ce85f84e8d525b225eb8a04cf6a 100644 --- a/src/main/java/org/example/chaosgame/model/chaos/ChaosGame.java +++ b/src/main/java/org/example/chaosgame/model/chaos/ChaosGame.java @@ -3,9 +3,8 @@ package org.example.chaosgame.model.chaos; import java.util.ArrayList; import java.util.List; import java.util.Random; - -import org.example.chaosgame.controller.observer.Observer; -import org.example.chaosgame.controller.observer.Subject; +import org.example.chaosgame.controller.interfaces.Observer; +import org.example.chaosgame.controller.interfaces.Subject; import org.example.chaosgame.model.linalg.Vector2D; /** @@ -29,6 +28,7 @@ public class ChaosGame implements Subject { /** * Private constructor for ChaosGame. + * Secures that only one instance of the ChaosGame can be created. * * @param description Description of the chaos game * @@ -83,29 +83,39 @@ public class ChaosGame implements Subject { this.steps = steps; } + public void setTotalSteps(int totalSteps) { + this.totalSteps = totalSteps; + } /** - * Method for setting the total number of steps. + * Method for setting the chaos game description. * - * @param totalSteps Number of steps + * @param newDescription New description of the chaos game */ - public void setTotalSteps(int totalSteps) { - this.totalSteps = totalSteps; + public void setChaosGameDescription(ChaosGameDescription newDescription) { + this.description = newDescription; + resetTotalSteps(); + setChaosCanvas(description.getMinCoords(), description.getMaxCoords()); + notifyObservers(); } - /** - * Method for adding steps to the total number of steps. + * Method for setting the chaos canvas. * - * @param newSteps Number of steps to add + * @param minCoords Minimum coordinates of the canvas + * @param maxCoords Maximum coordinates of the canvas */ + public void setChaosCanvas(Vector2D minCoords, Vector2D maxCoords) { + this.canvas.clearCanvas(); + this.canvas.setMinCoords(minCoords); + this.canvas.setMaxCoords(maxCoords); + this.canvas.setTransformCoordsToIndices(); + } + public void addTotalSteps(int newSteps) { this.totalSteps += newSteps; } - /** - * Method for resetting the total number of steps. - */ public void resetTotalSteps() { this.totalSteps = 0; } @@ -128,7 +138,7 @@ public class ChaosGame implements Subject { for (int i = 0; i < steps; i++) { int transformIndex = random.nextInt(description.getTransforms().size()); currentPoint = description.getTransforms().get(transformIndex).transform(currentPoint); - canvas.putPixel(currentPoint); + canvas.putPixelChaos(currentPoint); } } @@ -155,44 +165,37 @@ public class ChaosGame implements Subject { transformIndex = probabilities.size() - 1; // default to the last transformation } currentPoint = description.getTransforms().get(transformIndex).transform(currentPoint); - canvas.putPixel(currentPoint); + canvas.putPixelChaos(currentPoint); } } - public void setChaosGameDescription(ChaosGameDescription newDescription) { - if (!this.description.equals(newDescription)) { - this.resetTotalSteps(); - } - this.description = newDescription; - this.totalSteps = 0; - setChaosCanvas(description.getMinCoords(), description.getMaxCoords()); - notifyObservers(); - } - - public void setChaosCanvas(Vector2D minCoords, Vector2D maxCoords) { - this.canvas.clearCanvas(); - this.canvas.setMinCoords(minCoords); - this.canvas.setMaxCoords(maxCoords); - this.canvas.setTransformCoordsToIndices(); - } - + /** + * Method for registering an observer. + * + * @param gameObserver Observer to register + */ @Override public void registerObserver(Observer gameObserver) { gameObservers.add(gameObserver); - System.out.println("Observer added"); } + /** + * Method for removing an observer. + * + * @param gameObserver Observer to remove + */ @Override public void removeObserver(Observer gameObserver) { gameObservers.remove(gameObserver); - System.out.println("Observer removed"); } + /** + * Method for notifying observers. + */ @Override public void notifyObservers() { for (Observer gameObserver : gameObservers) { gameObserver.update(); - System.out.println("Observer notified drawed"); } } } diff --git a/src/main/java/org/example/chaosgame/model/chaos/ChaosGameDescription.java b/src/main/java/org/example/chaosgame/model/chaos/ChaosGameDescription.java index add831b82632705dae5ea4603628993323f8ce39..7b92582cc4624895b789b626da1e074b04dba77b 100644 --- a/src/main/java/org/example/chaosgame/model/chaos/ChaosGameDescription.java +++ b/src/main/java/org/example/chaosgame/model/chaos/ChaosGameDescription.java @@ -33,6 +33,18 @@ public class ChaosGameDescription { this.transforms = transforms; } + /** + * Second constructor for ChaosGameDescription. + * Includes a list of probabilities for the transformations. + * + * @param minCoords Minimum coordinates of the game area + * + * @param maxCoords Maximum coordinates of the game area + * + * @param transforms List of transformations to apply to the points + * + * @param probabilities List of probabilities for the transformations + */ public ChaosGameDescription(Vector2D minCoords, Vector2D maxCoords, List<Transform2D> transforms, List<Integer> probabilities) { this.minCoords = minCoords; @@ -49,21 +61,23 @@ public class ChaosGameDescription { return maxCoords; } - public void setMinCoords(Vector2D minCoords) { - this.minCoords = minCoords; - } - public void setMaxCoords(Vector2D maxCoords) { - this.maxCoords = maxCoords; - } - public List<Transform2D> getTransforms() { return transforms; } + + public List<Integer> getProbabilities() { + return probabilities; + } + public void setTransforms(List<Transform2D> transforms) { this.transforms = transforms; } - public List<Integer> getProbabilities() { - return probabilities; + public void setMinCoords(Vector2D minCoords) { + this.minCoords = minCoords; + } + + public void setMaxCoords(Vector2D maxCoords) { + this.maxCoords = maxCoords; } } diff --git a/src/main/java/org/example/chaosgame/model/chaos/ChaosGameDescriptionFactory.java b/src/main/java/org/example/chaosgame/model/chaos/ChaosGameDescriptionFactory.java index 74ca154abd6ba151a564c38df57f86ae02681557..166963ee5f073e835f347d780a82ba25e28c1e87 100644 --- a/src/main/java/org/example/chaosgame/model/chaos/ChaosGameDescriptionFactory.java +++ b/src/main/java/org/example/chaosgame/model/chaos/ChaosGameDescriptionFactory.java @@ -21,7 +21,7 @@ public class ChaosGameDescriptionFactory { public static ChaosGameDescription get(ChaosGameType type) { return switch (type) { case JULIA -> createJulia(); - case BARNSLEY-> createBarnsley(); + case BARNSLEY -> createBarnsley(); case SIERPINSKI -> createSierpinski(); }; } @@ -51,15 +51,19 @@ public class ChaosGameDescriptionFactory { new Vector2D(0.0, 0.0), new Vector2D(1.0, 1.0), List.of( - new AffineTransform2D(new Matrix2x2(0.5, 0.0, 0.0, 0.5), new Vector2D(0.0, 0.0)), - new AffineTransform2D(new Matrix2x2(0.5, 0.0, 0.0, 0.5), new Vector2D(0.25, 0.50)), - new AffineTransform2D(new Matrix2x2(0.5, 0.0, 0.0, 0.5), new Vector2D(0.5, 0.0)) + new AffineTransform2D(new Matrix2x2(0.5, 0.0, 0.0, 0.5), + new Vector2D(0.0, 0.0)), + new AffineTransform2D(new Matrix2x2(0.5, 0.0, 0.0, 0.5), + new Vector2D(0.25, 0.50)), + new AffineTransform2D(new Matrix2x2(0.5, 0.0, 0.0, 0.5), + new Vector2D(0.5, 0.0)) ) ); } /** * Creates a ChaosGameDescription object for the Barnsley fern. + * Includes probabilities for the transformations. * * @return A ChaosGameDescription object */ @@ -68,10 +72,14 @@ public class ChaosGameDescriptionFactory { new Vector2D(-2.65, 0.0), new Vector2D(2.65, 10.0), List.of( - new AffineTransform2D(new Matrix2x2(0.0, 0.0, 0.0, 0.16), new Vector2D(0.0, 0.0)), - new AffineTransform2D(new Matrix2x2(0.85, 0.04, -0.04, 0.85), new Vector2D(0.0, 1.60)), - new AffineTransform2D(new Matrix2x2(0.20, -0.26, 0.23, 0.22), new Vector2D(0.0, 1.60)), - new AffineTransform2D(new Matrix2x2(-0.15, 0.28, 0.26, 0.24), new Vector2D(0.0, 0.44)) + new AffineTransform2D(new Matrix2x2(0.0, 0.0, 0.0, 0.16), + new Vector2D(0.0, 0.0)), + new AffineTransform2D(new Matrix2x2(0.85, 0.04, -0.04, 0.85), + new Vector2D(0.0, 1.60)), + new AffineTransform2D(new Matrix2x2(0.20, -0.26, 0.23, 0.22), + new Vector2D(0.0, 1.60)), + new AffineTransform2D(new Matrix2x2(-0.15, 0.28, 0.26, 0.24), + new Vector2D(0.0, 0.44)) ), List.of(2, 84, 7, 7) ); } diff --git a/src/main/java/org/example/chaosgame/model/chaos/ChaosGameFileHandler.java b/src/main/java/org/example/chaosgame/model/chaos/ChaosGameFileHandler.java index 0d86039346198f9d65bf3d6c14545351d39c9c67..e10510ef599e1a7042886c6188b9e242be01da8d 100644 --- a/src/main/java/org/example/chaosgame/model/chaos/ChaosGameFileHandler.java +++ b/src/main/java/org/example/chaosgame/model/chaos/ChaosGameFileHandler.java @@ -104,10 +104,10 @@ public class ChaosGameFileHandler { for (Transform2D transform : description.getTransforms()) { if (transform instanceof AffineTransform2D affine) { count++; - Matrix2x2 matrix = affine.getMatrix(); - Vector2D vector = affine.getVector(); - writer.write(matrix.getA() + ", " + matrix.getB() + ", " - + matrix.getC() + ", " + matrix.getD() + ", " + Matrix2x2 matrix = affine.matrix(); + Vector2D vector = affine.vector(); + writer.write(matrix.a() + ", " + matrix.b() + ", " + + matrix.c() + ", " + matrix.d() + ", " + vector.getX() + ", " + vector.getY() + " # " + count + " transformation"); } else if (transform instanceof JuliaTransform julia) { diff --git a/src/main/java/org/example/chaosgame/model/chaos/ChaosGameType.java b/src/main/java/org/example/chaosgame/model/chaos/ChaosGameType.java index afe632a17bbd3a176fe735e3a6df56374bc8d6aa..c709d9a32442da82d4072798fa91534f09e90d01 100644 --- a/src/main/java/org/example/chaosgame/model/chaos/ChaosGameType.java +++ b/src/main/java/org/example/chaosgame/model/chaos/ChaosGameType.java @@ -1,5 +1,10 @@ package org.example.chaosgame.model.chaos; +/** + * Enum for the different types of chaos games. + * Used to determine which type of chaos game to play. + + */ public enum ChaosGameType { JULIA, BARNSLEY, diff --git a/src/main/java/org/example/chaosgame/model/chaos/ExploreGame.java b/src/main/java/org/example/chaosgame/model/chaos/ExploreGame.java index 6caad1a691fe8b62065b9fea47d0b796c84a1973..506e325997f5858ad48c1b3eb6b750749a5abc7b 100644 --- a/src/main/java/org/example/chaosgame/model/chaos/ExploreGame.java +++ b/src/main/java/org/example/chaosgame/model/chaos/ExploreGame.java @@ -1,23 +1,18 @@ package org.example.chaosgame.model.chaos; -import javafx.concurrent.Task; -import javafx.scene.canvas.Canvas; -import org.example.chaosgame.controller.observer.Observer; -import org.example.chaosgame.controller.observer.Subject; -import org.example.chaosgame.model.linalg.Vector2D; -import org.example.chaosgame.model.transformations.Transform2D; - import java.util.ArrayList; import java.util.List; import java.util.stream.IntStream; +import org.example.chaosgame.controller.interfaces.Observer; +import org.example.chaosgame.controller.interfaces.Subject; +import org.example.chaosgame.model.linalg.Vector2D; /** * Class for exploring julia sets. */ -public class ExploreGame extends Task implements Subject { - private final int MAX_ITER = 256; - - private ChaosCanvas canvas; +public class ExploreGame implements Subject { + private static final int MAX_ITER = 256; + private final ChaosCanvas canvas; private ChaosGameDescription description; private Vector2D currentPoint = new Vector2D(0.0, 0.0); private final List<Observer> gameObservers; @@ -33,98 +28,100 @@ public class ExploreGame extends Task implements Subject { */ public ExploreGame(ChaosGameDescription description, int width, int height) { this.description = description; - this.canvas = new ChaosCanvas(width, height, description.getMinCoords(), description.getMaxCoords()); + this.canvas = new ChaosCanvas(width, height, + description.getMinCoords(), description.getMaxCoords()); this.gameObservers = new ArrayList<>(); } + public ChaosCanvas getCanvas() { + return canvas; + } + + public ChaosGameDescription getDescription() { + return description; + } + + public void setExploreGame(ChaosGameDescription description, int width, int height) { + this.description = description; + setChaosCanvas(description.getMinCoords(), description.getMaxCoords(), width, height); + } + + /** + * Method for setting the chaos canvas. + * + * @param minCoords Minimum coordinates of the canvas + * + * @param maxCoords Maximum coordinates of the canvas + * + * @param width Width of the canvas + * + * @param height Height of the canvas + */ + public void setChaosCanvas(Vector2D minCoords, Vector2D maxCoords, int width, int height) { + this.canvas.clearCanvas(); + this.canvas.setMaxCoords(maxCoords); + this.canvas.setMinCoords(minCoords); + this.canvas.setWidth(width); + this.canvas.setHeight(height); + } + /** * Method for exploring fractals. Iterates over all pixels in the canvas * and applies the transformation to the current point. + * Inspiration from <a href="https://www.youtube.com/watch?v=uc2yok_pLV4">Pezzza's Work</a> + * and <a href="https://github.com/majidrouhani/idatt2003-gui-demo-mandelbrot">idatt2003-gui-demo-mandelbrot</a> * */ - public void exploreFractals(){ -// stopTask(); - -// long start = System.currentTimeMillis(); - - IntStream yStream = IntStream.range(0, canvas.getHeight()); - yStream.parallel().forEach(y -> { -// for (int y = 0; y < canvas.getHeight(); y++) { - for (int x = 0; x < canvas.getWidth(); x++) { -// if (isCancelled()) { -// break; -// } + public void exploreFractals() { + IntStream heightStream = IntStream.range(0, canvas.getHeight()); + heightStream.parallel().forEach(height -> { + for (int width = 0; width < canvas.getWidth(); width++) { int iter = 0; - currentPoint = canvas.transformIndicesToCoords(x, y); + currentPoint = canvas.transformIndicesToCoords(width, height); Vector2D tempPoint = currentPoint; - while (iter < MAX_ITER && tempPoint.lengthSQ() < 4){ + while (iter < MAX_ITER && tempPoint.lengthSq() < 4) { tempPoint = description.getTransforms().getFirst().transform(tempPoint); iter++; } - double abs = Math.sqrt(tempPoint.lengthSQ()); + double abs = Math.sqrt(tempPoint.lengthSq()); double smooth = iter - Math.log(Math.log(abs)) / Math.log(2); - canvas.putPixel(x, y, smooth); + canvas.putPixelExplore(width, height, smooth); } }); notifyObservers(); -// long end = System.currentTimeMillis(); -// System.out.println("Time taken: " + (end - start) + "ms"); - } - - - public void setChaosCanvas(Vector2D minCoords, Vector2D maxCoords, int width, int height) { - this.canvas.clearCanvas(); - this.canvas.setMaxCoords(maxCoords); - this.canvas.setMinCoords(minCoords); - this.canvas.setWidth(width); - this.canvas.setHeight(height); - } - public void setExploreGame(ChaosGameDescription description, int width, int height) { - this.description = description; - setChaosCanvas(description.getMinCoords(), description.getMaxCoords(), width, height); - } - - public ChaosCanvas getCanvas() { - return canvas; - } - - public ChaosGameDescription getDescription() { - return description; } + /** + * Method for registering gameObservers. + * + * @param gameObserver gameObserver to register + */ @Override public void registerObserver(Observer gameObserver) { gameObservers.add(gameObserver); } + /** + * Method for removing gameObservers. + * + * @param gameObserver gameObserver to remove + */ @Override public void removeObserver(Observer gameObserver) { gameObservers.remove(gameObserver); } + /** + * Method for notifying gameObservers. + * Need to create a new list to avoid concurrent modification exception. + */ @Override public void notifyObservers() { List<Observer> gameObservers = new ArrayList<>(this.gameObservers); for (Observer gameObserver : gameObservers) { - try { - gameObserver.update(); - } catch (Exception e) { - System.out.println("Message: " + e.getMessage()); - } - - } - } - - public Task call() throws Exception { - System.out.println("Task called"); - return this; - } - public void stopTask() { - if (this != null) { - - this.cancel(); + gameObserver.update(); } } } diff --git a/src/main/java/org/example/chaosgame/model/linalg/Matrix2x2.java b/src/main/java/org/example/chaosgame/model/linalg/Matrix2x2.java index 89bba3de7b09c490d6fd47f87f7889c40158c28b..24a5f69fd23de18c3a0b064a7053f17b7b1c12c6 100644 --- a/src/main/java/org/example/chaosgame/model/linalg/Matrix2x2.java +++ b/src/main/java/org/example/chaosgame/model/linalg/Matrix2x2.java @@ -2,20 +2,17 @@ package org.example.chaosgame.model.linalg; /** - * Class for 2x2 matrices. + * Record for 2x2 matrices. * The matrices are represented by four double values: a, b, c, and d. * * <br> * [ a b ] * <br> * [ c d ] + * + * <p>Chosen to use a, b, c, d instead of the traditional row, column notation for simplicity. */ -public class Matrix2x2 { - private final double a; - private final double b; - private final double c; - private final double d; - +public record Matrix2x2(double a, double b, double c, double d) { /** * Constructor for Matrix2x2. * @@ -24,27 +21,7 @@ public class Matrix2x2 { * @param c second row, first column in the matrix. * @param d second row, second column in the matrix. */ - public Matrix2x2(double a, double b, double c, double d) { - this.a = a; - this.b = b; - this.c = c; - this.d = d; - } - - public double getA() { - return a; - } - - public double getB() { - return b; - } - - public double getC() { - return c; - } - - public double getD() { - return d; + public Matrix2x2 { } @@ -56,8 +33,8 @@ public class Matrix2x2 { */ public Vector2D multiply(Vector2D vector) { return new Vector2D( - this.a * vector.getX() + this.b * vector.getY(), - this.c * vector.getX() + this.d * vector.getY() + this.a * vector.getX() + this.b * vector.getY(), + this.c * vector.getX() + this.d * vector.getY() ); } } diff --git a/src/main/java/org/example/chaosgame/model/linalg/Vector2D.java b/src/main/java/org/example/chaosgame/model/linalg/Vector2D.java index a5801d4a829ad8a555057c46d3c9762e197ecbe6..3d9ec7a2daf3979335f7acb14ebe02923cfe79e3 100644 --- a/src/main/java/org/example/chaosgame/model/linalg/Vector2D.java +++ b/src/main/java/org/example/chaosgame/model/linalg/Vector2D.java @@ -4,6 +4,8 @@ package org.example.chaosgame.model.linalg; * Class for 2D vectors. * Vectors are represented by an x-coordinate and a y-coordinate. * The class contains methods for adding and subtracting vectors. + * + * <p>Chosen to use x and y instead of the traditional row, column notation for simplicity. */ public class Vector2D { private final double x; @@ -52,25 +54,48 @@ public class Vector2D { y - other.y); } + /** + * Scale a vector by a scalar. + * + * @param scalar the scalar to multiply the vector by + * @return the scaled vector + */ public Vector2D scale(double scalar) { return new Vector2D( x * scalar, y * scalar); } + /** + * Multiply two vectors together. + * + * @param other the other vector + * @return the product of the two vectors + */ public Vector2D multiply(Vector2D other) { return new Vector2D( x * other.x, y * other.y); } + /** + * Divide one vector by another. + * + * @param other the other vector + * @return the quotient of the two vectors + */ public Vector2D divide(Vector2D other) { return new Vector2D( x / other.x, y / other.y); } - public double lengthSQ() { + /** + * Calculate the length of a vector. + * + * @return the length of the vector + */ + public double lengthSq() { return x * x + y * y; } } diff --git a/src/main/java/org/example/chaosgame/model/transformations/AffineTransform2D.java b/src/main/java/org/example/chaosgame/model/transformations/AffineTransform2D.java index 3bb339a23639376b84f36aa6e653fee0c5576407..91c6d239e41630164e9018f27d7efab9aadda68b 100644 --- a/src/main/java/org/example/chaosgame/model/transformations/AffineTransform2D.java +++ b/src/main/java/org/example/chaosgame/model/transformations/AffineTransform2D.java @@ -4,15 +4,12 @@ import org.example.chaosgame.model.linalg.Matrix2x2; import org.example.chaosgame.model.linalg.Vector2D; /** - * Represents an affine transformation in 2D space. + * Record for 2D affine transformations. * The transformation is represented by a 2x2 matrix and a 2D vector. * The transformation is applied to a 2D point by first multiplying the point with the matrix * and then adding the vector. */ -public class AffineTransform2D implements Transform2D { - private final Matrix2x2 matrix; - private final Vector2D vector; - +public record AffineTransform2D(Matrix2x2 matrix, Vector2D vector) implements Transform2D { /** * Constructor for AffineTransform2D. * An affine transformation is represented by a 2x2 matrix and a 2D vector. @@ -22,9 +19,7 @@ public class AffineTransform2D implements Transform2D { * @param matrix the 2x2 matrix * @param vector the 2D vector */ - public AffineTransform2D(Matrix2x2 matrix, Vector2D vector) { - this.matrix = matrix; - this.vector = vector; + public AffineTransform2D { } /** @@ -32,19 +27,10 @@ public class AffineTransform2D implements Transform2D { * Overridden from the Transform2D interface. * * @param point the point to transform - * * @return the transformed point */ @Override public Vector2D transform(Vector2D point) { return matrix.multiply(point).add(vector); } - - public Matrix2x2 getMatrix() { - return matrix; - } - - public Vector2D getVector() { - return vector; - } } diff --git a/src/main/java/org/example/chaosgame/model/transformations/ExploreJulia.java b/src/main/java/org/example/chaosgame/model/transformations/ExploreJulia.java index ea65f0f74fc1e9c5d35be7a8b93a6a636fdf3700..4d84a62e2352e3f4079d95b9a97105ccf2c57818 100644 --- a/src/main/java/org/example/chaosgame/model/transformations/ExploreJulia.java +++ b/src/main/java/org/example/chaosgame/model/transformations/ExploreJulia.java @@ -3,7 +3,14 @@ package org.example.chaosgame.model.transformations; import org.example.chaosgame.model.linalg.Complex; import org.example.chaosgame.model.linalg.Vector2D; -public class ExploreJulia implements Transform2D{ +/** + * Class for the Julia transformation. + * This formula describes the transformation: + * <br> + * <span style="font-family: Courier"> + * z → z<sup>2</sup> + c </span> + */ +public class ExploreJulia implements Transform2D { private final Complex point; /** @@ -21,10 +28,10 @@ public class ExploreJulia implements Transform2D{ /** * Method to transform a 2D vector using the Julia transformation. - * The transformation is given by the formula: + * This formula describes this transformation: * <br> * <span style="font-family: Courier"> - * z → z<sup>2</sup> + c + * z → z<sup>2</sup> + c </span> * * @param point the 2D vector to transform * @return a new 2D vector @@ -36,5 +43,4 @@ public class ExploreJulia implements Transform2D{ double a = temp + this.point.getX(); return new Vector2D(a, b); } - } diff --git a/src/main/java/org/example/chaosgame/model/transformations/JuliaTransform.java b/src/main/java/org/example/chaosgame/model/transformations/JuliaTransform.java index 37e217db69fea7849391597dac2cbb6e350e6d12..85d619f461c67429aff91032bb02f16864154001 100644 --- a/src/main/java/org/example/chaosgame/model/transformations/JuliaTransform.java +++ b/src/main/java/org/example/chaosgame/model/transformations/JuliaTransform.java @@ -5,11 +5,10 @@ import org.example.chaosgame.model.linalg.Vector2D; /** * Class for the Julia transformation. - * The transformation is given by the formula: + * This formula describes the transformation: * <br> * <span style="font-family: Courier"> - * z → ±√̅z̅ ̅-̅ ̅c - *</span> + * z → ±√̅z̅ ̅-̅ ̅c</span> * */ public class JuliaTransform implements Transform2D { @@ -33,10 +32,10 @@ public class JuliaTransform implements Transform2D { /** * Method to transform a 2D vector using the Julia transformation. - * The transformation is given by the formula: + * This formula describes the transformation: * <br> * <span style="font-family: Courier"> - * z → ±√̅z̅ ̅-̅ ̅c + * z → ±√̅z̅ ̅-̅ ̅c </span> * * @param point the 2D vector to transform * @return a new 2D vector diff --git a/src/main/java/org/example/chaosgame/model/transformations/Transform2D.java b/src/main/java/org/example/chaosgame/model/transformations/Transform2D.java index d1025d5d517b9024fcb43d3293e4bece747135f9..c97d56a76b4b050050d7a306ad13bf2b04da1c43 100644 --- a/src/main/java/org/example/chaosgame/model/transformations/Transform2D.java +++ b/src/main/java/org/example/chaosgame/model/transformations/Transform2D.java @@ -6,6 +6,5 @@ import org.example.chaosgame.model.linalg.Vector2D; * Interface for 2D transformations. */ public interface Transform2D { - public Vector2D transform(Vector2D point); - + Vector2D transform(Vector2D point); } diff --git a/src/main/java/org/example/chaosgame/view/ChaosPage.java b/src/main/java/org/example/chaosgame/view/ChaosPage.java index f4abc3c32a3d3d89f70791764fe1fe0745fffbf3..cbb58d76538c913ad304ddca7361c4da086b07b3 100644 --- a/src/main/java/org/example/chaosgame/view/ChaosPage.java +++ b/src/main/java/org/example/chaosgame/view/ChaosPage.java @@ -1,24 +1,27 @@ package org.example.chaosgame.view; -import javafx.scene.canvas.Canvas; import javafx.scene.canvas.GraphicsContext; -import javafx.scene.control.*; -import javafx.scene.layout.HBox; -import javafx.scene.layout.VBox; import org.example.chaosgame.controller.ChaosGameController; -import org.example.chaosgame.model.chaos.ChaosCanvas; import org.example.chaosgame.model.linalg.Vector2D; -import org.example.chaosgame.model.transformations.JuliaTransform; import org.example.chaosgame.model.transformations.Transform2D; -import org.example.chaosgame.view.components.*; - -import java.util.List; -import java.util.Vector; - +import org.example.chaosgame.view.components.BottomBar; +import org.example.chaosgame.view.components.SideBar; +import org.example.chaosgame.view.components.TopBar; + +/** + * Class for the ChaosPage, extends GamePage. + * The ChaosPage is used for displaying the chaosGame. + */ public class ChaosPage extends GamePage { private final TopBar topBar; private final BottomBar bottomBar; + /** + * Constructor for the ChaosPage. + * Initializes the top bar, bottom bar and sidebar components. + * + * @param chaosGameController the chaos game controller + */ public ChaosPage(ChaosGameController chaosGameController) { super(); this.topBar = new TopBar(chaosGameController); @@ -31,14 +34,26 @@ public class ChaosPage extends GamePage { this.setRight(sideBar); this.setBottom(bottomBar); this.setLeft(gc.getCanvas()); - } + /** + * Calls the updateTopBar and updateBottomBar methods in the ChaosPage. + * + * @param transformation the transformation + * @param steps the steps + * @param min the min coordinates + * @param max the max coordinates + */ public void updateInformation(Transform2D transformation, int steps, Vector2D min, Vector2D max) { topBar.updateTopBar(transformation, steps, min, max); bottomBar.updateBottomBar(transformation); } + /** + * Method for getting the GraphicsContext. + * + * @return the GraphicsContext + */ public GraphicsContext getGraphicsContext() { return gc; } diff --git a/src/main/java/org/example/chaosgame/view/ExplorePage.java b/src/main/java/org/example/chaosgame/view/ExplorePage.java index d20786198b5fd090d6e744b92454579dc8eaacbc..97e6522b52bdae8e577317b26893bcbd8a709747 100644 --- a/src/main/java/org/example/chaosgame/view/ExplorePage.java +++ b/src/main/java/org/example/chaosgame/view/ExplorePage.java @@ -1,12 +1,5 @@ package org.example.chaosgame.view; -import javafx.geometry.Orientation; -import javafx.geometry.Pos; -import javafx.scene.canvas.GraphicsContext; -import javafx.scene.control.Button; -import javafx.scene.control.Slider; -import javafx.scene.layout.HBox; -import javafx.scene.layout.VBox; import org.example.chaosgame.controller.ExploreGameController; import org.example.chaosgame.model.linalg.Vector2D; import org.example.chaosgame.model.transformations.Transform2D; @@ -14,16 +7,25 @@ import org.example.chaosgame.view.components.BottomBar; import org.example.chaosgame.view.components.SideBar; import org.example.chaosgame.view.components.TopBar; +/** + * Class for the ExplorePage, extends GamePage. + * The ExplorePage is used for displaying the exploreGame. + */ public class ExplorePage extends GamePage { - - private final SideBar sidebar; private final BottomBar bottomBar; private final TopBar topBar; + + /** + * Constructor for the ExplorePage. + * Initializes the top bar, bottom bar and sidebar components. + * + * @param exploreGameController the explore game controller + */ public ExplorePage(ExploreGameController exploreGameController) { super(); this.setStyle("-fx-background-color: black;"); - this.sidebar = new SideBar(exploreGameController); - this.sidebar.setStyle("-fx-background-color: black;"); + SideBar sidebar = new SideBar(exploreGameController); + sidebar.setStyle("-fx-background-color: black;"); this.topBar = new TopBar(exploreGameController); this.topBar.setStyle("-fx-background-color: black;"); this.bottomBar = new BottomBar(exploreGameController); @@ -35,17 +37,24 @@ public class ExplorePage extends GamePage { this.setTop(topBar); gc.getCanvas().setOnScroll(event -> { - try{ - exploreGameController.onScroll(event); - } catch (Exception e) { - exploreGameController.resetImage(); - } + try { + exploreGameController.onScroll(event); + } catch (Exception e) { + exploreGameController.resetImage(); + } }); this.setOnMousePressed(exploreGameController::mousePressed); this.setOnMouseDragged(exploreGameController::mouseDragged); this.setOnMouseReleased(exploreGameController::mouseReleased); } + /** + * Calls the updateTopBar and updateBottomBar methods in the ExplorePage. + * + * @param transformation the transformation + * @param min the min coordinates + * @param max the max coordinates + */ public void updateInformation(Transform2D transformation, Vector2D min, Vector2D max) { topBar.updateTopBar(min, max); bottomBar.updateBottomBar(transformation); diff --git a/src/main/java/org/example/chaosgame/view/GamePage.java b/src/main/java/org/example/chaosgame/view/GamePage.java index 74a8bdaa625ae904050c64bf97751309aa1cb954..68944e8292504ffec1ed522b6b544896e838058f 100644 --- a/src/main/java/org/example/chaosgame/view/GamePage.java +++ b/src/main/java/org/example/chaosgame/view/GamePage.java @@ -1,69 +1,97 @@ package org.example.chaosgame.view; -import javafx.event.ActionEvent; -import javafx.event.EventHandler; import javafx.scene.canvas.Canvas; import javafx.scene.canvas.GraphicsContext; -import javafx.scene.control.Button; -import javafx.scene.image.Image; -import javafx.scene.image.ImageView; import javafx.scene.image.PixelWriter; import javafx.scene.image.WritableImage; - import javafx.scene.layout.BorderPane; import javafx.scene.paint.Color; import org.example.chaosgame.model.chaos.ChaosCanvas; -import org.example.chaosgame.view.components.HomeButton; - -import java.util.Objects; +/** + * Abstract class for the GamePage, extends BorderPane. + * The GamePage is used for displaying the game. + */ public abstract class GamePage extends BorderPane { protected final GraphicsContext gc; private static final int COLOR_FACTOR = 6; private static final int CANVAS_WIDTH = 1250; private static final int CANVAS_HEIGHT = 805; private static final int MAX_COLOR_VALUE = 255; - protected Color fractalColor; + /** + * Constructor for the GamePage. + * Initializes the canvas and fractal color. + */ public GamePage() { this.gc = createCanvas(); this.fractalColor = Color.WHITE; } + /** + * Method for setting color of the fractal. + * + * @param newFractalColor the new fractal color + */ + public void setFractalColor(Color newFractalColor) { + this.fractalColor = newFractalColor; + } + + /** + * Method for creating the canvas. + * + * @return the GraphicsContext + */ private GraphicsContext createCanvas() { Canvas canvas = new Canvas(CANVAS_WIDTH, CANVAS_HEIGHT); return canvas.getGraphicsContext2D(); } + /** + * Method for updating the canvas. + * Clears the canvas and draws the canvas. + * + * @param chaosCanvas the chaos canvas + */ public void updateCanvas(ChaosCanvas chaosCanvas) { clearCanvas(); drawCanvas(chaosCanvas); } - public void setCanvasSize(double width, double height) { - gc.getCanvas().setWidth(width); - gc.getCanvas().setHeight(height); - } - + /** + * Method for clearing the canvas. + */ public void clearCanvas() { gc.clearRect(0, 0, gc.getCanvas().getWidth(), gc.getCanvas().getHeight()); } + /** + * Method for drawing the canvas. + * + * @param chaosCanvas the chaos canvas + */ private void drawCanvas(ChaosCanvas chaosCanvas) { double[][] canvasArray = chaosCanvas.getCanvasArray(); double cellWidth = gc.getCanvas().getWidth() / chaosCanvas.getWidth(); double cellHeight = gc.getCanvas().getHeight() / chaosCanvas.getHeight(); - // Create an off-screen image WritableImage offScreenImage = createOffScreenImage(chaosCanvas, canvasArray); - // Draw the off-screen image on the canvas - gc.drawImage(offScreenImage, 0, 0, cellWidth * chaosCanvas.getWidth(), cellHeight * chaosCanvas.getHeight()); + gc.drawImage(offScreenImage, 0, 0, cellWidth * chaosCanvas.getWidth(), + cellHeight * chaosCanvas.getHeight()); } - // Creates an off-screen image from the given ChaosCanvas and canvas array + /** + * Method for creating the offscreen image. + * Creates a WritableImage and sets the pixel color. + * + * @param chaosCanvas the chaos canvas + * @param canvasArray the canvas array + * @return the WritableImage + */ private WritableImage createOffScreenImage(ChaosCanvas chaosCanvas, double[][] canvasArray) { - WritableImage offScreenImage = new WritableImage(chaosCanvas.getWidth(), chaosCanvas.getHeight()); + WritableImage offScreenImage = new WritableImage( + chaosCanvas.getWidth(), chaosCanvas.getHeight()); PixelWriter pixelWriter = offScreenImage.getPixelWriter(); Color minColor = Color.BLACK; @@ -84,14 +112,4 @@ public abstract class GamePage extends BorderPane { return offScreenImage; } - - public void setFractalColor(Color newFractalColor) { - this.fractalColor = newFractalColor; - } - - protected Button createHomeButton(EventHandler<ActionEvent> eventHandler) { - Button homeButton = new HomeButton(); - homeButton.setOnAction(eventHandler); - return homeButton; - } } diff --git a/src/main/java/org/example/chaosgame/view/HomePage.java b/src/main/java/org/example/chaosgame/view/HomePage.java index 5c9865064caba4f8c4dd4552526c8c0929751402..5f06af2ee17f134f87e1b215cb44745123d74e97 100644 --- a/src/main/java/org/example/chaosgame/view/HomePage.java +++ b/src/main/java/org/example/chaosgame/view/HomePage.java @@ -1,65 +1,61 @@ package org.example.chaosgame.view; +import java.util.Objects; import javafx.geometry.Pos; -import javafx.geometry.Rectangle2D; -import javafx.scene.Group; import javafx.scene.control.Button; import javafx.scene.effect.ColorAdjust; import javafx.scene.input.MouseEvent; import javafx.scene.layout.HBox; import javafx.scene.layout.Pane; import javafx.scene.layout.StackPane; -import javafx.scene.layout.VBox; +import javafx.scene.media.Media; import javafx.scene.media.MediaPlayer; import javafx.scene.media.MediaView; -import javafx.scene.shape.Rectangle; import javafx.scene.text.Text; -import javafx.stage.FileChooser; -import javafx.util.Duration; -import org.example.chaosgame.controller.ChaosGameController; import org.example.chaosgame.controller.HomeController; import org.example.chaosgame.controller.PageController; -import org.example.chaosgame.model.chaos.ChaosGameDescription; -import org.example.chaosgame.model.chaos.ChaosGameFileHandler; - import org.example.chaosgame.view.components.ExitButton; import org.example.chaosgame.view.components.GameHeader; -import javafx.scene.media.Media; - -import java.io.File; -import java.io.FileReader; -import java.util.Objects; -import java.util.Stack; - +/** + * Class for the home page, extends StackPane. + * The home page is the first page the user sees when starting the application. + * The home page contains two videos, one for the ChaosGame and one for the ExploreGame. + * The user can click on the videos to go to the corresponding game. + */ public class HomePage extends StackPane { - private final String EXPLORE_PATH = Objects.requireNonNull(getClass().getResource("/ExploreVideoFinal.mp4")).toString(); - private final String CHAOS_PATH = Objects.requireNonNull(getClass().getResource("/ChaosVideoFinal.mp4")).toString(); private final MediaPlayer exploreVideo; private final MediaPlayer chaosVideo; - private final MediaView exploreView; private final MediaView chaosView; private final StackPane explorePane; private final StackPane chaosPane; - //private final HomeController homeController; + /** + * Constructor for the HomePage. + * Initializes the videos, media views and panes for the videos. + * The user can click on the videos to go to the corresponding game. + * + * @param pageController the page controller + * @param homeController the home controller + */ public HomePage(PageController pageController, HomeController homeController) { - //this.homeController = homeController; HBox videoBox = new HBox(); videoBox.prefWidthProperty().bind(this.prefWidthProperty()); videoBox.prefHeightProperty().bind(this.prefHeightProperty()); - /*videoBox.setStyle("-fx-background-color: black;");*/ - Text header = new GameHeader("Welcome to ChaosGame"); Button exitButton = new ExitButton(); exitButton.setOnAction(e -> pageController.exitGame()); ColorAdjust colorAdjust = new ColorAdjust(); colorAdjust.setBrightness(-0.8); - chaosVideo = new MediaPlayer(new Media(CHAOS_PATH)); + String chaosPath = Objects.requireNonNull(getClass() + .getResource("/ChaosVideoFinal.mp4")).toString(); + chaosVideo = new MediaPlayer(new Media(chaosPath)); - exploreVideo = new MediaPlayer(new Media(EXPLORE_PATH)); + String explorePath = Objects.requireNonNull(getClass() + .getResource("/ExploreVideoFinal.mp4")).toString(); + exploreVideo = new MediaPlayer(new Media(explorePath)); chaosView = new MediaView(chaosVideo); chaosView.setEffect(null); @@ -73,10 +69,10 @@ public class HomePage extends StackPane { Text chaosHeader = new GameHeader("Chaos Game"); chaosPane.getChildren().addAll(chaosView, chaosHeader); chaosPane.addEventFilter(MouseEvent.MOUSE_CLICKED, e -> pageController.goToPage("chaos")); - chaosPane.addEventFilter(MouseEvent.MOUSE_ENTERED, e -> homeController.mouseEvent(MouseEvent.MOUSE_ENTERED, - chaosVideo, chaosView, chaosHeader, null, null)); - chaosPane.addEventFilter(MouseEvent.MOUSE_EXITED, e -> homeController.mouseEvent(MouseEvent.MOUSE_EXITED, - chaosVideo, chaosView, chaosHeader, null, colorAdjust)); + chaosPane.addEventFilter(MouseEvent.MOUSE_ENTERED, e -> homeController.mouseEvent( + MouseEvent.MOUSE_ENTERED, chaosVideo, chaosView, chaosHeader, null, null)); + chaosPane.addEventFilter(MouseEvent.MOUSE_EXITED, e -> homeController.mouseEvent( + MouseEvent.MOUSE_EXITED, chaosVideo, chaosView, chaosHeader, null, colorAdjust)); explorePane = new StackPane(); Text exploreHeader = new GameHeader("Explore Game"); @@ -84,11 +80,12 @@ public class HomePage extends StackPane { explorePane.setStyle("-fx-background-color: black;"); explorePane.addEventFilter(MouseEvent.MOUSE_CLICKED, e -> pageController.goToPage("explore")); - explorePane.addEventFilter(MouseEvent.MOUSE_ENTERED, e -> homeController.mouseEvent(MouseEvent.MOUSE_ENTERED, - exploreVideo, exploreView, exploreHeader, null, colorAdjust)); - explorePane.addEventFilter(MouseEvent.MOUSE_EXITED, e -> homeController.mouseEvent(MouseEvent.MOUSE_EXITED, - exploreVideo, exploreView, exploreHeader, colorAdjust, null)); - // Play the video + explorePane.addEventFilter(MouseEvent.MOUSE_ENTERED, e -> homeController.mouseEvent( + MouseEvent.MOUSE_ENTERED, exploreVideo, exploreView, exploreHeader, null, colorAdjust)); + explorePane.addEventFilter(MouseEvent.MOUSE_EXITED, e -> homeController.mouseEvent( + MouseEvent.MOUSE_EXITED, exploreVideo, exploreView, exploreHeader, colorAdjust, null)); + + Text header = new GameHeader("Welcome to ChaosGame"); StackPane.setAlignment(header, Pos.TOP_CENTER); StackPane.setAlignment(exitButton, Pos.BOTTOM_CENTER); @@ -97,6 +94,11 @@ public class HomePage extends StackPane { getChildren().addAll(videoBox, header, exitButton); } + /** + * Binds the width and height of the panes to the width and height of the main pane. + * + * @param pane the main pane + */ public void setBind(Pane pane) { explorePane.prefWidthProperty().bind(pane.widthProperty()); chaosPane.prefWidthProperty().bind(pane.widthProperty()); diff --git a/src/main/java/org/example/chaosgame/view/components/AlertUtility.java b/src/main/java/org/example/chaosgame/view/components/AlertUtility.java index 8513a3738525e572a64714b33571d240585f0702..f0b2af5dea9aba7efd9b49e42504a59126062813 100644 --- a/src/main/java/org/example/chaosgame/view/components/AlertUtility.java +++ b/src/main/java/org/example/chaosgame/view/components/AlertUtility.java @@ -6,7 +6,13 @@ import javafx.scene.control.Alert; * Utility class for showing alert dialogs. */ public class AlertUtility { - public static void showErrorDialog(String title, String message){ + /** + * Shows an error dialog with the given title and message. + * + * @param title The title of the dialog. + * @param message The message of the dialog. + */ + public static void showErrorDialog(String title, String message) { Alert alert = new Alert(Alert.AlertType.ERROR); alert.setTitle(title); alert.setHeaderText(null); diff --git a/src/main/java/org/example/chaosgame/view/components/BaseSlider.java b/src/main/java/org/example/chaosgame/view/components/BaseSlider.java index 95029d0370dc490c1911f7f823c57b9232b72fac..6f21a499d228cdb4bf26a27b57e9fbde446fb943 100644 --- a/src/main/java/org/example/chaosgame/view/components/BaseSlider.java +++ b/src/main/java/org/example/chaosgame/view/components/BaseSlider.java @@ -1,16 +1,23 @@ package org.example.chaosgame.view.components; import javafx.scene.control.Slider; -import org.example.chaosgame.controller.ChaosGameController; -import org.example.chaosgame.controller.observer.GameController; +import org.example.chaosgame.controller.interfaces.GameController; /** * Abstract class for sliders in the GUI to Julia values. + * Extends the Slider class. */ public abstract class BaseSlider extends Slider { + /** + * Constructor for the BaseSlider. + * + * @param gameController the game controller + */ public BaseSlider(GameController gameController) { super(); + this.setMin(-1); + this.setMax(1); this.setValue(0); this.setShowTickLabels(true); this.setMaxWidth(200); diff --git a/src/main/java/org/example/chaosgame/view/components/BottomBar.java b/src/main/java/org/example/chaosgame/view/components/BottomBar.java index be58ff8f806550a3ead73e8030018319db28e4b9..00d8d3677d5c8916bc5c5d37845ce30af3f82b87 100644 --- a/src/main/java/org/example/chaosgame/view/components/BottomBar.java +++ b/src/main/java/org/example/chaosgame/view/components/BottomBar.java @@ -3,8 +3,7 @@ package org.example.chaosgame.view.components; import javafx.geometry.Pos; import javafx.scene.control.Label; import javafx.scene.layout.HBox; - -import org.example.chaosgame.controller.observer.GameController; +import org.example.chaosgame.controller.interfaces.GameController; import org.example.chaosgame.model.linalg.Complex; import org.example.chaosgame.model.transformations.ExploreJulia; import org.example.chaosgame.model.transformations.JuliaTransform; @@ -12,15 +11,14 @@ import org.example.chaosgame.model.transformations.Transform2D; /** - * Bottom bar of the GUI. - * - * <p>Contains sliders and labels for the real and imaginary part of the Julia value. + * Bottom bar of the GUI, extends HBox. + * Contains sliders and labels for the real and imaginary part of the Julia value. */ public class BottomBar extends HBox { - private Label realPartLabel; - private Label imaginaryPartLabel; - private SliderRealPart sliderRealPart; - private SliderImaginaryPart sliderImaginaryPart; + private final Label realPartLabel; + private final Label imaginaryPartLabel; + private final SliderRealPart sliderRealPart; + private final SliderImaginaryPart sliderImaginaryPart; /** * Constructor for the bottom bar. @@ -48,6 +46,12 @@ public class BottomBar extends HBox { this.getStyleClass().add("top-bottom-bar"); } + /** + * Check if the transformation is a Julia transformation or an ExploreJulia transformation. + * Else, hide the sliders and labels. + * + * @param transformation the transformation to update the bottom bar with + */ public void updateBottomBar(Transform2D transformation) { if (transformation instanceof JuliaTransform juliaTransform) { juliaInformation(juliaTransform.getComplex()); @@ -58,6 +62,11 @@ public class BottomBar extends HBox { } } + /** + * Update the bottom bar with the Julia value. + * + * @param complex the complex number to update the bottom bar with + */ private void juliaInformation(Complex complex) { sliderInfoVisibility(true); sliderRealPart.setValue(complex.getX()); @@ -66,15 +75,15 @@ public class BottomBar extends HBox { imaginaryPartLabel.setText("Imaginary Part: " + (double) Math.round(complex.getY() * 100) / 100); } + /** + * Set the visibility of the sliders and labels. + * + * @param isVisible the visibility of the sliders and labels + */ private void sliderInfoVisibility(boolean isVisible) { realPartLabel.setVisible(isVisible); imaginaryPartLabel.setVisible(isVisible); sliderRealPart.setVisible(isVisible); sliderImaginaryPart.setVisible(isVisible); } - - public void setBottomBarStyle(String text) { - realPartLabel.getStyleClass().add(text); - imaginaryPartLabel.getStyleClass().add(text); - } } diff --git a/src/main/java/org/example/chaosgame/view/components/ColorPickerComponent.java b/src/main/java/org/example/chaosgame/view/components/ColorPickerComponent.java index 8b1e0361cf1a3e3f09dd1bc8fe12741e7724ae65..643fe4576a7d6385a76ca74c46f65a760337c6a4 100644 --- a/src/main/java/org/example/chaosgame/view/components/ColorPickerComponent.java +++ b/src/main/java/org/example/chaosgame/view/components/ColorPickerComponent.java @@ -5,7 +5,7 @@ import javafx.scene.control.ColorPicker; import javafx.scene.paint.Color; /** - * Color picker component using ColorPicker from JavaFX. + * Class for the color picker component, extends ColorPicker. */ public class ColorPickerComponent extends ColorPicker { /** diff --git a/src/main/java/org/example/chaosgame/view/components/CreateAffinePane.java b/src/main/java/org/example/chaosgame/view/components/CreateAffinePane.java index f439278a2c1c5277c8baad5d1db2fcada8f71d48..c8bdcdc9ab335c2ce0abfb8322b09a6134eec46b 100644 --- a/src/main/java/org/example/chaosgame/view/components/CreateAffinePane.java +++ b/src/main/java/org/example/chaosgame/view/components/CreateAffinePane.java @@ -9,7 +9,7 @@ import javafx.scene.layout.GridPane; import javafx.scene.layout.HBox; /** - * Pane for creating affine transformations. + * Class for the CreateAffinePane, extends GridPane. */ public class CreateAffinePane extends GridPane { private final List<List<TextField>> lines; @@ -97,6 +97,11 @@ public class CreateAffinePane extends GridPane { this.getChildren().remove(lastVectorBox); } + /** + * Get the result of the affine transformation creation. + * + * @return the matrix and vector of the affine transformation + */ public List<List<String>> getResult() { List<List<String>> result = new ArrayList<>(); for (List<TextField> line : lines) { diff --git a/src/main/java/org/example/chaosgame/view/components/CreateFractalDialog.java b/src/main/java/org/example/chaosgame/view/components/CreateFractalDialog.java index e9ed761b27914b87b415b0d732aa5be0a09ed983..7ee80bf29e35cb1d486c24b56b7db6bb7a06a10d 100644 --- a/src/main/java/org/example/chaosgame/view/components/CreateFractalDialog.java +++ b/src/main/java/org/example/chaosgame/view/components/CreateFractalDialog.java @@ -1,12 +1,25 @@ package org.example.chaosgame.view.components; import javafx.geometry.Insets; -import javafx.scene.control.*; +import javafx.scene.control.ButtonBar; +import javafx.scene.control.ButtonType; +import javafx.scene.control.Dialog; +import javafx.scene.control.RadioButton; +import javafx.scene.control.ToggleGroup; import javafx.scene.layout.HBox; import javafx.scene.layout.StackPane; import javafx.scene.layout.VBox; +/** + * Class for the CreateFractalDialog, extends Dialog. + * Lets the user create their own fractal. + */ public class CreateFractalDialog extends Dialog<Object> { + /** + * Constructor for the CreateFractalDialog. + * + * <p>Creates a dialog for the user to create their own fractal. + */ public CreateFractalDialog() { this.setTitle("Create Fractal"); this.setHeaderText("Select the type of fractal to create."); @@ -15,25 +28,25 @@ public class CreateFractalDialog extends Dialog<Object> { this.getDialogPane().getButtonTypes().addAll(createButtonType, ButtonType.CANCEL); ToggleGroup group = new ToggleGroup(); - - HBox buttonBox = new HBox(); RadioButton affineButton = new RadioButton("Affine"); + affineButton.setToggleGroup(group); affineButton.setSelected(true); RadioButton juliaButton = new RadioButton("Julia"); juliaButton.setToggleGroup(group); + HBox buttonBox = new HBox(); buttonBox.setSpacing(30); buttonBox.getChildren().addAll(affineButton, juliaButton); - CreateAffinePane affinePane = new CreateAffinePane(); - CreateJuliaPane juliaPane = new CreateJuliaPane(); - StackPane content = new StackPane(); content.setPadding(new Insets(10)); content.setMinHeight(200); content.setMinWidth(400); + + CreateAffinePane affinePane = new CreateAffinePane(); + CreateJuliaPane juliaPane = new CreateJuliaPane(); content.getChildren().addAll(affinePane, juliaPane); affinePane.visibleProperty().bind(affineButton.selectedProperty()); diff --git a/src/main/java/org/example/chaosgame/view/components/CreateJuliaPane.java b/src/main/java/org/example/chaosgame/view/components/CreateJuliaPane.java index c4b42a838ad607ed734a00c0b71e3804671f3762..ecbec347ece7e46b313405f9eb4e0b93810b2ebd 100644 --- a/src/main/java/org/example/chaosgame/view/components/CreateJuliaPane.java +++ b/src/main/java/org/example/chaosgame/view/components/CreateJuliaPane.java @@ -5,7 +5,7 @@ import javafx.scene.layout.HBox; import javafx.util.Pair; /** - * Pane for creating Julia values. + * Class for the CreateJuliaPane, extends HBox. */ public class CreateJuliaPane extends HBox { private final TextField realPart; diff --git a/src/main/java/org/example/chaosgame/view/components/DoubleSlider.java b/src/main/java/org/example/chaosgame/view/components/DoubleSlider.java deleted file mode 100644 index b0644b91d8b5e40c26fe53754808605eee0ece7f..0000000000000000000000000000000000000000 --- a/src/main/java/org/example/chaosgame/view/components/DoubleSlider.java +++ /dev/null @@ -1,35 +0,0 @@ -package org.example.chaosgame.view.components; - -import javafx.scene.control.Slider; -import javafx.scene.layout.HBox; -import org.example.chaosgame.controller.ChaosGameController; -import org.example.chaosgame.controller.ExploreGameController; -import org.example.chaosgame.model.chaos.ExploreGame; - -import java.util.List; - -public class DoubleSlider extends Slider { - public DoubleSlider(ChaosGameController chaosGameController) { - //min value -1 and max is 1 - super(); - this.setMin(-1); - this.setMax(1); - this.setValue(0); - this.setShowTickLabels(true); - this.setShowTickMarks(true); - this.setMaxWidth(200); - - } - - public DoubleSlider(ExploreGameController exploreGameController) { - //min value -1 and max is 1 - super(); - this.setMin(-1); - this.setMax(1); - this.setValue(0); - this.setShowTickLabels(true); - this.setShowTickMarks(true); - this.setMaxWidth(200); - } - -} diff --git a/src/main/java/org/example/chaosgame/view/components/ExitButton.java b/src/main/java/org/example/chaosgame/view/components/ExitButton.java index b5ba68ce9d11cd2c7160465fef626068192f7ad4..da97319bd86de1965b4987ab43f12b108a357ae1 100644 --- a/src/main/java/org/example/chaosgame/view/components/ExitButton.java +++ b/src/main/java/org/example/chaosgame/view/components/ExitButton.java @@ -3,7 +3,7 @@ package org.example.chaosgame.view.components; import javafx.scene.control.Button; /** - * Button for exiting the application. + * Class for the exit button, extends Button. */ public class ExitButton extends Button { public ExitButton() { diff --git a/src/main/java/org/example/chaosgame/view/components/FractalSelectionBox.java b/src/main/java/org/example/chaosgame/view/components/FractalSelectionBox.java index 925d8ece665bf12f8b881cd29f12dd8290712ff6..f4f8edc93d77d0b71b889d584d18113232bf6e70 100644 --- a/src/main/java/org/example/chaosgame/view/components/FractalSelectionBox.java +++ b/src/main/java/org/example/chaosgame/view/components/FractalSelectionBox.java @@ -4,7 +4,8 @@ import javafx.scene.control.ComboBox; import org.example.chaosgame.controller.ChaosGameController; /** - * ComboBox for selecting already implemented fractals. + * Class for the FractalSelectionBox, extends ComboBox. + * Creates a ComboBox for selecting already implemented fractals. */ public class FractalSelectionBox extends ComboBox<String> { diff --git a/src/main/java/org/example/chaosgame/view/components/GameButton.java b/src/main/java/org/example/chaosgame/view/components/GameButton.java index 9e1621189fa4c63c5e6c4aa238d2bc74744b1c52..5f16d81db046dbd8e00d7120428a7f57c96d4ace 100644 --- a/src/main/java/org/example/chaosgame/view/components/GameButton.java +++ b/src/main/java/org/example/chaosgame/view/components/GameButton.java @@ -3,10 +3,16 @@ package org.example.chaosgame.view.components; import javafx.scene.control.Button; /** - * Button for the game related functions. + * Class for the game button, extends Button. + * The button is used for game related actions. */ public class GameButton extends Button { - public GameButton(String text){ + /** + * Constructor for the GameButton. + * + * @param text the text to be displayed on the button + */ + public GameButton(String text) { super(text); this.setMaxWidth(180); this.setMinWidth(180); diff --git a/src/main/java/org/example/chaosgame/view/components/GameHeader.java b/src/main/java/org/example/chaosgame/view/components/GameHeader.java index 716f6435ac504e44d2c996d03bfeabeb561f56fa..5de562b39bab0d07741a87f7c121a4ad1b0978a5 100644 --- a/src/main/java/org/example/chaosgame/view/components/GameHeader.java +++ b/src/main/java/org/example/chaosgame/view/components/GameHeader.java @@ -3,9 +3,15 @@ package org.example.chaosgame.view.components; import javafx.scene.text.Text; /** - * Header for the application, in HomePage. + * Class for the game header, extends Text. + * The header is used for displaying the game title. */ public class GameHeader extends Text { + /** + * Constructor for the GameHeader. + * + * @param text the text to be displayed on the header + */ public GameHeader(String text) { super(text); this.getStyleClass().add("game-header"); diff --git a/src/main/java/org/example/chaosgame/view/components/HomeButton.java b/src/main/java/org/example/chaosgame/view/components/HomeButton.java index 59ac6b77e7a7fcaed1d2492b3e70685b998b111d..dbf47ed8220f0155dbffbf1e04f4dfba4cfb82f8 100644 --- a/src/main/java/org/example/chaosgame/view/components/HomeButton.java +++ b/src/main/java/org/example/chaosgame/view/components/HomeButton.java @@ -1,20 +1,26 @@ package org.example.chaosgame.view.components; +import java.util.Objects; import javafx.scene.control.Button; import javafx.scene.image.Image; import javafx.scene.image.ImageView; -import javafx.scene.layout.StackPane; -import org.example.chaosgame.controller.ChaosGameController; -import java.util.Objects; +/** + * Class for the home button, extends Button. + * The button is used for navigating to the home screen. + */ public class HomeButton extends Button { - public HomeButton(){ + /** + * Constructor for the HomeButton. + * Sets the icon for the home button. + */ + public HomeButton() { super(); - String filePath = Objects.requireNonNull(getClass().getResource("/White-home-icon.png")).toString(); + String filePath = Objects.requireNonNull(getClass() + .getResource("/White-home-icon.png")).toString(); ImageView homeIcon = new ImageView(new Image(filePath)); homeIcon.setFitHeight(24); homeIcon.setFitWidth(24); this.setGraphic(homeIcon); - } } diff --git a/src/main/java/org/example/chaosgame/view/components/MinMaxDialog.java b/src/main/java/org/example/chaosgame/view/components/MinMaxDialog.java index 57d2605335844b1d5a8afd19052461204b9b0225..de0589baaeeaf30a31be6beca32ff59313c70893 100644 --- a/src/main/java/org/example/chaosgame/view/components/MinMaxDialog.java +++ b/src/main/java/org/example/chaosgame/view/components/MinMaxDialog.java @@ -1,20 +1,25 @@ package org.example.chaosgame.view.components; +import java.util.List; import javafx.scene.control.ButtonType; import javafx.scene.control.Dialog; import javafx.scene.control.TextField; import javafx.scene.layout.GridPane; -import javafx.util.Pair; -import org.example.chaosgame.model.linalg.Vector2D; - -import java.util.List; +/** + * Class for the MinMaxDialog, extends Dialog. + * The dialog has fields for the min and max x and y coordinates. + */ public class MinMaxDialog extends Dialog<List<String>> { private final TextField minXField; private final TextField minYField; private final TextField maxXField; private final TextField maxYField; + /** + * Constructor for the MinMaxDialog. + * Creates a dialog for setting the min and max coordinates. + */ public MinMaxDialog() { setTitle("Set Min/Max Coordinates"); setHeaderText("Please enter the min and max coordinates:"); diff --git a/src/main/java/org/example/chaosgame/view/components/NumberOfStepsInput.java b/src/main/java/org/example/chaosgame/view/components/NumberOfStepsInput.java index d8c0d9c4880634a5108548ee6ba1053f803f6dd4..75bb62a31935405af03581c2e174827dc0bdb991 100644 --- a/src/main/java/org/example/chaosgame/view/components/NumberOfStepsInput.java +++ b/src/main/java/org/example/chaosgame/view/components/NumberOfStepsInput.java @@ -3,9 +3,14 @@ package org.example.chaosgame.view.components; import javafx.scene.control.TextField; /** - * Input for the number of steps. + * Class for the NumberOfStepsInput, extends TextField. + * The input is used for setting the number of steps for the game. */ public class NumberOfStepsInput extends TextField { + /** + * Constructor for the NumberOfStepsInput. + * Sets the prompt text for the input. + */ public NumberOfStepsInput() { this.setPromptText("Number of steps"); this.setMaxWidth(180); diff --git a/src/main/java/org/example/chaosgame/view/components/SideBar.java b/src/main/java/org/example/chaosgame/view/components/SideBar.java index 57e22953ce05cc34df4cab6c79e9e5ebe0881052..7102f0ea6ce0165b4c158394be74adf77fd2bc4e 100644 --- a/src/main/java/org/example/chaosgame/view/components/SideBar.java +++ b/src/main/java/org/example/chaosgame/view/components/SideBar.java @@ -8,27 +8,44 @@ import javafx.scene.layout.VBox; import org.example.chaosgame.controller.ChaosGameController; import org.example.chaosgame.controller.ExploreGameController; +/** + * Class for the sidebar, extends VBox. + * The sidebar is used for displaying buttons and input fields for the game. + * The class uses two constructors, one for the ChaosGame and one for the ExploreGame. + */ public class SideBar extends VBox { + /** + * Constructor for the SideBar. + * Creates the sidebar for the ChaosGame. + * Event handlers are added to the buttons, + * and call the corresponding methods in the ChaosGameController. + * + * @param chaosGameController the ChaosGameController + */ public SideBar(ChaosGameController chaosGameController) { - FractalSelectionBox fractalSelectionBox = new FractalSelectionBox(chaosGameController); - ColorPickerComponent colorPicker = new ColorPickerComponent(chaosGameController::updateFractalColor); - TextField numberOfStepsInput = new NumberOfStepsInput(); - Button coordinatesButton = new GameButton("Set coordinates"); + coordinatesButton.setOnAction(event -> chaosGameController.setMaxMinCoords()); + Button createOwnFractal = new GameButton("Create fractal"); + createOwnFractal.setOnAction(event -> chaosGameController.createOwnFractal()); + Button openFileButton = new GameButton("Open file"); + openFileButton.setOnAction(event -> chaosGameController.openFromFile()); + Button saveFractalButton = new GameButton("Save fractal"); + saveFractalButton.setOnAction(event -> chaosGameController.saveFractal()); + TextField numberOfStepsInput = new NumberOfStepsInput(); Button runGame = new GameButton("Run steps"); - Button resetGame = new GameButton("Clear canvas"); - - coordinatesButton.setOnAction(event -> chaosGameController.setMaxMinCoords()); - createOwnFractal.setOnAction(event -> chaosGameController.createOwnFractal()); - openFileButton.setOnAction(event -> chaosGameController.openFromFile()); - saveFractalButton.setOnAction(event -> chaosGameController.saveFractal()); runGame.setOnAction(event -> chaosGameController.runStepsValidation(numberOfStepsInput)); + + Button resetGame = new GameButton("Clear canvas"); resetGame.setOnAction(event -> chaosGameController.resetGame()); + FractalSelectionBox fractalSelectionBox = new FractalSelectionBox(chaosGameController); + ColorPickerComponent colorPicker = new ColorPickerComponent( + chaosGameController::updateFractalColor); + this.getChildren().addAll( fractalSelectionBox, colorPicker, numberOfStepsInput, coordinatesButton, createOwnFractal, saveFractalButton, openFileButton, @@ -41,16 +58,25 @@ public class SideBar extends VBox { this.getStyleClass().add("side-bar"); } + /** + * Constructor for the SideBar. + * Creates the sidebar for the ExploreGame. + * + * @param exploreGameController the ExploreGameController + */ public SideBar(ExploreGameController exploreGameController) { Button zoomInButton = new GameButton("Zoom in"); - Button zoomOutButton = new GameButton("Zoom out"); - Button resetImage = new GameButton("Reset"); - ColorPickerComponent colorPicker = new ColorPickerComponent(exploreGameController::updateFractalColor); - zoomInButton.setOnAction(event -> exploreGameController.zoomButtonClicked(1 / 1.05)); + + Button zoomOutButton = new GameButton("Zoom out"); zoomOutButton.setOnAction(event -> exploreGameController.zoomButtonClicked(1.05)); + + Button resetImage = new GameButton("Reset"); resetImage.setOnAction(event -> exploreGameController.resetImage()); + ColorPickerComponent colorPicker = new ColorPickerComponent( + exploreGameController::updateFractalColor); + this.getChildren().addAll(zoomInButton, zoomOutButton, colorPicker, resetImage); this.setAlignment(Pos.CENTER_RIGHT); this.getStyleClass().add("side-bar"); diff --git a/src/main/java/org/example/chaosgame/view/components/SliderImaginaryPart.java b/src/main/java/org/example/chaosgame/view/components/SliderImaginaryPart.java index 14dfe2c2adb50d7b348b37cad1853146f39d741e..db2f476fd378b1bacdf468427a8a003184835b20 100644 --- a/src/main/java/org/example/chaosgame/view/components/SliderImaginaryPart.java +++ b/src/main/java/org/example/chaosgame/view/components/SliderImaginaryPart.java @@ -1,17 +1,21 @@ package org.example.chaosgame.view.components; -import org.example.chaosgame.controller.ChaosGameController; -import org.example.chaosgame.controller.observer.GameController; +import org.example.chaosgame.controller.interfaces.GameController; /** - * Slider for the imaginary part of a complex number. + * Class for the imaginary part slider, extends BaseSlider. + * The slider is used for setting the imaginary part of the complex number. */ public class SliderImaginaryPart extends BaseSlider { + /** + * Constructor for the SliderImaginaryPart. + * + * @param gameController the game controller + */ public SliderImaginaryPart(GameController gameController) { super(gameController); - this.setMin(-1); - this.setMax(1); } + /** * {@inheritDoc} */ diff --git a/src/main/java/org/example/chaosgame/view/components/SliderRealPart.java b/src/main/java/org/example/chaosgame/view/components/SliderRealPart.java index 71369aa4ec183c15c57b9100d7d5edf0d6c346d5..1d9586fee9926401c6ae11fd03afb17777fddf46 100644 --- a/src/main/java/org/example/chaosgame/view/components/SliderRealPart.java +++ b/src/main/java/org/example/chaosgame/view/components/SliderRealPart.java @@ -1,13 +1,19 @@ package org.example.chaosgame.view.components; -import org.example.chaosgame.controller.ChaosGameController; -import org.example.chaosgame.controller.observer.GameController; +import org.example.chaosgame.controller.interfaces.GameController; +/** + * Class for the real part slider, extends BaseSlider. + * The slider is used for setting the real part of the complex number. + */ public class SliderRealPart extends BaseSlider { + /** + * Constructor for the SliderRealPart. + * + * @param gameController the game controller + */ public SliderRealPart(GameController gameController) { super(gameController); - this.setMin(-1); - this.setMax(1); } @Override diff --git a/src/main/java/org/example/chaosgame/view/components/TopBar.java b/src/main/java/org/example/chaosgame/view/components/TopBar.java index 70800bc8cddb59ae1b04ef9015df5a7dcca01542..8ffad6d296c05eadac91c21eea946166b5c5ecf0 100644 --- a/src/main/java/org/example/chaosgame/view/components/TopBar.java +++ b/src/main/java/org/example/chaosgame/view/components/TopBar.java @@ -4,17 +4,24 @@ import javafx.geometry.Pos; import javafx.scene.control.Button; import javafx.scene.control.Label; import javafx.scene.layout.HBox; -import org.example.chaosgame.controller.ChaosGameController; -import org.example.chaosgame.controller.ExploreGameController; -import org.example.chaosgame.controller.observer.GameController; +import org.example.chaosgame.controller.interfaces.GameController; import org.example.chaosgame.model.linalg.Vector2D; import org.example.chaosgame.model.transformations.Transform2D; +/** + * Class for the top bar, extends HBox. + * The top bar is used for displaying game information. + */ public class TopBar extends HBox { private final Label gameInfo; private final Label stepsLabel; private final Label coordinatesLabel; + /** + * Constructor for the TopBar. + * + * @param gameController the game controller + */ public TopBar(GameController gameController) { super(); this.gameInfo = new Label(); @@ -32,19 +39,31 @@ public class TopBar extends HBox { this.getStyleClass().add("top-bottom-bar"); } + /** + * Updates the top bar for the ChaosGame. + * + * @param first the first transformation + * @param totalSteps the total steps + * @param min the min coordinates + * @param max the max coordinates + */ public void updateTopBar(Transform2D first, int totalSteps, Vector2D min, Vector2D max) { gameInfo.setText("Transformation: " + first.getClass().getSimpleName()); - coordinatesLabel.setText("Min-Coordinate: " + min.getX() + ", " + min.getY() + - ". Max-Coordinate: " + max.getX() + ", " + max.getY()); + coordinatesLabel.setText("Min-Coordinate: " + min.getX() + ", " + min.getY() + + ". Max-Coordinate: " + max.getX() + ", " + max.getY()); stepsLabel.setText("Total steps: " + totalSteps); } + /** + * Updates the top bar for the ExploreGame. + * + * @param min the min coordinates + * @param max the max coordinates + */ public void updateTopBar(Vector2D min, Vector2D max) { - coordinatesLabel.setText("Min-Coordinate: " + (double) Math.round(min.getX() * 100) / 100 + ", " + (double) Math.round(min.getY() * 100) / 100 + - ". Max-Coordinate: " + (double) Math.round(max.getX() * 100) / 100 + ", " + (double) Math.round(max.getY() * 100) / 100); - } - - public void setTopBarStyle(String text) { - coordinatesLabel.getStyleClass().add(text); + coordinatesLabel.setText("Min-Coordinate: " + (double) Math.round(min.getX() * 100) / 100 + + ", " + (double) Math.round(min.getY() * 100) / 100 + + ". Max-Coordinate: " + (double) Math.round(max.getX() * 100) / 100 + ", " + + (double) Math.round(max.getY() * 100) / 100); } } diff --git a/src/test/java/org/example/chaosgame/linalg/Matrix2x2Test.java b/src/test/java/org/example/chaosgame/linalg/Matrix2x2Test.java index 7ae36e34c531857be0ff79a841a5eaca52f6ecb0..11ea00fbe6b85631de2e220b425df2ce2aa969f7 100644 --- a/src/test/java/org/example/chaosgame/linalg/Matrix2x2Test.java +++ b/src/test/java/org/example/chaosgame/linalg/Matrix2x2Test.java @@ -36,25 +36,25 @@ class Matrix2x2Test { @Test @DisplayName("Test getA") void getA() { - assertEquals(a, matrix.getA()); + assertEquals(a, matrix.a()); } @Test @DisplayName("Test getB") void getB() { - assertEquals(b, matrix.getB()); + assertEquals(b, matrix.b()); } @Test @DisplayName("Test getC") void getC() { - assertEquals(c, matrix.getC()); + assertEquals(c, matrix.c()); } @Test @DisplayName("Test getD") void getD() { - assertEquals(d, matrix.getD()); + assertEquals(d, matrix.d()); } }