diff --git a/src/main/java/edu/ntnu/idatt2003/mappevurderingprog2/controllers/Controller.java b/src/main/java/edu/ntnu/idatt2003/mappevurderingprog2/controllers/Controller.java deleted file mode 100644 index c1cb41d4f061599ae3d3d693584f7cb28d6eca8b..0000000000000000000000000000000000000000 --- a/src/main/java/edu/ntnu/idatt2003/mappevurderingprog2/controllers/Controller.java +++ /dev/null @@ -1,5 +0,0 @@ -package edu.ntnu.idatt2003.mappevurderingprog2.controllers; - -public class Controller{ - -} \ No newline at end of file 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 4546b3bbf762e015b243a01ccc6ac43b398d609d..8a161f5531d0e25627d95c756768d17bbc5d458f 100644 --- a/src/main/java/edu/ntnu/idatt2003/mappevurderingprog2/controllers/GameController.java +++ b/src/main/java/edu/ntnu/idatt2003/mappevurderingprog2/controllers/GameController.java @@ -12,19 +12,44 @@ import edu.ntnu.idatt2003.mappevurderingprog2.models.chaos.ChaosGameFileHandler; import java.util.ArrayList; import java.util.List; +/** + * The GameController class is a controller class that handles the logic for the ChaosGame. + * The class is responsible for creating and updating the ChaosGameDescription, + * and running the ChaosGame. + * The class also handles saving and reading ChaosGameDescriptions to and from files. + */ public class GameController { + /** + * Creates a Sierpinski triangle ChaosGameDescription + * and sets it as the current ChaosGameDescription. + */ public void createSierpinskiTriangle() { ChaosGame.getInstance().setDescription(ChaosGameDescriptionFactory.createSierpinskiTriangle()); } + /** + * Creates a Barnsley Fern ChaosGameDescription and sets it as the current ChaosGameDescription. + */ public void createBarnsleyFern() { ChaosGame.getInstance().setDescription(ChaosGameDescriptionFactory.createBarnsleyFern()); } + /** + * Creates a standard Julia transformation ChaosGameDescription + * and sets it as the current ChaosGameDescription. + */ public void createJuliaTransformation() { - ChaosGame.getInstance().setDescription(ChaosGameDescriptionFactory.createStandardJuliaTransformation()); + ChaosGame.getInstance().setDescription( + ChaosGameDescriptionFactory.createStandardJuliaTransformation()); } + + /** + * Updates the canvas coordinates of the current ChaosGameDescription. + * + * @param minCoords the minimum coordinates of the canvas + * @param maxCoords the maximum coordinates of the canvas + */ public void updateCanvasCoordinates(Vector2D minCoords, Vector2D maxCoords) { ChaosGameDescription description = ChaosGame.getInstance().getDescription(); description.setMaxCoords(maxCoords); @@ -32,59 +57,119 @@ public class GameController { ChaosGame.getInstance().setDescription(description); } + /** + * Gets the current number of steps of the ChaosGame. + * + * @return the current number of steps + */ public int getCurrentSteps() { return ChaosGame.getInstance().getSteps(); } + /** + * Gets the current minimum coordinates of the canvas. + * + * @return the current minimum coordinates + */ public Vector2D getCurrentMaxCoords() { return ChaosGame.getInstance().getDescription().getMaxCoords(); } + /** + * Gets the current maximum coordinates of the canvas. + * + * @return the current maximum coordinates + */ public Vector2D getCurrentMinCoords() { return ChaosGame.getInstance().getDescription().getMinCoords(); } + /** + * Gets the current Julia point of the ChaosGame. + * + * @return the current Julia point + */ public Complex getCurrentJuliaPoint() { List<Transform2D> transforms = ChaosGame.getInstance().getDescription().getTransforms(); JuliaTransform julia = (JuliaTransform) transforms.get(0); return julia.getPoint(); } + /** + * Gets the current affine transformations of the ChaosGame. + * + * @return the current affine transformations + */ public List<Transform2D> getAffineTransformations() { return ChaosGame.getInstance().getDescription().getTransforms(); } - public void setChaosGameDescription(ChaosGameDescription description) { - ChaosGame.getInstance().setDescription(description); - } + /** + * Sets the ChaosGame canvas. + */ public void setChaosCanvas() { ChaosGame.getInstance().setCanvas(); } + /** + * Sets the number of steps of the ChaosGame. + * + * @param steps the number of steps to set + */ public void setChaosGameSteps(int steps) { ChaosGame.getInstance().setSteps(steps); } + /** + * Runs the ChaosGame transformations. + */ public void runTransformation() { ChaosGame.getInstance().runSteps(); } + /** + * Gets the count of out-of-bounds occurrences. + * + * @return the count of out-of-bounds occurrences + */ public int getOutOfBoundsCount() { return ChaosGame.getInstance().getOutOfBoundsCount(); } + /** + * Sets the Julia transformation with specified parameters. + * + * @param point the Julia point to set + * @param minCoords the minimum coordinates of the canvas + * @param maxCoords the maximum coordinates of the canvas + */ public void setJuliaTransformation(Complex point, Vector2D minCoords, Vector2D maxCoords) { List<Transform2D> transforms = new ArrayList<>(); transforms.add(new JuliaTransform(point, -1)); transforms.add(new JuliaTransform(point, 1)); - ChaosGame.getInstance().setDescription(new ChaosGameDescription(transforms, minCoords, maxCoords)); + ChaosGame.getInstance().setDescription( + new ChaosGameDescription(transforms, minCoords, maxCoords)); } - public void setAffineTransformation(List<Transform2D> transforms, Vector2D minCoords, Vector2D maxCoords) { - ChaosGame.getInstance().setDescription(new ChaosGameDescription(transforms, minCoords, maxCoords)); + /** + * Sets the affine transformation with specified parameters. + * + * @param transforms the affine transformations to set + * @param minCoords the minimum coordinates of the canvas + * @param maxCoords the maximum coordinates of the canvas + */ + public void setAffineTransformation( + List<Transform2D> transforms, Vector2D minCoords, Vector2D maxCoords) { + ChaosGame.getInstance().setDescription( + new ChaosGameDescription(transforms, minCoords, maxCoords)); } + /** + * Checks if the ChaosGame is empty. + * + * @return true if the ChaosGame is empty, false otherwise + */ public boolean isChaosGameEmpty() { boolean empty = false; if (ChaosGame.getInstance().getDescription() == null) { @@ -93,39 +178,82 @@ public class GameController { return empty; } + /** + * Checks if the current transformation is an affine transformation. + * + * @return true if the current transformation is an affine transformation, false otherwise + */ public boolean isAffineTransformation() { List<Transform2D> transforms = ChaosGame.getInstance().getDescription().getTransforms(); - if (transforms.isEmpty()) return false; + if (transforms.isEmpty()) { + return false; + } return transforms.get(0) instanceof AffineTransform2D; } + /** + * Checks if the current transformation is a Julia transformation. + * + * @return true if the current transformation is a Julia transformation, false otherwise + */ public boolean isJuliaTransformation() { List<Transform2D> transforms = ChaosGame.getInstance().getDescription().getTransforms(); - if (transforms.isEmpty()) return false; + if (transforms.isEmpty()) { + return false; + } return transforms.get(0) instanceof JuliaTransform; } + /** + * Reads ChaosGame transformations from a file. + * + * @param name the name of the file to read from + * @throws Exception if an error occurs during reading + */ public void saveFractalToFile(String name) throws Exception { ChaosGameFileHandler.writeTransformationsToFile(ChaosGame.getInstance().getDescription(), name); } + /** + * Reads ChaosGame transformations from a file. + * + * @param name the name of the file to read from + * @throws Exception if an error occurs during reading + */ public void readFractalFromFile(String name) throws Exception { ChaosGameDescription description = ChaosGameFileHandler.readTransformationsFromFile(name); ChaosGame.getInstance().setDescription(description); } + /** + * Checks if a file with the specified name exists. + * + * @param name the name of the file to check + * @return true if the file exists, false otherwise + */ public boolean doesFileExist(String name) { return ChaosGameFileHandler.checkFileExists(name); } + /** + * Lists all transformation file names. + * + * @return a list of transformation file names + */ public List<String> listTransformationFileNames() { return ChaosGameFileHandler.listTransformationFileNames(); } + /** + * Empties the ChaosGame. + */ public void emptyChaosGame() { ChaosGame.getInstance().setDescription(null); } + /** + * Resets canvas coordinates to initial values. + */ public void resetCanvasCoordinates() { ChaosGameDescription description = ChaosGame.getInstance().getDescription(); Vector2D initialMin = description.getInitialMinCoords(); @@ -135,6 +263,5 @@ public class GameController { description.setMaxCoords(initialMax); ChaosGame.getInstance().setDescription(description); } - } diff --git a/src/main/java/edu/ntnu/idatt2003/mappevurderingprog2/enums/ButtonEnum.java b/src/main/java/edu/ntnu/idatt2003/mappevurderingprog2/enums/ButtonEnum.java deleted file mode 100644 index cfe0dbde2052e98485a99fa808d0f327427d8190..0000000000000000000000000000000000000000 --- a/src/main/java/edu/ntnu/idatt2003/mappevurderingprog2/enums/ButtonEnum.java +++ /dev/null @@ -1,15 +0,0 @@ -package edu.ntnu.idatt2003.mappevurderingprog2.enums; - -/** - * An enum representing the buttons in the application - */ -public enum ButtonEnum { - Transform, - ClearTransformation, - ZoomIn, - ZoomOut, - ResetZoom, - Submit, - Clear, - -} diff --git a/src/main/java/edu/ntnu/idatt2003/mappevurderingprog2/models/chaos/ChaosCanvas.java b/src/main/java/edu/ntnu/idatt2003/mappevurderingprog2/models/chaos/ChaosCanvas.java index 6b194df0c33620af3c6f5f88edc11347bb2e9643..d8b7bef8660c8c353ef6c7cd9ec0d63e8bbd0c6f 100644 --- a/src/main/java/edu/ntnu/idatt2003/mappevurderingprog2/models/chaos/ChaosCanvas.java +++ b/src/main/java/edu/ntnu/idatt2003/mappevurderingprog2/models/chaos/ChaosCanvas.java @@ -1,117 +1,131 @@ package edu.ntnu.idatt2003.mappevurderingprog2.models.chaos; import edu.ntnu.idatt2003.mappevurderingprog2.models.AffineTransform2D; -import edu.ntnu.idatt2003.mappevurderingprog2.models.Complex; import edu.ntnu.idatt2003.mappevurderingprog2.models.Matrix2x2; import edu.ntnu.idatt2003.mappevurderingprog2.models.Vector2D; -import javafx.scene.transform.Affine; /** * The ChaosCanvas class represent a 2D canvas with the ability to store and retrieve pixels. * The class can apply transformations to obtain pixel values from a given point. */ -public class ChaosCanvas{ - - //The canvas is represented as a 2D array of integers, where each integer represents a color. - private int [][] canvas; - - // The width of the canvas - private int width; - - // The height of the canvas - private int height; - - // The minimum coordinates of the canvas - private Vector2D minCoords; - - // The maximum coordinates of the canvas - private Vector2D maxCoords; - - // The transformation from coordinates to indices - private AffineTransform2D transformCoordsToIndices; - - /** - * Constructs a ChaosCanvas object with the given width, height, minimum coordinates, and maximum coordinates. - - * @param width the width of the canvas - * @param height the height of the canvas - * @param minCoords the minimum coordinates of the canvas - * @param maxCoords the maximum coordinates of the canvas - */ - public ChaosCanvas(int width, int height, Vector2D minCoords, Vector2D maxCoords) { - this.width = width; - this.height = height; - this.minCoords = minCoords; - this.maxCoords = maxCoords; - this.canvas = new int[width][height]; - setUpTransformation(); - } - - private void setUpTransformation() { - this.transformCoordsToIndices = new AffineTransform2D( - new Matrix2x2(0, - ((height - 1)/(minCoords.getX1() - maxCoords.getX1())), - ((width - 1)/(maxCoords.getX0() - minCoords.getX0())), - 0), - new Vector2D(((height - 1) * maxCoords.getX1())/(maxCoords.getX1() - minCoords.getX1()), - ((width - 1) * minCoords.getX0())/(minCoords.getX0() - maxCoords.getX0()))); - } - - public Vector2D getMinCoords() { - return minCoords; - } - - public Vector2D getMaxCoords() { - return maxCoords; - } - - /** - * Gets the color of the pixel at the given point. - - * @return the color of the pixel at the given point - */ - public int getPixel(Vector2D point){ - Vector2D indices = transformCoordsToIndices.transform(point); - int x = (int) indices.getX0(); - int y = (int) indices.getX1(); - return canvas[x][y]; +public class ChaosCanvas { + + //The canvas is represented as a 2D array of integers, where each integer represents a color. + private int[][] canvas; + + // The width of the canvas + private int width; + + // The height of the canvas + private int height; + + // The minimum coordinates of the canvas + private Vector2D minCoords; + + // The maximum coordinates of the canvas + private Vector2D maxCoords; + + // The transformation from coordinates to indices + private AffineTransform2D transformCoordsToIndices; + + /** + * Constructs a ChaosCanvas object with the given + * width, height, minimum coordinates, and maximum coordinates. + * + * @param width the width of the canvas + * @param height the height of the canvas + * @param minCoords the minimum coordinates of the canvas + * @param maxCoords the maximum coordinates of the canvas + */ + public ChaosCanvas(int width, int height, Vector2D minCoords, Vector2D maxCoords) { + this.width = width; + this.height = height; + this.minCoords = minCoords; + this.maxCoords = maxCoords; + this.canvas = new int[width][height]; + setUpTransformation(); + } + + /** + * Sets up the transformation from coordinates to indices. + */ + private void setUpTransformation() { + this.transformCoordsToIndices = new AffineTransform2D( + new Matrix2x2(0, + ((height - 1) / (minCoords.getX1() - maxCoords.getX1())), + ((width - 1) / (maxCoords.getX0() - minCoords.getX0())), + 0), + new Vector2D(((height - 1) * maxCoords.getX1()) / (maxCoords.getX1() - minCoords.getX1()), + ((width - 1) * minCoords.getX0()) / (minCoords.getX0() - maxCoords.getX0()))); + } + + /** + * Gets the minimum coordinates of the canvas. + * + * @return the minimum coordinates of the canvas + */ + public Vector2D getMinCoords() { + return minCoords; + } + + /** + * Gets the maximum coordinates of the canvas. + * + * @return the maximum coordinates of the canvas + */ + public Vector2D getMaxCoords() { + return maxCoords; + } + + /** + * Gets the color of the pixel at the given point. + * + * @param point the point at which to get the pixel color + * @return the color of the pixel at the given point + */ + public int getPixel(Vector2D point) { + Vector2D indices = transformCoordsToIndices.transform(point); + int x = (int) indices.getX0(); + int y = (int) indices.getX1(); + return canvas[x][y]; + } + + + /** + * Puts a pixel at the given point. + * + * @param point the point at which to put the pixel + * @return true if the pixel was successfully put, false otherwise + */ + public boolean putPixel(Vector2D point) { + Vector2D indices = transformCoordsToIndices.transform(point); + int x = (int) indices.getX0(); + int y = (int) indices.getX1(); + if (x >= 0 && x < width && y >= 0 && y < height) { + canvas[x][y] += 1; + return true; + } else { + return false; } - - - /** - * Puts a pixel at the given point. - - * @param point the point at which to put the pixel - */ - - public boolean putPixel(Vector2D point) { - Vector2D indices = transformCoordsToIndices.transform(point); - int x = (int) indices.getX0(); - int y = (int) indices.getX1(); - if (x >= 0 && x < width && y >= 0 && y < height) { - canvas[x][y] += 1; - return true; - } else { - return false; - } - } - /** - * Gets the canvas array. - - * @return the canvas array - */ - public int[][]getCanvasArray(){ - return canvas; - } - - /** - * Clears the canvas. - */ - public void clear() { - for (int i = 0; i < canvas.length; i++) { - for (int j = 0; j < canvas[i].length; j++) { - canvas[i][j] = 0; - } + } + + /** + * Gets the canvas array. + * + * @return the canvas array + */ + public int[][] getCanvasArray() { + return canvas; + } + + /** + * Clears the canvas. + */ + public void clear() { + for (int i = 0; i < canvas.length; i++) { + for (int j = 0; j < canvas[i].length; j++) { + canvas[i][j] = 0; } } + } } \ No newline at end of file diff --git a/src/main/java/edu/ntnu/idatt2003/mappevurderingprog2/models/chaos/ChaosGame.java b/src/main/java/edu/ntnu/idatt2003/mappevurderingprog2/models/chaos/ChaosGame.java index 4f18d87824f1b5f806ecd24ba8aba99228e1b018..a6ff51a720181b27016deffc4e4d5148f91c4804 100644 --- a/src/main/java/edu/ntnu/idatt2003/mappevurderingprog2/models/chaos/ChaosGame.java +++ b/src/main/java/edu/ntnu/idatt2003/mappevurderingprog2/models/chaos/ChaosGame.java @@ -3,35 +3,64 @@ package edu.ntnu.idatt2003.mappevurderingprog2.models.chaos; import edu.ntnu.idatt2003.mappevurderingprog2.models.Complex; import edu.ntnu.idatt2003.mappevurderingprog2.models.Transform2D; import edu.ntnu.idatt2003.mappevurderingprog2.models.Vector2D; +import javafx.util.Pair; import java.util.ArrayList; import java.util.List; import java.util.Random; -import javafx.util.Pair; /** * The ChaosGame class represents a chaos game. - * The class simulate a chaos game with a given description on a canvas. + * The class simulates a chaos game with a given description on a canvas. */ public class ChaosGame { + /** The instance of the ChaosGame (singleton pattern). */ private static ChaosGame instance; + + /** The canvas of the ChaosGame. */ private ChaosCanvas canvas; + + /** The description of the ChaosGame. */ private ChaosGameDescription description; + + /** The number of steps of the ChaosGame. */ private int steps; + + /** The current point of the ChaosGame. */ private Vector2D currentPoint; + + /** The random object of the ChaosGame. */ private Random random; + + /** The number of points that are out of bounds. */ private int outOfBoundsCount = 0; + + /** The list of observers of the ChaosGame. */ private List<ChaosGameObserver> observers; + + /** The height of the canvas. */ private final int height = 200; + + /** The width of the canvas. */ private final int width = 200; + /** + * Constructs a new ChaosGame instance. + * Initializes the current point to (0, 0), random object, and observers list. + */ private ChaosGame() { this.currentPoint = new Complex(0, 0); this.random = new Random(); this.observers = new ArrayList<>(); } + /** + * Returns the singleton instance of ChaosGame. + * If the instance does not exist, it creates a new one. + * + * @return the singleton instance of ChaosGame. + */ public static synchronized ChaosGame getInstance() { if (instance == null) { instance = new ChaosGame(); @@ -39,11 +68,21 @@ public class ChaosGame { return instance; } + /** + * Sets the description of the ChaosGame and resets the game. + * + * @param description the description of the ChaosGame. + */ public void setDescription(ChaosGameDescription description) { resetGame(); this.description = description; } + /** + * Sets up the canvas for the ChaosGame using the description's min and max coordinates. + * + * @throws IllegalStateException if the description is not set. + */ public void setCanvas() { if (description == null) { throw new IllegalStateException("ChaosGame description is not set."); @@ -51,6 +90,12 @@ public class ChaosGame { this.canvas = new ChaosCanvas(width, height, description.getMinCoords(), description.getMaxCoords()); } + /** + * Sets the number of steps for the ChaosGame. + * + * @param steps the number of steps, must be between 0 and 1000000. + * @throws IllegalArgumentException if the number of steps is out of bounds. + */ public void setSteps(int steps) { if (steps < 0 || steps > 1000000) { throw new IllegalArgumentException("Number of steps must be between 0 and 1000000."); @@ -58,6 +103,9 @@ public class ChaosGame { this.steps = steps; } + /** + * Resets the ChaosGame by clearing the canvas and resetting the current point. + */ private void resetGame() { if (this.canvas != null) { this.canvas.clear(); @@ -65,6 +113,12 @@ public class ChaosGame { this.currentPoint = new Complex(0, 0); } + /** + * Adds an observer to the ChaosGame. + * + * @param observer the observer to be added. + * @throws IllegalArgumentException if the observer is null. + */ public void addObserver(ChaosGameObserver observer) { if (observer == null) { throw new IllegalArgumentException("Observer cannot be null."); @@ -72,6 +126,12 @@ public class ChaosGame { observers.add(observer); } + /** + * Removes an observer from the ChaosGame. + * + * @param observer the observer to be removed. + * @throws IllegalArgumentException if the observer is null. + */ public void removeObserver(ChaosGameObserver observer) { if (observer == null) { throw new IllegalArgumentException("Observer cannot be null."); @@ -79,29 +139,65 @@ public class ChaosGame { observers.remove(observer); } + /** + * Notifies all observers that the ChaosGame has been updated. + */ protected void notifyChaosGameUpdated() { for (ChaosGameObserver observer : observers) { observer.onChaosGameUpdated(canvas); } } + /** + * Returns the canvas of the ChaosGame. + * + * @return the canvas of the ChaosGame. + */ public ChaosCanvas getCanvas() { return canvas; } + /** + * Returns the description of the ChaosGame. + * + * @return the description of the ChaosGame. + */ public ChaosGameDescription getDescription() { return description; } + + /** + * Returns the number of steps of the ChaosGame. + * + * @return the number of steps. + */ public int getSteps() { return steps; } + + /** + * Returns the number of points that are out of bounds. + * + * @return the number of points that are out of bounds. + */ public int getOutOfBoundsCount() { return outOfBoundsCount; } + + /** + * Returns the list of observers of the ChaosGame. + * + * @return the list of observers. + */ public List<ChaosGameObserver> getObservers() { return observers; } + /** + * Runs the chaos game for the set number of steps. + * Updates the current point based on weighted or non-weighted transformations. + * Notifies observers after completing the steps. + */ public void runSteps() { ChaosGameDescription description = ChaosGame.getInstance().getDescription(); outOfBoundsCount = 0;