Skip to content
Snippets Groups Projects
Commit 7057ce63 authored by Vetle Solheim Hodne's avatar Vetle Solheim Hodne
Browse files

Merge branch 'unit-test' into 'main'

Created test classes for Factory and FileReader. Created equals methods

See merge request !20
parents 23ced3f5 2ecd7c1c
No related branches found
No related tags found
1 merge request!20Created test classes for Factory and FileReader. Created equals methods
Pipeline #288208 passed
Showing
with 408 additions and 132 deletions
......@@ -2,7 +2,7 @@
<project version="4">
<component name="CheckStyle-IDEA" serialisationVersion="2">
<checkstyleVersion>10.13.0</checkstyleVersion>
<scanScope>JavaOnly</scanScope>
<scanScope>JavaOnlyWithTests</scanScope>
<option name="thirdPartyClasspath" />
<option name="activeLocationIds" />
<option name="locations">
......
<component name="InspectionProjectProfileManager">
<profile version="1.0">
<option name="myName" value="Project Default" />
<inspection_tool class="AutoCloseableResource" enabled="true" level="WARNING" enabled_by_default="true">
<option name="METHOD_MATCHER_CONFIG" value="java.util.Formatter,format,java.io.Writer,append,com.google.common.base.Preconditions,checkNotNull,org.hibernate.Session,close,java.io.PrintWriter,printf,java.io.PrintStream,printf,org.mockito.MockitoAnnotations,openMocks" />
</inspection_tool>
</profile>
</component>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<<<<<<< HEAD
<mapping directory="$PROJECT_DIR$" vcs="Git" />
=======
<mapping directory="" vcs="Git" />
>>>>>>> origin/main
</component>
</project>
\ No newline at end of file
......@@ -42,7 +42,26 @@
<artifactId>javafx-media</artifactId>
<version>21.0.2</version>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<version>3.12.4</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-inline</artifactId>
<version>3.12.4</version>
<scope>test</scope>
</dependency>
<!-- Mockito JUnit Jupiter Dependency -->
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-junit-jupiter</artifactId>
<version>3.11.2</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
......
......@@ -24,13 +24,13 @@ public class MainApp extends Application {
new PageController(mainPane, chaosGameController, exploreGameController);
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);
primaryStage.setMinWidth(1000);
primaryStage.setMinHeight(650);
primaryStage.setScene(scene);
primaryStage.setTitle("Chaos Game Canvas");
......
......@@ -17,12 +17,10 @@ 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.Vector2D;
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;
......@@ -105,26 +103,29 @@ public class ChaosGameController implements Observer, Subject, GameController {
String input = stepsField.getText();
try {
int steps = Integer.parseInt(input);
if (steps < 1 || steps > 10000000) {
throw new NumberFormatException();
}
if (chaosGame.getDescription().getTransforms().getFirst() instanceof JuliaTransform && steps > 250000) {
AlertUtility.showErrorDialog("Invalid input", "Please enter a lower amount of steps for Julia transformations.");
return;
chaosGame.setSteps(steps);
if (chaosGame.getDescription().getTransforms().getFirst()
instanceof JuliaTransform && steps > 250000) {
throw new IllegalArgumentException(
"Please enter a lower amount of steps for Julia transformations.");
}
if (chaosGame.getTotalSteps() > Math.pow(10, 8)) {
AlertUtility.showErrorDialog("Invalid input", "The total number of steps is too high. Please reset the game.");
return;
throw new IllegalArgumentException(
"The total amount of steps is too high. Choose a lower amount.");
}
chaosGame.setSteps(steps);
chaosGame.addTotalSteps(steps);
chaosGame.runSteps();
stepsField.getStyleClass().remove("text-field-invalid");
} catch (NumberFormatException ex) {
} catch (NumberFormatException e) {
stepsField.clear();
stepsField.getStyleClass().add("text-field-invalid");
AlertUtility.showErrorDialog("Invalid input", "Please enter a valid number.");
} catch (IllegalArgumentException ex) {
stepsField.clear();
stepsField.getStyleClass().add("text-field-invalid");
AlertUtility.showErrorDialog(
"Invalid input", "Please enter a number between 1 - 10 000 000.");
"Invalid input", ex.getMessage());
}
}
......@@ -146,46 +147,22 @@ public class ChaosGameController implements Observer, Subject, GameController {
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.");
}
updateChaosGame(new ChaosGameDescription(min, max,
chaosGame.getDescription().getTransforms()));
} catch (NumberFormatException e) {
AlertUtility.showErrorDialog("Invalid input",
"Please enter a valid number.");
} catch (IndexOutOfBoundsException e) {
AlertUtility.showErrorDialog("Invalid input",
"Please enter all coordinates.");
} catch (IllegalArgumentException e) {
AlertUtility.showErrorDialog("Invalid input",
e.getMessage());
}
}
}
/**
* 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());
double x = vector.getX();
double y = vector.getY();
if (x < -50 || x > 50 || y < -50 || y > 50) {
return false;
}
} catch (NumberFormatException e) {
return false;
}
return true;
}
/**
* Method for opening a file with a chaos game description.
*
......@@ -212,10 +189,12 @@ public class ChaosGameController implements Observer, Subject, GameController {
}
/**
* Method for creating a new fractal.
* Method for user creation of fractal.
* {@link org.example.chaosgame.view.components.CreateFractalDialog} returns either a
* {@link java.util.List}<{@link java.util.List}<{@link java.lang.String}>>
* or a {@link javafx.util.Pair}<{@link java.lang.String}, {@link java.lang.String}>.
*
* <p>Opens a dialog for the user to create a new fractal.
*
*/
public void createOwnFractal() {
CreateFractalDialog dialog = new CreateFractalDialog();
......@@ -226,7 +205,7 @@ public class ChaosGameController implements Observer, Subject, GameController {
List<Transform2D> transforms = new ArrayList<>();
if (fractalData instanceof List) {
List<List<String>> userInput = (List<List<String>>) fractalData;
for(List<String> input : userInput) {
for (List<String> input : userInput) {
try {
double a = Double.parseDouble(input.get(0));
double b = Double.parseDouble(input.get(1));
......@@ -235,8 +214,8 @@ public class ChaosGameController implements Observer, Subject, GameController {
double x = Double.parseDouble(input.get(4));
double y = Double.parseDouble(input.get(5));
if (a < -5 || a > 5 || b < -5 || b > 5 || c < -5 || c > 5 ||
d < -5 || d > 5 || x < -5 || x > 5 || y < -5 || y > 5) {
if (a < -5 || a > 5 || b < -5 || b > 5 || c < -5 || c > 5
|| d < -5 || d > 5 || x < -5 || x > 5 || y < -5 || y > 5) {
throw new NumberFormatException();
} else {
transforms.add(new AffineTransform2D(new Matrix2x2(a, b, c, d), new Vector2D(x, y)));
......@@ -249,7 +228,6 @@ public class ChaosGameController implements Observer, Subject, GameController {
AlertUtility.showErrorDialog("Invalid input", "Please enter a valid number.");
}
}
// List<Transform2D> transforms = new ArrayList<>(transformations);
} else if (fractalData instanceof Pair) {
Pair<String, String> userInput = (Pair<String, String>) fractalData;
try { // Check if the input is a valid number
......
package org.example.chaosgame.model.chaos;
package org.example.chaosgame.controller;
import java.util.List;
import org.example.chaosgame.model.chaos.ChaosGameDescription;
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;
......@@ -13,12 +15,16 @@ import org.example.chaosgame.model.transformations.JuliaTransform;
public class ChaosGameDescriptionFactory {
/**
* Returns a ChaosGameDescription object based on the description and complex number.
* Returns a ChaosGameDescription object based on the ChaosGameType-enum.
*
* @param type The description of the chaos game
* @return A ChaosGameDescription object
* @throws IllegalArgumentException if the ChaosGameType is null
*/
public static ChaosGameDescription get(ChaosGameType type) {
public static ChaosGameDescription get(ChaosGameType type) throws IllegalArgumentException {
if (type == null) {
throw new IllegalArgumentException("ChaosGameType cannot be null");
}
return switch (type) {
case JULIA -> createJulia();
case BARNSLEY -> createBarnsley();
......
package org.example.chaosgame.model.chaos;
package org.example.chaosgame.controller;
import java.io.BufferedReader;
import java.io.BufferedWriter;
......@@ -7,6 +7,7 @@ import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import org.example.chaosgame.model.chaos.ChaosGameDescription;
import org.example.chaosgame.model.linalg.Complex;
import org.example.chaosgame.model.linalg.Matrix2x2;
import org.example.chaosgame.model.linalg.Vector2D;
......@@ -42,8 +43,6 @@ public class ChaosGameFileHandler {
Vector2D maxCoords;
try (BufferedReader reader = new BufferedReader(new FileReader(path))) {
String typeOfTransformation = skipComments(reader.readLine());
System.out.println("Parsing type of transformation: " + typeOfTransformation);
minCoords = parseVector(reader.readLine().trim());
maxCoords = parseVector(reader.readLine().trim());
......@@ -132,7 +131,7 @@ public class ChaosGameFileHandler {
* @return the transformation
* @throws IllegalArgumentException if the type of transformation is unknown
*/
private Transform2D selectTransformation(String typeOfTransformation, String line)
public Transform2D selectTransformation(String typeOfTransformation, String line)
throws IllegalArgumentException {
return switch (typeOfTransformation) {
case "Affine2D" -> parseAffine(line);
......@@ -148,7 +147,7 @@ public class ChaosGameFileHandler {
* @param line a line of text
* @return the first part of the line
*/
private String skipComments(String line) {
public String skipComments(String line) {
String[] parts = line.split("#");
return parts[0].trim();
}
......@@ -159,9 +158,8 @@ public class ChaosGameFileHandler {
* @param line a line of text
* @return the vector
*/
private Vector2D parseVector(String line) {
public Vector2D parseVector(String line) {
String numbers = skipComments(line);
System.out.println("Parsing vector: " + numbers);
String[] vectorParts = numbers.split(",");
double x = Double.parseDouble(vectorParts[0].trim());
double y = Double.parseDouble(vectorParts[1].trim());
......@@ -174,9 +172,8 @@ public class ChaosGameFileHandler {
* @param line a line of text
* @return the transformation
*/
private Transform2D parseAffine(String line) {
public Transform2D parseAffine(String line) {
String numbers = skipComments(line);
System.out.println("Parsing transform: " + numbers);
String[] transformParts = numbers.split(",");
double a = Double.parseDouble(transformParts[0].trim());
double b = Double.parseDouble(transformParts[1].trim());
......@@ -193,9 +190,8 @@ public class ChaosGameFileHandler {
* @param line a line of text
* @return the transformation
*/
private Transform2D parseJulia(String line) {
public Transform2D parseJulia(String line) {
String numbers = skipComments(line);
System.out.println("Parsing transform: " + numbers);
String[] parts = numbers.split(",");
double r = Double.parseDouble(parts[0].trim());
double i = Double.parseDouble(parts[1].trim());
......
......@@ -40,6 +40,9 @@ public class ExploreGameController implements Observer, Subject, GameController
private static final int WIDTH = 1200;
private static final int HEIGHT = 800;
private Vector2D minCoords = new Vector2D(-1.6, -1);
private Vector2D maxCoords = new Vector2D(1.6, 1);
/**
* Constructor for ExploreGameController.
* Initializes the ExploreGame and ExplorePage.
......@@ -47,9 +50,9 @@ public class ExploreGameController implements Observer, Subject, GameController
public ExploreGameController() {
ExploreJulia exploreJulia = new ExploreJulia(new Complex(-0.835, 0.2321));
this.trans = List.of(exploreJulia);
this.description = new ChaosGameDescription(
new Vector2D(-1.6, -1),
new Vector2D(1.6, 1), trans);
this.description = new ChaosGameDescription(
minCoords,
maxCoords, trans);
this.exploreGame = new ExploreGame(description, WIDTH, HEIGHT);
this.chaosCanvas = exploreGame.getCanvas();
this.pageObservers = new ArrayList<>();
......@@ -101,10 +104,9 @@ public class ExploreGameController implements Observer, Subject, GameController
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 newMinCoords = description.getMinCoords().subtract(adjustedDragDistance);
Vector2D newMaxCoords = description.getMaxCoords().subtract(adjustedDragDistance);
description = new ChaosGameDescription(newMinCoords, newMaxCoords, trans);
.divide(new Vector2D(canvas.getWidth(), canvas.getHeight()));
minCoords = description.getMinCoords().subtract(adjustedDragDistance);
maxCoords = description.getMaxCoords().subtract(adjustedDragDistance);
updateExplorePage();
}
......@@ -119,12 +121,11 @@ public class ExploreGameController implements Observer, Subject, GameController
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));
minCoords = canvasCenter.subtract(canvasCenter.subtract(
description.getMinCoords()).scale(scaleFactor));
maxCoords = canvasCenter.add(description.getMaxCoords()
.subtract(canvasCenter).scale(scaleFactor));
description = new ChaosGameDescription(newMinCoords, newMaxCoords, trans);
updateExplorePage();
}
......@@ -166,29 +167,32 @@ public class ExploreGameController implements Observer, Subject, GameController
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));
description = new ChaosGameDescription(newMinCoords, newMaxCoords, trans);
minCoords = canvasCenter.subtract(canvasCenter.subtract(
description.getMinCoords()).scale(scaleFactor));
maxCoords = canvasCenter.add(description.getMaxCoords()
.subtract(canvasCenter).scale(scaleFactor));
updateExplorePage();
}
private void updateExplorePage() {
exploreGame.removeObserver(this);
exploreGame = new ExploreGame(description, (int) canvas.getWidth(), (int) canvas.getHeight());
exploreGame.registerObserver(this);
this.description.setMinCoords(minCoords);
this.description.setMaxCoords(maxCoords);
this.description.setTransforms(trans);
this.exploreGame = new ExploreGame(
description, (int) canvas.getWidth(), (int) canvas.getHeight());
this.exploreGame.registerObserver(this);
this.chaosCanvas = exploreGame.getCanvas();
exploreGame.exploreFractals();
explorePage.updateCanvas(this.chaosCanvas);
explorePage.updateCanvas(exploreGame.getCanvas());
canvas.setTranslateX(0);
canvas.setTranslateY(0);
canvas.setScaleY(1);
canvas.setScaleX(1);
this.canvas.setTranslateX(0);
this.canvas.setTranslateY(0);
this.canvas.setScaleX(1);
this.canvas.setScaleY(1);
}
public void homeButtonClicked() {
notifyObservers();
}
......@@ -213,11 +217,12 @@ public class ExploreGameController implements Observer, Subject, GameController
* 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);
minCoords = new Vector2D(-1.6, -1);
maxCoords = new Vector2D(1.6, 1);
description = new ChaosGameDescription(
newMinCoords,
newMaxCoords, trans);
minCoords,
maxCoords, trans);
cumulativeScaleFactor = 1;
updateExplorePage();
}
......@@ -250,7 +255,6 @@ public class ExploreGameController implements Observer, Subject, GameController
? value : exploreTransform.getComplex().getY();
trans = List.of(new ExploreJulia(new Complex(realPart, imaginaryPart)));
description.setTransforms(trans);
updateExplorePage();
}
......
......@@ -13,7 +13,6 @@ import org.example.chaosgame.model.transformations.AffineTransform2D;
* The canvas also has an Affine transformation that maps coordinates, {@link Vector2D},
* to indices in the canvas array. This is used to map points to pixels in the canvas.
*/
public class ChaosCanvas {
private int width;
private int height;
......@@ -89,6 +88,11 @@ public class ChaosCanvas {
this.height = height;
}
public AffineTransform2D getTransformCoordsToIndices() {
return transformCoordsToIndices;
}
/**
* 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.
......@@ -105,6 +109,7 @@ public class ChaosCanvas {
((height - 1.0) * maxCoords.getY()) / (maxCoords.getY() - minCoords.getY()),
((width - 1.0) * minCoords.getX()) / (minCoords.getX() - maxCoords.getX())
));
}
/**
......@@ -166,4 +171,23 @@ public class ChaosCanvas {
}
}
}
/**
* Returns the pixel value at the given point.
* If the point is outside the canvas, the method returns 0.
*
* @param point The point to get the pixel value at
*
* @return The pixel value at the given point
*/
public double getPixel(Vector2D point) {
Vector2D indices = transformCoordsToIndices.transform(point);
int x = (int) indices.getX();
int y = (int) indices.getY();
if (x >= 0 && x < height && y >= 0 && y < width) {
return canvas[x][y];
}
return 0.0;
}
}
......@@ -79,7 +79,19 @@ public class ChaosGame implements Subject {
return totalSteps;
}
public void setSteps(int steps) {
/**
* Method for setting the number of steps to run.
*
* @param steps Number of steps to run
* @throws IllegalArgumentException If steps is less than 0 or greater than 1000000
*/
public void setSteps(int steps) throws IllegalArgumentException {
if (steps < 0) {
throw new IllegalArgumentException("Steps must be a positive number");
}
if (steps > 1000000) {
throw new IllegalArgumentException("Steps must be less than 1000000");
}
this.steps = steps;
}
......@@ -91,8 +103,13 @@ public class ChaosGame implements Subject {
* Method for setting the chaos game description.
*
* @param newDescription New description of the chaos game
* @throws IllegalArgumentException If newDescription is null
*/
public void setChaosGameDescription(ChaosGameDescription newDescription) {
public void setChaosGameDescription(ChaosGameDescription newDescription)
throws IllegalArgumentException {
if (newDescription == null) {
throw new IllegalArgumentException("Description cannot be null");
}
this.description = newDescription;
resetTotalSteps();
setChaosCanvas(description.getMinCoords(), description.getMaxCoords());
......@@ -112,7 +129,16 @@ public class ChaosGame implements Subject {
this.canvas.setTransformCoordsToIndices();
}
public void addTotalSteps(int newSteps) {
/**
* Method for adding steps to the total number of steps.
*
* @param newSteps Number of steps to add
* @throws IllegalArgumentException If newSteps is less than 0
*/
public void addTotalSteps(int newSteps) throws IllegalArgumentException {
if (newSteps < 0) {
throw new IllegalArgumentException("Steps must be a positive number");
}
this.totalSteps += newSteps;
}
......@@ -122,8 +148,9 @@ public class ChaosGame implements Subject {
/**
* Method for running the chaos game. Randomly selects a transformation
* from the description and applies it to the current point.
* Method for running the chaos game.
* Selects which runSteps method to use based if it has a list of probabilities.
* Notifies observers after running the steps.
*/
public void runSteps() {
if (description.getProbabilities() != null) {
......@@ -134,6 +161,10 @@ public class ChaosGame implements Subject {
notifyObservers();
}
/**
* Method for running the chaos game. Randomly selects a transformation
* from the description and applies it to the current point.
*/
private void runStepsUniform(int steps) {
for (int i = 0; i < steps; i++) {
int transformIndex = random.nextInt(description.getTransforms().size());
......
package org.example.chaosgame.model.chaos;
import java.util.List;
import java.util.Objects;
import org.example.chaosgame.model.linalg.Vector2D;
import org.example.chaosgame.model.transformations.Transform2D;
......@@ -28,6 +29,8 @@ public class ChaosGameDescription {
*/
public ChaosGameDescription(Vector2D minCoords, Vector2D maxCoords,
List<Transform2D> transforms) {
validateCoordinates(minCoords, maxCoords);
validateTransforms(transforms);
this.minCoords = minCoords;
this.maxCoords = maxCoords;
this.transforms = transforms;
......@@ -46,13 +49,55 @@ public class ChaosGameDescription {
* @param probabilities List of probabilities for the transformations
*/
public ChaosGameDescription(Vector2D minCoords, Vector2D maxCoords,
List<Transform2D> transforms, List<Integer> probabilities) {
List<Transform2D> transforms, List<Integer> probabilities)
throws IllegalArgumentException {
validateCoordinates(minCoords, maxCoords);
validateTransforms(transforms);
if (probabilities.size() != transforms.size()) {
throw new IllegalArgumentException("Probabilities must match the number of transformations");
}
this.minCoords = minCoords;
this.maxCoords = maxCoords;
this.transforms = transforms;
this.probabilities = probabilities;
}
/**
* Method for validating the coordinates.
*
* @param minCoords Minimum coordinates of the game area
*
* @param maxCoords Maximum coordinates of the game area
*/
private void validateCoordinates(Vector2D minCoords, Vector2D maxCoords) {
if (minCoords.getX() < -50 || minCoords.getY() < -50
|| minCoords.getX() > 50 || minCoords.getY() > 50
|| maxCoords.getX() > 50 || maxCoords.getY() > 50
|| maxCoords.getX() < -50 || maxCoords.getY() < -50) {
throw new IllegalArgumentException("Coordinates must be between -50 and 50");
} else if (minCoords.getX() > maxCoords.getX() || minCoords.getY() > maxCoords.getY()) {
throw new IllegalArgumentException(
"Minimum coordinates must be less than maximum coordinates");
}
if (minCoords.equals(maxCoords)) {
throw new IllegalArgumentException("Minimum and maximum coordinates cannot be the same");
}
}
/**
* Method for validating the transformations.
*
* @param transforms List of transformations to apply to the points
*/
private void validateTransforms(List<Transform2D> transforms) {
if (transforms == null) {
throw new IllegalArgumentException("Transformations cannot be null");
}
if (transforms.size() > 4 || transforms.isEmpty()) {
throw new IllegalArgumentException("Number of transformations must be between 1 and 4");
}
}
public Vector2D getMinCoords() {
return minCoords;
}
......@@ -70,6 +115,7 @@ public class ChaosGameDescription {
}
public void setTransforms(List<Transform2D> transforms) {
validateTransforms(transforms);
this.transforms = transforms;
}
......@@ -80,4 +126,24 @@ public class ChaosGameDescription {
public void setMaxCoords(Vector2D maxCoords) {
this.maxCoords = maxCoords;
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
ChaosGameDescription that = (ChaosGameDescription) o;
return Objects.equals(minCoords, that.minCoords)
&& Objects.equals(maxCoords, that.maxCoords)
&& Objects.equals(transforms, that.transforms)
&& Objects.equals(probabilities, that.probabilities);
}
@Override
public int hashCode() {
return Objects.hash(minCoords, maxCoords, transforms, probabilities);
}
}
......@@ -7,6 +7,8 @@ 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.
*/
......@@ -28,11 +30,28 @@ public class ExploreGame 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<>();
}
/**
* Method for setting the chaos game.
*
* @param description Description of the chaos game
*
* @param width Width of the canvas
*
* @param height Height of the canvas
*/
public void setExploreGame(ChaosGameDescription description, int width, int height) {
this.description = description;
setChaosCanvas(description.getMinCoords(), description.getMaxCoords(), width, height);
}
public ChaosCanvas getCanvas() {
return canvas;
}
......@@ -41,11 +60,6 @@ public class ExploreGame implements Subject {
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.
*
......
package org.example.chaosgame.model.linalg;
import java.util.Objects;
/**
* Record for 2x2 matrices.
* The matrices are represented by four double values: a, b, c, and d.
......@@ -37,4 +39,39 @@ public record Matrix2x2(double a, double b, double c, double d) {
this.c * vector.getX() + this.d * vector.getY()
);
}
/**
* Equals method for Matrix2x2.
* Compares the four double values of two Matrix2x2 objects.
* Generated by IntelliJ IDEA.
*
* @param o the object to compare.
* @return true if the objects are equal, false otherwise.
*/
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
Matrix2x2 matrix2x2 = (Matrix2x2) o;
return Double.compare(a, matrix2x2.a) == 0
&& Double.compare(b, matrix2x2.b) == 0
&& Double.compare(c, matrix2x2.c) == 0
&& Double.compare(d, matrix2x2.d) == 0;
}
/**
* Hashcode method for Matrix2x2.
* Use the four double values to generate the hashcode.
* Generated by IntelliJ IDEA.
*
* @return the hashcode of the Matrix2x2 object.
*/
@Override
public int hashCode() {
return Objects.hash(a, b, c, d);
}
}
package org.example.chaosgame.model.linalg;
import java.util.Objects;
/**
* Class for 2D vectors.
* Vectors are represented by an x-coordinate and a y-coordinate.
......@@ -98,4 +100,38 @@ public class Vector2D {
public double lengthSq() {
return x * x + y * y;
}
/**
* Equals method for Vector2D.
* Compares two vectors for equality.
* Overrides the default equals method.
* Generated by IntelliJ IDEA.
*
* @param o Object to compare
* @return true if the vectors are equal, false otherwise
*/
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
Vector2D vector2D = (Vector2D) o;
return Double.compare(x, vector2D.x) == 0 && Double.compare(y, vector2D.y) == 0;
}
/**
* Hashcode method for Vector2D.
* Overrides the default hashcode method.
* Generated by IntelliJ IDEA.
*
* @return the hashcode of the vector
*/
@Override
public int hashCode() {
return Objects.hash(x, y);
}
}
package org.example.chaosgame.model.transformations;
import java.util.Objects;
import org.example.chaosgame.model.linalg.Matrix2x2;
import org.example.chaosgame.model.linalg.Vector2D;
/**
* Record for 2D affine transformations.
* The transformation is represented by a 2x2 matrix and a 2D vector.
......@@ -33,4 +35,36 @@ public record AffineTransform2D(Matrix2x2 matrix, Vector2D vector) implements Tr
public Vector2D transform(Vector2D point) {
return matrix.multiply(point).add(vector);
}
/**
* Equals method for AffineTransform2D.
* Compares the matrix and vector of two AffineTransform2D objects.
* Generated by IntelliJ IDEA.
*
* @param o the object to compare
* @return true if the objects are equal, false otherwise
*/
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
AffineTransform2D that = (AffineTransform2D) o;
return Objects.equals(vector, that.vector) && Objects.equals(matrix, that.matrix);
}
/**
* Hashcode method for AffineTransform2D.
* Use the matrix and vector to generate the hashcode.
* Generated by IntelliJ IDEA.
*
* @return the hashcode of the AffineTransform2D object
*/
@Override
public int hashCode() {
return Objects.hash(matrix, vector);
}
}
package org.example.chaosgame.model.transformations;
import java.util.Objects;
import org.example.chaosgame.model.linalg.Complex;
import org.example.chaosgame.model.linalg.Vector2D;
......@@ -49,4 +50,37 @@ public class JuliaTransform implements Transform2D {
double b = sign * result.getY();
return new Vector2D(a, b);
}
/**
* Equals method for JuliaTransform.
* Compares the point and sign of two JuliaTransform objects.
* Generated by IntelliJ IDEA.
*
* @param o the object to compare
* @return true if the objects are equal, false otherwise
*/
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
JuliaTransform that = (JuliaTransform) o;
return sign == that.sign && Objects.equals(point, that.point);
}
/**
* Hashcode method for JuliaTransform.
* Generates a hashcode based on the point and sign of the JuliaTransform object.
* Generated by IntelliJ IDEA.
*
* @return the hashcode of the object
*/
@Override
public int hashCode() {
return Objects.hash(point, sign);
}
}
......@@ -30,10 +30,10 @@ public class ChaosPage extends GamePage {
this.bottomBar.getStyleClass().add("chaos-text");
SideBar sideBar = new SideBar(chaosGameController);
this.setCenter(gc.getCanvas());
this.setTop(topBar);
this.setRight(sideBar);
this.setBottom(bottomBar);
this.setLeft(gc.getCanvas());
}
/**
......@@ -45,7 +45,7 @@ public class ChaosPage extends GamePage {
* @param max the max coordinates
*/
public void updateInformation(Transform2D transformation, int steps, Vector2D min, Vector2D max) {
topBar.updateTopBar(transformation, steps, min, max);
topBar.updateTotalTopBar(transformation, steps, min, max);
bottomBar.updateBottomBar(transformation);
}
......
......@@ -36,13 +36,7 @@ public class ExplorePage extends GamePage {
this.setBottom(bottomBar);
this.setTop(topBar);
gc.getCanvas().setOnScroll(event -> {
try {
exploreGameController.onScroll(event);
} catch (Exception e) {
exploreGameController.resetImage();
}
});
gc.getCanvas().setOnScroll(exploreGameController::onScroll);
this.setOnMousePressed(exploreGameController::mousePressed);
this.setOnMouseDragged(exploreGameController::mouseDragged);
this.setOnMouseReleased(exploreGameController::mouseReleased);
......
......@@ -30,16 +30,15 @@ public class BottomBar extends HBox {
public BottomBar(GameController gameController) {
this.setSpacing(10);
this.realPartLabel = new Label();
this.realPartLabel.getStyleClass().add("top-bottom-padding");
this.imaginaryPartLabel = new Label();
this.imaginaryPartLabel.getStyleClass().add("top-bottom-padding");
this.sliderRealPart = new SliderRealPart(gameController);
this.sliderImaginaryPart = new SliderImaginaryPart(gameController);
realPartLabel.setMinSize(200, 20);
imaginaryPartLabel.setMinSize(200, 20);
realPartLabel.setAlignment(Pos.CENTER);
imaginaryPartLabel.setAlignment(Pos.CENTER);
this.setAlignment(javafx.geometry.Pos.CENTER);
this.setAlignment(Pos.CENTER);
this.getChildren().addAll(realPartLabel, sliderRealPart,
sliderImaginaryPart, imaginaryPartLabel);
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment