diff --git a/src/main/java/edu/ntnu/idatt2003/mappevurderingprog2/MyApp.java b/src/main/java/edu/ntnu/idatt2003/mappevurderingprog2/MyApp.java index 39e4cb57e25a158d638d11ebc37164ace83e02d1..855a87f72df85bbb5b315484d2940131f433fa7d 100644 --- a/src/main/java/edu/ntnu/idatt2003/mappevurderingprog2/MyApp.java +++ b/src/main/java/edu/ntnu/idatt2003/mappevurderingprog2/MyApp.java @@ -1,5 +1,6 @@ package edu.ntnu.idatt2003.mappevurderingprog2; +import edu.ntnu.idatt2003.mappevurderingprog2.controllers.CanvasController; import edu.ntnu.idatt2003.mappevurderingprog2.controllers.GameController; import edu.ntnu.idatt2003.mappevurderingprog2.models.chaos.ChaosGame; import edu.ntnu.idatt2003.mappevurderingprog2.views.View; @@ -22,7 +23,8 @@ public class MyApp extends Application { @Override public void start(Stage primaryStage) throws FileNotFoundException { GameController gameController = new GameController(); - View view = new View(gameController); + CanvasController canvasController = new CanvasController(); + View view = new View(gameController, canvasController); ChaosGame.getInstance().addObserver(view); primaryStage.setScene(view.createScene()); primaryStage.show(); diff --git a/src/main/java/edu/ntnu/idatt2003/mappevurderingprog2/controllers/CanvasController.java b/src/main/java/edu/ntnu/idatt2003/mappevurderingprog2/controllers/CanvasController.java new file mode 100644 index 0000000000000000000000000000000000000000..cecb931f97c3b130137f710af540f836a9a1d901 --- /dev/null +++ b/src/main/java/edu/ntnu/idatt2003/mappevurderingprog2/controllers/CanvasController.java @@ -0,0 +1,112 @@ +package edu.ntnu.idatt2003.mappevurderingprog2.controllers; + +import edu.ntnu.idatt2003.mappevurderingprog2.models.chaos.ChaosGame; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import javafx.scene.canvas.Canvas; +import javafx.scene.canvas.GraphicsContext; +import javafx.scene.paint.Color; + +/** + * The CanvasController class is a controller class that handles the logic for the Canvas. + * The class is responsible for updating the canvas display and setting the canvas width and height. + */ + +public class CanvasController { + + // Private integer for the green threshold. + private int greenThreshold; + + // Private integer for the blue threshold. + private int blueThreshold; + + /** + * Calculates the quantiles for the hits. + */ + public void calculateQuantiles() { + List<Integer> hitCounts = new ArrayList<>(); + for (int[] row : ChaosGame.getInstance().getCanvas().getCanvasArray()) { + for (int hit : row) { + if (hit > 0) { + hitCounts.add(hit); + } + } + } + + if (hitCounts.isEmpty()) { + return; + } + + Collections.sort(hitCounts); + int n = hitCounts.size(); + greenThreshold = hitCounts.get((int) (n * 0.33)); + blueThreshold = hitCounts.get((int) (n * 0.66)); + } + + /** + * Returns the color for the hits. + * + * @param hits the number of hits. + * @return the color for the hits. + */ + private Color getColorForHits(int hits) { + if (hits == 0) { + return Color.WHITE; + } else if (hits <= greenThreshold) { + return Color.GREEN; + } else if (hits <= blueThreshold) { + return Color.BLUE; + } else { + return Color.RED; + } + } + + /** + * Updates the canvas display. + * + * @param mainCanvas the main canvas. + * @return the updated canvas. + */ + public Canvas updateCanvasDisplay(Canvas mainCanvas) { + GraphicsContext gc = mainCanvas.getGraphicsContext2D(); + int[][] canvasArray = ChaosGame.getInstance().getCanvas().getCanvasArray(); + double canvasWidth = mainCanvas.getWidth() - 20; + double canvasHeight = mainCanvas.getHeight() - 20; + double pixelWidth = canvasWidth / canvasArray[0].length; + double pixelHeight = canvasHeight / canvasArray.length; + + gc.clearRect(0, 0, mainCanvas.getWidth(), mainCanvas.getHeight()); + for (int i = 0; i < canvasArray.length; i++) { + for (int j = 0; j < canvasArray[i].length; j++) { + double x = j * pixelWidth + 3; + double y = i * pixelHeight + 3; + gc.setFill(getColorForHits(canvasArray[i][j])); + gc.fillRect(x, y, pixelWidth, pixelHeight); + } + } + return mainCanvas; + } + + /** + * Sets the canvas width. + * + * @param canvas the canvas. + * @param width the width. + */ + public void setCanvasWidth(Canvas canvas, double width) { + canvas.setWidth(width); + updateCanvasDisplay(canvas); + } + + /** + * Sets the canvas height. + * + * @param canvas the canvas. + * @param height the height. + */ + public void setCanvasHeight(Canvas canvas, double height) { + canvas.setHeight(height); + updateCanvasDisplay(canvas); + } +} diff --git a/src/main/java/edu/ntnu/idatt2003/mappevurderingprog2/controllers/GameController.java b/src/main/java/edu/ntnu/idatt2003/mappevurderingprog2/controllers/GameController.java index bc743e77810a43774cfd6e21eb330d8d8a3a0160..e9a48aa96884aa5cc6f814286b61665bb0a372c9 100644 --- a/src/main/java/edu/ntnu/idatt2003/mappevurderingprog2/controllers/GameController.java +++ b/src/main/java/edu/ntnu/idatt2003/mappevurderingprog2/controllers/GameController.java @@ -25,8 +25,6 @@ import javafx.scene.paint.Color; */ public class GameController { - private int greenThreshold, blueThreshold; - /** * Creates a Sierpinski triangle ChaosGameDescription * and sets it as the current ChaosGameDescription. @@ -270,57 +268,5 @@ public class GameController { description.setMaxCoords(initialMax); ChaosGame.getInstance().setDescription(description); } - - public void calculateQuantiles() { - List<Integer> hitCounts = new ArrayList<>(); - for (int[] row : ChaosGame.getInstance().getCanvas().getCanvasArray()) { - for (int hit : row) { - if (hit > 0) { - hitCounts.add(hit); - } - } - } - - if (hitCounts.isEmpty()) { - return; - } - - Collections.sort(hitCounts); - int n = hitCounts.size(); - greenThreshold = hitCounts.get((int) (n * 0.33)); - blueThreshold = hitCounts.get((int) (n * 0.66)); - } - - private Color getColorForHits(int hits) { - if (hits == 0) { - return Color.WHITE; - } else if (hits <= greenThreshold) { - return Color.GREEN; - } else if (hits <= blueThreshold) { - return Color.BLUE; - } else { - return Color.RED; - } - } - - public Canvas updateCanvasDisplay(Canvas mainCanvas) { - GraphicsContext gc = mainCanvas.getGraphicsContext2D(); - int[][] canvasArray = ChaosGame.getInstance().getCanvas().getCanvasArray(); - double canvasWidth = mainCanvas.getWidth() - 20; - double canvasHeight = mainCanvas.getHeight() - 20; - double pixelWidth = canvasWidth / canvasArray[0].length; - double pixelHeight = canvasHeight / canvasArray.length; - - gc.clearRect(0, 0, mainCanvas.getWidth(), mainCanvas.getHeight()); - for (int i = 0; i < canvasArray.length; i++) { - for (int j = 0; j < canvasArray[i].length; j++) { - double x = j * pixelWidth + 3; - double y = i * pixelHeight + 3; - gc.setFill(getColorForHits(canvasArray[i][j])); - gc.fillRect(x, y, pixelWidth, pixelHeight); - } - } - return mainCanvas; - } } diff --git a/src/main/java/edu/ntnu/idatt2003/mappevurderingprog2/views/View.java b/src/main/java/edu/ntnu/idatt2003/mappevurderingprog2/views/View.java index c54fb2806afc8956ecad9a4b05c9b3ec26671e0f..000e154c8b18546ccc3279bf0abea2ce915151dc 100644 --- a/src/main/java/edu/ntnu/idatt2003/mappevurderingprog2/views/View.java +++ b/src/main/java/edu/ntnu/idatt2003/mappevurderingprog2/views/View.java @@ -1,5 +1,6 @@ package edu.ntnu.idatt2003.mappevurderingprog2.views; +import edu.ntnu.idatt2003.mappevurderingprog2.controllers.CanvasController; import edu.ntnu.idatt2003.mappevurderingprog2.controllers.GameController; import edu.ntnu.idatt2003.mappevurderingprog2.models.chaos.ChaosGameObserver; import edu.ntnu.idatt2003.mappevurderingprog2.utils.Colorpalette; @@ -31,6 +32,9 @@ public class View extends BorderPane implements ChaosGameObserver { // Private GameController object. private GameController gameController; + // Private CanvasController object. + private CanvasController canvasController; + // Private Menu object. private Menu menu; @@ -41,9 +45,11 @@ public class View extends BorderPane implements ChaosGameObserver { * Constructs a new View object. * * @param gameController The GameController object associated with the View object. + * @param canvasController The CanvasController object associated with the View object. */ - public View(GameController gameController) { + public View(GameController gameController, CanvasController canvasController) { this.gameController = gameController; + this.canvasController = canvasController; this.mainCanvas = new Canvas(600, 400); } @@ -66,7 +72,7 @@ public class View extends BorderPane implements ChaosGameObserver { this.setBackground(new Background( new BackgroundFill(Colorpalette.Primary, CornerRadii.EMPTY, Insets.EMPTY))); this.setCenter(mainCanvas); - this.menu = new Menu(this, gameController); + this.menu = new Menu(this, gameController, canvasController); menu.setPrefWidth(Size.getScreenWidth() * 0.15); menu.setMaxWidth(Size.getScreenWidth() * 0.15); initializeExtraUserOptions(); @@ -96,28 +102,8 @@ public class View extends BorderPane implements ChaosGameObserver { @Override public void onChaosGameUpdated() { Platform.runLater(() -> { - gameController.calculateQuantiles(); - mainCanvas = gameController.updateCanvasDisplay(mainCanvas); + canvasController.calculateQuantiles(); + mainCanvas = canvasController.updateCanvasDisplay(mainCanvas); }); } - - /** - * Sets the width of the canvas. - * - * @param width The new width of the canvas. - */ - public void setCanvasWidth(double width) { - mainCanvas.setWidth(width); - mainCanvas = gameController.updateCanvasDisplay(mainCanvas); - } - - /** - * Sets the height of the canvas. - * - * @param height The new height of the canvas. - */ - public void setCanvasHeight(double height) { - mainCanvas.setHeight(height); - mainCanvas = gameController.updateCanvasDisplay(mainCanvas); - } } diff --git a/src/main/java/edu/ntnu/idatt2003/mappevurderingprog2/views/components/AffineDialog.java b/src/main/java/edu/ntnu/idatt2003/mappevurderingprog2/views/components/AffineDialog.java index fb3aaa4166efa97e7788c3966ed4b25ba022daf8..2dcfea46f992cb47cd960452628feeb130dcbbfe 100644 --- a/src/main/java/edu/ntnu/idatt2003/mappevurderingprog2/views/components/AffineDialog.java +++ b/src/main/java/edu/ntnu/idatt2003/mappevurderingprog2/views/components/AffineDialog.java @@ -8,6 +8,7 @@ import edu.ntnu.idatt2003.mappevurderingprog2.models.Vector2D; import java.util.ArrayList; import java.util.List; import java.util.concurrent.atomic.AtomicInteger; +import javafx.application.Platform; import javafx.geometry.Insets; import javafx.geometry.Pos; import javafx.scene.Node; @@ -57,7 +58,7 @@ public class AffineDialog { */ private void setupDialog() { dialog = new Dialog<>(); - dialog.setTitle("Edit Affine Transformation"); + dialog.setTitle(isEditMode ? "Edit Affine Set" : "Create Affine Set"); VBox dialogVbox = new VBox(10); dialogVbox.setPadding(new Insets(10)); @@ -190,10 +191,12 @@ public class AffineDialog { gameController.setChaosCanvas(); gameController.runTransformation(); dialog.close(); - if (gameController.getOutOfBoundsCount() > 0) { - UserFeedback.showErrorPopup("Error", gameController.getOutOfBoundsCount() - + " points were out of bounds. Try adjusting the max and min coordinates."); - } + Platform.runLater(() -> { + if (gameController.getOutOfBoundsCount() > 0) { + UserFeedback.showErrorPopup("Error", + gameController.getOutOfBoundsCount() + " pixels are out of bounds."); + } + }); } /** @@ -227,7 +230,6 @@ public class AffineDialog { "Minimum coordinates must be less than maximum coordinates."); } - // Validate matrix and vector entries for (Node[] fields : transformationFields) { TextField matrixField = (TextField) fields[0]; TextField vectorField = (TextField) fields[1]; diff --git a/src/main/java/edu/ntnu/idatt2003/mappevurderingprog2/views/components/JuliaDialog.java b/src/main/java/edu/ntnu/idatt2003/mappevurderingprog2/views/components/JuliaDialog.java index f9960981ceee7498c4c1d6a8c89158df672a51bc..69c53a0c86647c5cd79fea44e8315794d8aa3286 100644 --- a/src/main/java/edu/ntnu/idatt2003/mappevurderingprog2/views/components/JuliaDialog.java +++ b/src/main/java/edu/ntnu/idatt2003/mappevurderingprog2/views/components/JuliaDialog.java @@ -3,6 +3,7 @@ package edu.ntnu.idatt2003.mappevurderingprog2.views.components; import edu.ntnu.idatt2003.mappevurderingprog2.controllers.GameController; import edu.ntnu.idatt2003.mappevurderingprog2.models.Complex; import edu.ntnu.idatt2003.mappevurderingprog2.models.Vector2D; +import javafx.application.Platform; import javafx.geometry.Insets; import javafx.scene.control.Button; import javafx.scene.control.ButtonType; @@ -128,10 +129,12 @@ public class JuliaDialog { gameController.setChaosCanvas(); gameController.runTransformation(); dialog.close(); - if (gameController.getOutOfBoundsCount() > 0) { - UserFeedback.showErrorPopup("Error", gameController.getOutOfBoundsCount() - + " points were out of bounds. Try adjusting the max and min coordinates."); - } + Platform.runLater(() -> { + if (gameController.getOutOfBoundsCount() > 0) { + UserFeedback.showErrorPopup("Error", + gameController.getOutOfBoundsCount() + " pixels are out of bounds."); + } + }); } /** diff --git a/src/main/java/edu/ntnu/idatt2003/mappevurderingprog2/views/components/Menu.java b/src/main/java/edu/ntnu/idatt2003/mappevurderingprog2/views/components/Menu.java index bcf7e3de1d8d485505d4605c0c00caea929ff5e3..bcb379ca7185159a5bb79ed13c49d1b72f6a972a 100644 --- a/src/main/java/edu/ntnu/idatt2003/mappevurderingprog2/views/components/Menu.java +++ b/src/main/java/edu/ntnu/idatt2003/mappevurderingprog2/views/components/Menu.java @@ -1,5 +1,6 @@ package edu.ntnu.idatt2003.mappevurderingprog2.views.components; +import edu.ntnu.idatt2003.mappevurderingprog2.controllers.CanvasController; import edu.ntnu.idatt2003.mappevurderingprog2.controllers.GameController; import edu.ntnu.idatt2003.mappevurderingprog2.views.View; import javafx.application.Platform; @@ -37,12 +38,13 @@ public class Menu extends VBox { * * @param view the view * @param gameController the game controller + * @param canvasController the canvas controller */ - public Menu(View view, GameController gameController) { + public Menu(View view, GameController gameController, CanvasController canvasController) { existingFractalsMenu = new ExistingFractalsMenu(view, gameController); createFractalMenu = new CreateFractalMenu(view, gameController); editFractalMenu = new CurrentFractalMenu(view, gameController); - scaleCanvasSize = new ScaleCanvasSize(view, gameController); + scaleCanvasSize = new ScaleCanvasSize(view, gameController, canvasController); quitButton = new Button("Quit application"); initializeMenu(); } diff --git a/src/main/java/edu/ntnu/idatt2003/mappevurderingprog2/views/components/ScaleCanvasSize.java b/src/main/java/edu/ntnu/idatt2003/mappevurderingprog2/views/components/ScaleCanvasSize.java index 761fdfad88b998dc4c84a7b2090f0b104cd89fa3..53e6c4480b019bd5a5095b783b11928c9024d086 100644 --- a/src/main/java/edu/ntnu/idatt2003/mappevurderingprog2/views/components/ScaleCanvasSize.java +++ b/src/main/java/edu/ntnu/idatt2003/mappevurderingprog2/views/components/ScaleCanvasSize.java @@ -1,7 +1,9 @@ package edu.ntnu.idatt2003.mappevurderingprog2.views.components; +import edu.ntnu.idatt2003.mappevurderingprog2.controllers.CanvasController; import edu.ntnu.idatt2003.mappevurderingprog2.controllers.GameController; import edu.ntnu.idatt2003.mappevurderingprog2.views.View; +import java.awt.Canvas; import javafx.geometry.Pos; import javafx.scene.control.Button; import javafx.scene.control.Label; @@ -29,14 +31,18 @@ public class ScaleCanvasSize extends VBox { // Private GameController object. private GameController gameController; + // Private CanvasController object. + private CanvasController canvasController; + /** * Constructs a new ScaleCanvasSize component. * * @param view The View object associated with the canvas. * @param gameController The GameController object associated with the canvas. */ - public ScaleCanvasSize(View view, GameController gameController) { + public ScaleCanvasSize(View view, GameController gameController, CanvasController canvasController) { this.gameController = gameController; + this.canvasController = canvasController; Label scaleLabel = new Label("Scale canvas size"); scaleLabel.setStyle("-fx-font-size: 16px; -fx-font-weight: bold;"); @@ -52,7 +58,7 @@ public class ScaleCanvasSize extends VBox { if (!gameController.isChaosGameEmpty()) { double currentHeight = view.getMainCanvas().getHeight(); if (currentHeight + 10 <= MAX_HEIGHT) { - view.setCanvasHeight(currentHeight + 10); + canvasController.setCanvasHeight(view.getMainCanvas(), currentHeight + 10); } } else { UserFeedback.showErrorPopup("Error", "There is no fractal to increase the height of"); @@ -63,7 +69,7 @@ public class ScaleCanvasSize extends VBox { if (!gameController.isChaosGameEmpty()) { double currentHeight = view.getMainCanvas().getHeight(); if (currentHeight - 10 >= MIN_HEIGHT) { - view.setCanvasHeight(currentHeight - 10); + canvasController.setCanvasHeight(view.getMainCanvas(), currentHeight - 10); } } else { UserFeedback.showErrorPopup("Error", "There is no fractal to decrease the height of"); @@ -82,7 +88,7 @@ public class ScaleCanvasSize extends VBox { if (!gameController.isChaosGameEmpty()) { double currentWidth = view.getMainCanvas().getWidth(); if (currentWidth + 10 <= MAX_WIDTH) { - view.setCanvasWidth(currentWidth + 10); + canvasController.setCanvasWidth(view.getMainCanvas(), currentWidth + 10); } } else { UserFeedback.showErrorPopup("Error", "There is no fractal to increase the width of"); @@ -93,7 +99,7 @@ public class ScaleCanvasSize extends VBox { if (!gameController.isChaosGameEmpty()) { double currentWidth = view.getMainCanvas().getWidth(); if (currentWidth - 10 >= MIN_WIDTH) { - view.setCanvasWidth(currentWidth - 10); + canvasController.setCanvasWidth(view.getMainCanvas(), currentWidth - 10); } } else { UserFeedback.showErrorPopup("Error", "There is no fractal to decrease the width of"); diff --git a/src/test/java/edu/ntnu/idatt2003/mappevurderingprog2/ChaosGameNegativeTest.java b/src/test/java/edu/ntnu/idatt2003/mappevurderingprog2/ChaosGameNegativeTest.java index dbb87ccccb8a9c719fd7ba3744525a1eb37ce717..1c6a2499f9b666da10f43cc316fb95bf7d131a68 100644 --- a/src/test/java/edu/ntnu/idatt2003/mappevurderingprog2/ChaosGameNegativeTest.java +++ b/src/test/java/edu/ntnu/idatt2003/mappevurderingprog2/ChaosGameNegativeTest.java @@ -2,6 +2,7 @@ package edu.ntnu.idatt2003.mappevurderingprog2; import static org.junit.jupiter.api.Assertions.assertThrows; +import edu.ntnu.idatt2003.mappevurderingprog2.controllers.CanvasController; import edu.ntnu.idatt2003.mappevurderingprog2.controllers.GameController; import edu.ntnu.idatt2003.mappevurderingprog2.models.AffineTransform2D; import edu.ntnu.idatt2003.mappevurderingprog2.models.Matrix2x2; @@ -148,7 +149,8 @@ public class ChaosGameNegativeTest { @Test public void getObserversNegativeTest() { GameController gameController = new GameController(); - View view = new View(gameController); + CanvasController canvasController = new CanvasController(); + View view = new View(gameController, canvasController); ChaosGame.getInstance().addObserver(view); System.out.println(ChaosGame.getInstance().getObservers().size() + " observers"); assert ChaosGame.getInstance().getObservers().size() != 0; diff --git a/src/test/java/edu/ntnu/idatt2003/mappevurderingprog2/ChaosGamePositiveTest.java b/src/test/java/edu/ntnu/idatt2003/mappevurderingprog2/ChaosGamePositiveTest.java index 10c963ab27ca2a3417fcbc0e1793226d9f35b908..08d62807c2ed1a76e6643e4aaf4f2f1d555c34a2 100644 --- a/src/test/java/edu/ntnu/idatt2003/mappevurderingprog2/ChaosGamePositiveTest.java +++ b/src/test/java/edu/ntnu/idatt2003/mappevurderingprog2/ChaosGamePositiveTest.java @@ -3,6 +3,7 @@ package edu.ntnu.idatt2003.mappevurderingprog2; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotNull; +import edu.ntnu.idatt2003.mappevurderingprog2.controllers.CanvasController; import edu.ntnu.idatt2003.mappevurderingprog2.controllers.GameController; import edu.ntnu.idatt2003.mappevurderingprog2.models.AffineTransform2D; import edu.ntnu.idatt2003.mappevurderingprog2.models.Matrix2x2; @@ -12,6 +13,7 @@ import edu.ntnu.idatt2003.mappevurderingprog2.models.chaos.ChaosGame; import edu.ntnu.idatt2003.mappevurderingprog2.models.chaos.ChaosGameDescription; import edu.ntnu.idatt2003.mappevurderingprog2.views.View; +import java.awt.Canvas; import java.util.ArrayList; import java.util.List; @@ -94,7 +96,8 @@ public class ChaosGamePositiveTest { @Test public void addObserverPositiveTest() { GameController gameController = new GameController(); - View view = new View(gameController); + CanvasController canvasController = new CanvasController(); + View view = new View(gameController, canvasController); ChaosGame.getInstance().addObserver(view); assertEquals(1, ChaosGame.getInstance().getObservers().size()); } @@ -106,7 +109,8 @@ public class ChaosGamePositiveTest { @Test public void removeObserverPositiveTest() { GameController gameController = new GameController(); - View view = new View(gameController); + CanvasController canvasController = new CanvasController(); + View view = new View(gameController, canvasController); ChaosGame.getInstance().addObserver(view); ChaosGame.getInstance().removeObserver(view); assertEquals(0, ChaosGame.getInstance().getObservers().size()); @@ -170,7 +174,8 @@ public class ChaosGamePositiveTest { @Test public void getObserversPositiveTest() { GameController gameController = new GameController(); - View view = new View(gameController); + CanvasController canvasController = new CanvasController(); + View view = new View(gameController, canvasController); ChaosGame.getInstance().addObserver(view); assertEquals(1, ChaosGame.getInstance().getObservers().size()); }