diff --git a/src/main/java/edu/ntnu/idatt2003/controller/ButtonObserver.java b/src/main/java/edu/ntnu/idatt2003/controller/ButtonObserver.java index 6b8274e853e08163a87fd045acf5e38a2a59cd7a..63f0db5b850ec4be96b6504065c5cc8e83ee1332 100644 --- a/src/main/java/edu/ntnu/idatt2003/controller/ButtonObserver.java +++ b/src/main/java/edu/ntnu/idatt2003/controller/ButtonObserver.java @@ -214,7 +214,7 @@ public class ButtonObserver implements Observer { ChaosGameDescription description = new ChaosGameDescription(transforms, lowerLeft, upperRight); System.out.println("Transforms updated: " + transforms.size()); - fractalOperations.updateMatrixAndVector(description); + fractalOperations.updateDescription(description); } private double parseInput(TextField textField) throws InvalidInputException { diff --git a/src/main/java/edu/ntnu/idatt2003/controller/ChaosGameObserver.java b/src/main/java/edu/ntnu/idatt2003/controller/ChaosGameObserver.java index edef5cbc6a6d83c5f5aab821a119c493d94c6d74..f0d253fb46973d3b3ac31eb25a46fdead48430ad 100644 --- a/src/main/java/edu/ntnu/idatt2003/controller/ChaosGameObserver.java +++ b/src/main/java/edu/ntnu/idatt2003/controller/ChaosGameObserver.java @@ -3,5 +3,5 @@ package edu.ntnu.idatt2003.controller; import edu.ntnu.idatt2003.model.ChaosGame; public interface ChaosGameObserver { - void update(ChaosGame chaosGame); + void update(); } diff --git a/src/main/java/edu/ntnu/idatt2003/model/ChaosGame.java b/src/main/java/edu/ntnu/idatt2003/model/ChaosGame.java index 8be6530724c0ae755242bd9dfccc5dd93f09b9c9..2c04924c2b4d33d33ce867471015999de4a048b8 100644 --- a/src/main/java/edu/ntnu/idatt2003/model/ChaosGame.java +++ b/src/main/java/edu/ntnu/idatt2003/model/ChaosGame.java @@ -11,7 +11,7 @@ import java.util.Random; */ public class ChaosGame { private final ChaosCanvas canvas; - private final ChaosGameDescription description; + private ChaosGameDescription description; private Vector2D currentPoint; private final Random random; private final List<ChaosGameObserver> observers; @@ -68,6 +68,10 @@ public class ChaosGame { return description; } + public void setDescription(ChaosGameDescription description) { + this.description = description; + } + public void addObserver(ChaosGameObserver observer) { observers.add(observer); } @@ -78,7 +82,7 @@ public class ChaosGame { private void notifyObservers() { for (ChaosGameObserver observer : observers) { - observer.update(this); + observer.update(); } } } diff --git a/src/main/java/edu/ntnu/idatt2003/view/components/FractalOperations.java b/src/main/java/edu/ntnu/idatt2003/view/components/FractalOperations.java index d72dc2698e6632c79e701c50aab187de871b80fb..59056ae1b15cc2b41d9b8b1d1bd703d09237677a 100644 --- a/src/main/java/edu/ntnu/idatt2003/view/components/FractalOperations.java +++ b/src/main/java/edu/ntnu/idatt2003/view/components/FractalOperations.java @@ -37,7 +37,6 @@ public class FractalOperations implements ChaosGameObserver { public void drawFractal(int iterations) { chaosGame.runSteps(iterations); - updateImage(); } public void resetIterations() { @@ -48,21 +47,6 @@ public class FractalOperations implements ChaosGameObserver { } } - /** - * Updates the image of the fractal. - */ - public void updateImage() { - PixelWriter pixelWriter = writableImage.getPixelWriter(); - int[][] canvasArray = chaosGame.getCanvas().getCanvasArray(); - for (int y = 0; y < chaosGame.getCanvas().getHeight(); y++) { - for (int x = 0; x < chaosGame.getCanvas().getWidth(); x++) { - int pixel = canvasArray[y][x]; - Color color = pixel == 1 ? Color.BLACK : Color.WHITE; - pixelWriter.setColor(x, y, color); - } - } - } - /** * Sets the fractal to Sierpinski Triangle. */ @@ -115,7 +99,8 @@ public class FractalOperations implements ChaosGameObserver { defaultLowerLeft, defaultUpperRight); this.chaosGame = new ChaosGame(description, 400, 400); this.chaosGame.addObserver(this); - drawFractal(0); + //drawFractal(0); + updateImage(); } /** @@ -134,7 +119,7 @@ public class FractalOperations implements ChaosGameObserver { * * @param description the ChaosGameDescription */ - public void updateMatrixAndVector(ChaosGameDescription description) { + public void updateDescription(ChaosGameDescription description) { this.chaosGame = new ChaosGame(description, 400, 400); this.chaosGame.addObserver(this); drawFractal(0); @@ -185,12 +170,27 @@ public class FractalOperations implements ChaosGameObserver { } } + /** + * Updates the image of the fractal. + */ + public void updateImage() { + PixelWriter pixelWriter = writableImage.getPixelWriter(); + int[][] canvasArray = chaosGame.getCanvas().getCanvasArray(); + for (int y = 0; y < chaosGame.getCanvas().getHeight(); y++) { + for (int x = 0; x < chaosGame.getCanvas().getWidth(); x++) { + int pixel = canvasArray[y][x]; + Color color = pixel == 1 ? Color.BLACK : Color.WHITE; + pixelWriter.setColor(x, y, color); + } + } + } + public ChaosGameDescription getDescription() { return chaosGame.getDescription(); } @Override - public void update(ChaosGame chaosGame) { + public void update() { updateImage(); } } diff --git a/src/main/java/edu/ntnu/idatt2003/view/scenes/Scene.java b/src/main/java/edu/ntnu/idatt2003/view/scenes/Scene.java index 8119fb6c4e492c2ebd07c194d7f0abb2e878a115..c0f34e17ca540fa94c5f2cb8ee9eb9d8d85c2592 100644 --- a/src/main/java/edu/ntnu/idatt2003/view/scenes/Scene.java +++ b/src/main/java/edu/ntnu/idatt2003/view/scenes/Scene.java @@ -14,8 +14,12 @@ import javafx.scene.layout.AnchorPane; import javafx.scene.layout.BorderPane; import javafx.scene.layout.HBox; import javafx.scene.layout.VBox; +import javafx.scene.paint.Paint; import javafx.stage.Stage; +import java.awt.*; +import java.awt.event.MouseEvent; +import javafx.scene.shape.Rectangle; import java.util.ArrayList; import java.util.Arrays; import java.util.List; @@ -42,6 +46,8 @@ public class Scene { private ComboBoxObserver comboBoxObserver; private LabelObserver labelObserver; private TextFieldObserver textFieldObserver; + private double startX, startY, endX, endY; + private Rectangle selectionRectangle; /** * Constructor for the AffineScene class @@ -197,6 +203,17 @@ public class Scene { AnchorPane.setTopAnchor(inputBox, 65.0); AnchorPane.setRightAnchor(inputBox, 30.0); + selectionRectangle = new Rectangle(); + selectionRectangle.setFill(null); + selectionRectangle.setStroke(Paint.valueOf("BLACK")); + root.getChildren().add(selectionRectangle); + + // Add mouse event handlers to the ImageView + imageView.setOnMousePressed(this::handleMousePressed); + imageView.setOnMouseDragged(this::handleMouseDragged); + imageView.setOnMouseReleased(this::handleMouseReleased); + + // Create a scene with the root and set the CSS style scene = new javafx.scene.Scene(root, 1400, 830); scene.getStylesheets().add(getClass().getResource("/style.css").toExternalForm()); @@ -415,6 +432,56 @@ public class Scene { textFields.getyMaxInput().setText(String.valueOf(fractalOperations.getChaosGame().getDescription().getMaxCoords().getX1())); } + private void handleMousePressed(javafx.scene.input.MouseEvent event) { + startX = event.getX(); + startY = event.getY(); + selectionRectangle.setX(startX); + selectionRectangle.setY(startY); + selectionRectangle.setWidth(0); + selectionRectangle.setHeight(0); + } + + private void handleMouseDragged(javafx.scene.input.MouseEvent event) { + endX = event.getX(); + endY = event.getY(); + selectionRectangle.setWidth(Math.abs(endX - startX)); + selectionRectangle.setHeight(Math.abs(endY - startY)); + selectionRectangle.setX(Math.min(startX, endX)); + selectionRectangle.setY(Math.min(startY, endY)); + } + + private void handleMouseReleased(javafx.scene.input.MouseEvent event) { + endX = event.getX(); + endY = event.getY(); + if (Math.abs(endX - startX) > 5 && Math.abs(endY - startY) > 5) { + applyZoom(); + } + selectionRectangle.setWidth(0); + selectionRectangle.setHeight(0); + } + + private void applyZoom() { + double imageWidth = imageView.getBoundsInLocal().getWidth(); + double imageHeight = imageView.getBoundsInLocal().getHeight(); + + double xMin = fractalOperations.getChaosGame().getDescription().getMinCoords().getX0(); + double yMin = fractalOperations.getChaosGame().getDescription().getMinCoords().getX1(); + double xMax = fractalOperations.getChaosGame().getDescription().getMaxCoords().getX0(); + double yMax = fractalOperations.getChaosGame().getDescription().getMaxCoords().getX1(); + + double newMinX = xMin + (startX / imageWidth) * (xMax - xMin); + double newMaxX = xMin + (endX / imageWidth) * (xMax - xMin); + double newMinY = yMin + (startY / imageHeight) * (yMax - yMin); + double newMaxY = yMin + (endY / imageHeight) * (yMax - yMin); + + Vector2D newMinCoords = new Vector2D(Math.min(newMinX, newMaxX), Math.min(newMinY, newMaxY)); + Vector2D newMaxCoords = new Vector2D(Math.max(newMinX, newMaxX), Math.max(newMinY, newMaxY)); + + fractalOperations.updateMinAndMaxFractal(newMinCoords, newMaxCoords); + updateVectorInputFields(); + fractalOperations.drawFractal(100000000); // Optionally redraw with initial iterations + } + public void setUpStage(Stage primaryStage) { primaryStage.setTitle("ChaosGame"); primaryStage.setScene(scene);