From e8fab927eb89c6ef9aca7a6e8aace5283d7dcde1 Mon Sep 17 00:00:00 2001
From: jez04 <david.jezek@post.cz>
Date: Thu, 14 Mar 2024 11:43:14 +0100
Subject: [PATCH] feat: lab start code

---
 .../cz/vsb/fei/java2/lab04/AppController.java | 167 ----------
 .../cz/vsb/fei/java2/lab04/ColorPoint.java    |  47 ---
 .../java/cz/vsb/fei/java2/lab04/Point.java    |  49 ---
 .../cz/vsb/fei/java2/lab04/{ => gui}/App.java |   2 +-
 .../fei/java2/lab04/gui/AppController.java    | 297 ++++++++++++++++++
 .../fei/java2/lab04/gui/LogarithmicAxis.java  | 232 ++++++++++++++
 .../java2/lab04/measurment/Measurment.java    |  55 ++++
 .../fei/java2/lab04/points/ColorPoint.java    |  50 +++
 .../cz/vsb/fei/java2/lab04/points/Point.java  |  88 ++++++
 src/main/java/module-info.java                |   9 +-
 .../fei/java2/lab04/{ => gui}/AppWindow.fxml  |  47 ++-
 .../fei/java2/lab04/{ => gui}/application.css |   0
 12 files changed, 751 insertions(+), 292 deletions(-)
 delete mode 100644 src/main/java/cz/vsb/fei/java2/lab04/AppController.java
 delete mode 100644 src/main/java/cz/vsb/fei/java2/lab04/ColorPoint.java
 delete mode 100644 src/main/java/cz/vsb/fei/java2/lab04/Point.java
 rename src/main/java/cz/vsb/fei/java2/lab04/{ => gui}/App.java (97%)
 create mode 100644 src/main/java/cz/vsb/fei/java2/lab04/gui/AppController.java
 create mode 100644 src/main/java/cz/vsb/fei/java2/lab04/gui/LogarithmicAxis.java
 create mode 100644 src/main/java/cz/vsb/fei/java2/lab04/measurment/Measurment.java
 create mode 100644 src/main/java/cz/vsb/fei/java2/lab04/points/ColorPoint.java
 create mode 100644 src/main/java/cz/vsb/fei/java2/lab04/points/Point.java
 rename src/main/resources/cz/vsb/fei/java2/lab04/{ => gui}/AppWindow.fxml (77%)
 rename src/main/resources/cz/vsb/fei/java2/lab04/{ => gui}/application.css (100%)

diff --git a/src/main/java/cz/vsb/fei/java2/lab04/AppController.java b/src/main/java/cz/vsb/fei/java2/lab04/AppController.java
deleted file mode 100644
index b4c4b94..0000000
--- a/src/main/java/cz/vsb/fei/java2/lab04/AppController.java
+++ /dev/null
@@ -1,167 +0,0 @@
-package cz.vsb.fei.java2.lab04;
-
-import java.util.Arrays;
-import java.util.List;
-import java.util.Random;
-import java.util.stream.Stream;
-
-import javafx.beans.binding.ObjectBinding;
-import javafx.beans.value.ObservableValue;
-import javafx.collections.FXCollections;
-import javafx.collections.ObservableList;
-import javafx.event.ActionEvent;
-import javafx.fxml.FXML;
-import javafx.scene.canvas.Canvas;
-import javafx.scene.canvas.GraphicsContext;
-import javafx.scene.chart.BarChart;
-import javafx.scene.chart.XYChart;
-import javafx.scene.chart.XYChart.Data;
-import javafx.scene.control.SelectionMode;
-import javafx.scene.control.TableColumn;
-import javafx.scene.control.TableView;
-import javafx.scene.control.cell.PropertyValueFactory;
-import javafx.scene.layout.BorderPane;
-import javafx.scene.paint.Color;
-
-public class AppController {
-
-	private static final Random RANDOM = new Random();
-	private static final List<Color> COLORS = Arrays.asList(Color.RED, Color.BLUE, Color.YELLOW, Color.BLACK,
-			Color.ORANGE, Color.PINK, Color.PURPLE);
-
-	@FXML
-	private TableView<Point> table1;
-	private ObservableList<Point> points1 = FXCollections.observableArrayList();
-
-	private Canvas canvas = new Canvas() {
-		@Override
-		public boolean isResizable() {
-			return true;
-		}
-	};
-
-	@FXML
-	private BorderPane pane;
-
-	@FXML
-	private BarChart<String, Long> chart;
-
-	@FXML
-	public void initialize() {
-		table1.setItems(points1);
-
-		initColumns(table1);
-		table1.getSelectionModel().setSelectionMode(SelectionMode.SINGLE);
-		table1.getSelectionModel().selectedItemProperty()
-				.addListener((ObservableValue<? extends Point> observable, Point oldValue, Point newValue) -> draw());
-		canvas.setWidth(200);
-		canvas.setHeight(200);
-		pane.setCenter(canvas);
-		pane.widthProperty()
-				.addListener((observer, oldValue, newValue) -> canvas.setWidth(newValue.doubleValue() * 0.9));
-		pane.heightProperty()
-				.addListener((observer, oldValue, newValue) -> canvas.setHeight(newValue.doubleValue() * 0.9));
-		canvas.boundsInLocalProperty().addListener((observable, oldValue, newValue) -> draw());
-		draw();
-
-	}
-
-	private void draw() {
-		GraphicsContext gc = canvas.getGraphicsContext2D();
-		double maxX = canvas.getWidth();
-		double maxY = canvas.getHeight();
-		double centerX = maxX / 2;
-		double centerY = maxY / 2;
-		gc.setFill(Color.WHITE);
-		gc.fillRect(0, 0, canvas.getWidth(), canvas.getHeight());
-		gc.setStroke(Color.BLACK);
-		gc.strokeLine(centerX, 0, centerX, maxY);
-		gc.strokeLine(0, centerY, maxX, centerY);
-		gc.setFill(Color.BLACK);
-		Point selectedPoint = table1.getSelectionModel().getSelectedItem();
-		for (Point point : points1) {
-			if (point instanceof ColorPoint colorPoint) {
-				gc.setFill(colorPoint.getColor());
-				gc.fillOval(centerX + colorPoint.getX() - 2, centerY + colorPoint.getY() - 2, 4, 4);
-			} else {
-				gc.strokeOval(centerX + point.getX() - 2, centerY + point.getY() - 2, 4, 4);
-			}
-			if (point.equals(selectedPoint)) {
-				gc.setStroke(Color.RED);
-				gc.strokeLine(centerX + point.getX() - 15, centerY + point.getY(), centerX + point.getX() - 6,
-						centerY + point.getY());
-				gc.strokeLine(centerX + point.getX() + 6, centerY + point.getY(), centerX + point.getX() + 15,
-						centerY + point.getY());
-				gc.strokeLine(centerX + point.getX(), centerY + point.getY() - 15, centerX + point.getX(),
-						centerY + point.getY() - 6);
-				gc.strokeLine(centerX + point.getX(), centerY + point.getY() + 6, centerX + point.getX(),
-						centerY + point.getY() + 15);
-			}
-		}
-	}
-
-	private void initColumns(TableView<Point> tab) {
-		((TableColumn<Point, Double>) tab.getColumns().get(0)).setCellValueFactory(new PropertyValueFactory<>("x"));
-		((TableColumn<Point, Double>) tab.getColumns().get(1)).setCellValueFactory(new PropertyValueFactory<>("y"));
-		((TableColumn<Point, Color>) tab.getColumns().get(2)).setCellValueFactory(param -> {
-			if (param.getValue() instanceof ColorPoint p) {
-				return new MyObservableValue<>(p.getColor());
-			}
-			return null;
-		});
-		((TableColumn<Point, Integer>) tab.getColumns().get(3))
-				.setCellValueFactory(param -> new MyObservableValue<>(System.identityHashCode(param.getValue())));
-	}
-
-	@FXML
-	private void generatePressed(ActionEvent event) {
-		Stream.generate(this::generate).limit(10).forEach(points1::add);
-		draw();
-	}
-
-	@FXML
-	private void clearPressed(ActionEvent event) {
-		table1.getSelectionModel().clearSelection();
-		points1.clear();
-		draw();
-	}
-
-	@FXML
-	private void measure(ActionEvent event) {
-		XYChart.Series<String, Long> containsSpeed = new XYChart.Series<>();
-		containsSpeed.setName("Speed of method contains() for interface Set");
-		int i=10;
-		while(i<=100000) {
-			containsSpeed.getData().add(new Data<>(Integer.toString(i), RANDOM.nextLong(i*100l)));
-			i*=2;
-		}
-		chart.getData().add(containsSpeed);
-	}
-
-	private Point generate() {
-		if (RANDOM.nextBoolean()) {
-			return new Point(canvas.getWidth() / 2 - RANDOM.nextDouble(canvas.getWidth()),
-					canvas.getHeight() / 2 - RANDOM.nextDouble(canvas.getHeight()));
-		} else {
-			return new ColorPoint(canvas.getWidth() / 2 - RANDOM.nextDouble(canvas.getWidth()),
-					canvas.getHeight() / 2 - RANDOM.nextDouble(canvas.getHeight()),
-					COLORS.get(RANDOM.nextInt(COLORS.size())));
-		}
-	}
-
-	public static class MyObservableValue<T> extends ObjectBinding<T> {
-
-		private T value;
-
-		public MyObservableValue(T color) {
-			this.value = color;
-		}
-
-		@Override
-		public T computeValue() {
-			return value;
-		}
-
-	}
-
-}
diff --git a/src/main/java/cz/vsb/fei/java2/lab04/ColorPoint.java b/src/main/java/cz/vsb/fei/java2/lab04/ColorPoint.java
deleted file mode 100644
index 4dce08c..0000000
--- a/src/main/java/cz/vsb/fei/java2/lab04/ColorPoint.java
+++ /dev/null
@@ -1,47 +0,0 @@
-package cz.vsb.fei.java2.lab04;
-
-import java.util.Objects;
-
-import javafx.scene.paint.Color;
-
-public class ColorPoint extends Point {
-
-	private Color color;
-
-	public ColorPoint(double x, double y, Color color) {
-		super(x, y);
-		this.color = color;
-	}
-
-	public Color getColor() {
-		return color;
-	}
-
-	@Override
-	public int hashCode() {
-		final int prime = 31;
-		int result = super.hashCode();
-		result = prime * result + Objects.hash(color);
-		return result;
-	}
-
-	@Override
-	public boolean equals(Object obj) {
-		if (this == obj)
-			return true;
-		if (!super.equals(obj))
-			return false;
-		if (!(obj instanceof ColorPoint))
-			return false;
-		ColorPoint other = (ColorPoint) obj;
-		if (!other.canEqual(this)) {
-			return false;
-		}
-		return Objects.equals(color, other.color);
-	}
-
-	@Override
-	public boolean canEqual(Point p) {
-		return p instanceof ColorPoint;
-	}
-}
diff --git a/src/main/java/cz/vsb/fei/java2/lab04/Point.java b/src/main/java/cz/vsb/fei/java2/lab04/Point.java
deleted file mode 100644
index d493f9e..0000000
--- a/src/main/java/cz/vsb/fei/java2/lab04/Point.java
+++ /dev/null
@@ -1,49 +0,0 @@
-package cz.vsb.fei.java2.lab04;
-
-import java.util.Objects;
-
-public class Point {
-
-	private double x;
-
-	private double y;
-
-	public Point(double x, double y) {
-		this.x = x;
-		this.y = y;
-	}
-
-	public double getX() {
-		return x;
-	}
-
-	public double getY() {
-		return y;
-	}
-
-	@Override
-	public int hashCode() {
-		return Objects.hash(x, y);
-	}
-
-	@Override
-	public boolean equals(Object obj) {
-		if (this == obj)
-			return true;
-		if (obj == null)
-			return false;
-		if (!(obj instanceof Point))
-			return false;
-		Point other = (Point) obj;
-		if (!other.canEqual(this)) {
-			return false;
-		}
-		return Double.doubleToLongBits(x) == Double.doubleToLongBits(other.x)
-				&& Double.doubleToLongBits(y) == Double.doubleToLongBits(other.y);
-	}
-
-	public boolean canEqual(Point p) {
-		return p instanceof Point;
-	}
-
-}
\ No newline at end of file
diff --git a/src/main/java/cz/vsb/fei/java2/lab04/App.java b/src/main/java/cz/vsb/fei/java2/lab04/gui/App.java
similarity index 97%
rename from src/main/java/cz/vsb/fei/java2/lab04/App.java
rename to src/main/java/cz/vsb/fei/java2/lab04/gui/App.java
index d2abb16..e1e216e 100644
--- a/src/main/java/cz/vsb/fei/java2/lab04/App.java
+++ b/src/main/java/cz/vsb/fei/java2/lab04/gui/App.java
@@ -1,4 +1,4 @@
-package cz.vsb.fei.java2.lab04;
+package cz.vsb.fei.java2.lab04.gui;
 
 import javafx.application.Application;
 import javafx.fxml.FXMLLoader;
diff --git a/src/main/java/cz/vsb/fei/java2/lab04/gui/AppController.java b/src/main/java/cz/vsb/fei/java2/lab04/gui/AppController.java
new file mode 100644
index 0000000..7f5f63e
--- /dev/null
+++ b/src/main/java/cz/vsb/fei/java2/lab04/gui/AppController.java
@@ -0,0 +1,297 @@
+package cz.vsb.fei.java2.lab04.gui;
+
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Optional;
+import java.util.Random;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+import cz.vsb.fei.java2.lab04.measurment.Measurment;
+import cz.vsb.fei.java2.lab04.measurment.Measurment.InsertContainsMeasurmentResult;
+import cz.vsb.fei.java2.lab04.measurment.Measurment.ReleabilityMeasurmentResult;
+import cz.vsb.fei.java2.lab04.points.ColorPoint;
+import cz.vsb.fei.java2.lab04.points.Point;
+import cz.vsb.fei.java2.lab04.points.Point.HashImpl;
+import javafx.beans.binding.ObjectBinding;
+import javafx.beans.value.ObservableValue;
+import javafx.collections.FXCollections;
+import javafx.collections.ObservableList;
+import javafx.event.ActionEvent;
+import javafx.fxml.FXML;
+import javafx.scene.canvas.Canvas;
+import javafx.scene.canvas.GraphicsContext;
+import javafx.scene.chart.BarChart;
+import javafx.scene.chart.CategoryAxis;
+import javafx.scene.chart.NumberAxis;
+import javafx.scene.chart.XYChart;
+import javafx.scene.chart.XYChart.Data;
+import javafx.scene.control.Alert;
+import javafx.scene.control.Alert.AlertType;
+import javafx.scene.control.Label;
+import javafx.scene.control.SelectionMode;
+import javafx.scene.control.TableColumn;
+import javafx.scene.control.TableView;
+import javafx.scene.control.cell.PropertyValueFactory;
+import javafx.scene.input.MouseEvent;
+import javafx.scene.layout.BorderPane;
+import javafx.scene.layout.VBox;
+import javafx.scene.paint.Color;
+import lombok.extern.log4j.Log4j2;
+
+@Log4j2
+public class AppController {
+
+    private static final Random RANDOM = new Random();
+
+    @FXML
+    private TableView<Point> table1;
+    private ObservableList<Point> points1 = FXCollections.observableArrayList();
+
+    private Canvas canvas = new Canvas() {
+	@Override
+	public boolean isResizable() {
+	    return true;
+	}
+    };
+
+    @FXML
+    private BorderPane pane;
+
+    private BarChart<String, Double> insertTimeChart;
+
+    private BarChart<String, Double> containsTimeCahrt;
+    private BarChart<String, Number> releabilityChart;
+
+    @FXML
+    private VBox chartBox;
+
+    @FXML
+    public void initialize() {
+	table1.setItems(points1);
+
+	initColumns(table1);
+	table1.getSelectionModel().setSelectionMode(SelectionMode.SINGLE);
+	table1.getSelectionModel().selectedItemProperty()
+		.addListener((ObservableValue<? extends Point> observable, Point oldValue, Point newValue) -> draw());
+	canvas.setWidth(200);
+	canvas.setHeight(200);
+	pane.setCenter(canvas);
+	pane.widthProperty()
+		.addListener((observer, oldValue, newValue) -> canvas.setWidth(newValue.doubleValue() * 0.9));
+	pane.heightProperty()
+		.addListener((observer, oldValue, newValue) -> canvas.setHeight(newValue.doubleValue() * 0.9));
+	canvas.boundsInLocalProperty().addListener((observable, oldValue, newValue) -> draw());
+	canvas.setOnMouseClicked(this::mouseClickedInDrawingArea);
+	draw();
+	insertTimeChart = new BarChart<>(new CategoryAxis(), new LogarithmicAxis());
+	containsTimeCahrt = new BarChart<>(new CategoryAxis(), new LogarithmicAxis());
+	releabilityChart = new BarChart<>(new CategoryAxis(), new NumberAxis());
+	chartBox.getChildren().add(new Label("Time of inserting points into set in seconds"));
+	chartBox.getChildren().add(insertTimeChart);
+	chartBox.getChildren().add(new Label("Average time (20 attempts) of method contains for set in seconds"));
+	chartBox.getChildren().add(containsTimeCahrt);
+	chartBox.getChildren().add(new Label("Releability of method contains (100 attempts) in percentage"));
+	chartBox.getChildren().add(releabilityChart);
+
+    }
+
+    private void draw() {
+	GraphicsContext gc = canvas.getGraphicsContext2D();
+	double maxX = canvas.getWidth();
+	double maxY = canvas.getHeight();
+	double centerX = maxX / 2;
+	double centerY = maxY / 2;
+	gc.setFill(Color.WHITE);
+	gc.fillRect(0, 0, canvas.getWidth(), canvas.getHeight());
+	gc.setStroke(Color.BLACK);
+	gc.strokeLine(centerX, 0, centerX, maxY);
+	gc.strokeLine(0, centerY, maxX, centerY);
+	gc.setFill(Color.BLACK);
+	Point selectedPoint = table1.getSelectionModel().getSelectedItem();
+	for (Point point : points1) {
+	    if (point instanceof ColorPoint colorPoint) {
+		gc.setFill(colorPoint.getColor());
+		gc.fillOval(centerX + colorPoint.getX() - 2, centerY + colorPoint.getY() - 2, 4, 4);
+	    } else {
+		gc.setStroke(Color.BLACK);
+		gc.strokeOval(centerX + point.getX() - 2, centerY + point.getY() - 2, 4, 4);
+	    }
+	    if (point.equals(selectedPoint)) {
+		drawCroshairAroundPoint(gc, point);
+	    }
+	}
+    }
+
+    private void drawCroshairAroundPoint(GraphicsContext gc, Point point) {
+	double maxX = canvas.getWidth();
+	double maxY = canvas.getHeight();
+	double centerX = maxX / 2;
+	double centerY = maxY / 2;
+	gc.setStroke(Color.RED);
+	gc.strokeLine(centerX + point.getX() - 15, centerY + point.getY(), centerX + point.getX() - 6,
+		centerY + point.getY());
+	gc.strokeLine(centerX + point.getX() + 6, centerY + point.getY(), centerX + point.getX() + 15,
+		centerY + point.getY());
+	gc.strokeLine(centerX + point.getX(), centerY + point.getY() - 15, centerX + point.getX(),
+		centerY + point.getY() - 6);
+	gc.strokeLine(centerX + point.getX(), centerY + point.getY() + 6, centerX + point.getX(),
+		centerY + point.getY() + 15);
+    }
+
+    private void initColumns(TableView<Point> tab) {
+	((TableColumn<Point, Double>) tab.getColumns().get(0)).setCellValueFactory(new PropertyValueFactory<>("x"));
+	((TableColumn<Point, Double>) tab.getColumns().get(1)).setCellValueFactory(new PropertyValueFactory<>("y"));
+	((TableColumn<Point, Color>) tab.getColumns().get(2)).setCellValueFactory(param -> {
+	    if (param.getValue() instanceof ColorPoint p) {
+		return new MyObservableValue<>(p.getColor());
+	    }
+	    return null;
+	});
+	((TableColumn<Point, Integer>) tab.getColumns().get(3))
+		.setCellValueFactory(param -> new MyObservableValue<>(System.identityHashCode(param.getValue())));
+    }
+
+    @FXML
+    private void generatePressed(ActionEvent event) {
+	double maxX = canvas.getWidth();
+	double maxY = canvas.getHeight();
+	try {
+	    Stream.generate(() -> Point.generateInRange(-maxX / 2, maxX / 2, -maxY / 2, maxY / 2)).limit(10)
+	    	.forEach(points1::add);
+	} catch (Exception ex) {
+	    showErrorAlert(ex.getMessage());
+	    log.error("Error while generate points.", ex);
+	}
+	draw();
+    }
+
+    private void showErrorAlert(List<String> messages) {
+	String message = "Exception messages:\n\t" + messages.stream().collect(Collectors.joining("\n\t"));
+	Alert alert = new Alert(AlertType.ERROR);
+	alert.setTitle("ExceptionOccurred");
+	Label text = new Label(message);
+	text.setWrapText(true);
+	Label header = new Label("Can We Implement It?\n\tYes We Can!!!");
+	header.setWrapText(true);
+	alert.getDialogPane().setContent(text);
+	alert.getDialogPane().setHeader(header);
+	alert.show();
+    }
+
+    private void showErrorAlert(String message) {
+	Alert alert = new Alert(AlertType.ERROR);
+	alert.setTitle("ExceptionOccurred");
+	Label text = new Label(message);
+	text.setWrapText(true);
+	Label header = new Label("Can We Implement It?\nYes We Can!!!");
+	header.setWrapText(true);
+	alert.getDialogPane().setContent(text);
+	alert.getDialogPane().setHeader(header);
+	alert.show();
+    }
+
+    @FXML
+    private void generateInRadiusPressed(ActionEvent event) {
+	double radius = 10 + RANDOM.nextDouble(200);
+	final Point center = Optional.ofNullable(table1.getSelectionModel().getSelectedItem()).orElse(new Point(0, 0));
+	try {
+	    Stream.generate(() -> Point.generateInRadius(center, radius)).limit(30).forEach(points1::add);
+	} catch (Exception ex) {
+	    showErrorAlert(ex.getMessage());
+	    log.error("Error while generate points in radius.", ex);
+	}
+	draw();
+    }
+
+    @FXML
+    private void mouseClickedInDrawingArea(MouseEvent event) {
+	double maxX = canvas.getWidth();
+	double maxY = canvas.getHeight();
+	double x = event.getX() - maxX / 2;
+	double y = event.getY() - maxY / 2;
+	points1.stream().filter(p -> Math.abs(p.getX() - x) < 5 && Math.abs(p.getY() - y) < 5).findFirst()
+		.ifPresent(p -> {
+		    table1.selectionModelProperty().get().select(p);
+		    table1.scrollTo(p);
+		});
+    }
+
+    @FXML
+    private void clearPressed(ActionEvent event) {
+	table1.getSelectionModel().clearSelection();
+	points1.clear();
+	draw();
+    }
+
+    @FXML
+    private void measure1000(ActionEvent event) {
+	measure(1000);
+    }
+
+    @FXML
+    private void measure10000(ActionEvent event) {
+	measure(10000);
+    }
+
+    @FXML
+    private void measure100000(ActionEvent event) {
+	measure(100000);
+    }
+
+    private void measure(int maxCount) {
+	insertTimeChart.getData().clear();
+	containsTimeCahrt.getData().clear();
+	releabilityChart.getData().clear();
+	XYChart.Series<String, Number> containsSameReleability = new XYChart.Series<>();
+	XYChart.Series<String, Number> containsEqualReleability = new XYChart.Series<>();
+	containsSameReleability.setName("for same instance.");
+	containsEqualReleability.setName("for equal instance.");
+	List<String> errorMessages  =new LinkedList<String>();
+	for (HashImpl hashImpl : HashImpl.values()) {
+	    try {
+		Point.setHashImplTo(hashImpl);
+		XYChart.Series<String, Double> containsSpeed = new XYChart.Series<>();
+		XYChart.Series<String, Double> insertSpeed = new XYChart.Series<>();
+		containsSpeed.setName("implementation " + Point.getHashImpl());
+		insertSpeed.setName("implementation " + Point.getHashImpl());
+		int i = 10;
+		while (i <= maxCount) {
+		InsertContainsMeasurmentResult measureResult = Measurment.mesure(i);
+		Data<String, Double> d = new Data<>(Integer.toString(i), measureResult.containsDuration() / 1000000d);
+		containsSpeed.getData().add(d);
+		insertSpeed.getData().add(new Data<>(Integer.toString(i), measureResult.insertDuration() / 1000000d));
+		i *= 10;
+		}
+		ReleabilityMeasurmentResult result = Measurment.mesureReleability();
+		containsSameReleability.getData().add(new Data<>(hashImpl.toString(), result.countSameInstance()));
+		containsEqualReleability.getData().add(new Data<>(hashImpl.toString(), result.countEqualObject()));
+		insertTimeChart.getData().add(insertSpeed);
+		containsTimeCahrt.getData().add(containsSpeed);
+	    } catch (Exception ex) {
+		errorMessages.add(ex.getMessage());
+		log.error("Error while mesure speed." , ex);
+	    }
+	}
+	releabilityChart.getData().addAll(containsSameReleability, containsEqualReleability);
+	if(!errorMessages.isEmpty()) {
+	    showErrorAlert(errorMessages);
+	}
+    }
+
+    public static class MyObservableValue<T> extends ObjectBinding<T> {
+
+	private T value;
+
+	public MyObservableValue(T color) {
+	    this.value = color;
+	}
+
+	@Override
+	public T computeValue() {
+	    return value;
+	}
+
+    }
+
+}
diff --git a/src/main/java/cz/vsb/fei/java2/lab04/gui/LogarithmicAxis.java b/src/main/java/cz/vsb/fei/java2/lab04/gui/LogarithmicAxis.java
new file mode 100644
index 0000000..90499d5
--- /dev/null
+++ b/src/main/java/cz/vsb/fei/java2/lab04/gui/LogarithmicAxis.java
@@ -0,0 +1,232 @@
+package cz.vsb.fei.java2.lab04.gui;
+
+import java.text.NumberFormat;
+import java.util.ArrayList;
+import java.util.List;
+
+import javafx.animation.KeyFrame;
+import javafx.animation.KeyValue;
+import javafx.animation.Timeline;
+import javafx.beans.binding.DoubleBinding;
+import javafx.beans.property.DoubleProperty;
+import javafx.beans.property.SimpleDoubleProperty;
+import javafx.scene.chart.ValueAxis;
+import javafx.util.Duration;
+
+/**
+ * A logarithmic axis implementation for JavaFX 2 charts<br>
+ * <br>
+ * 
+ * @author Kevin Senechal
+ * 
+ */
+public class LogarithmicAxis extends ValueAxis<Double> {
+
+    /**
+     * The time of animation in ms
+     */
+    private static final double ANIMATION_TIME = 2000;
+    private final Timeline lowerRangeTimeline = new Timeline();
+    private final Timeline upperRangeTimeline = new Timeline();
+
+    private final DoubleProperty logUpperBound = new SimpleDoubleProperty();
+    private final DoubleProperty logLowerBound = new SimpleDoubleProperty();
+
+    public LogarithmicAxis() {
+        super(0.00001, 10);
+        bindLogBoundsToDefaultBounds();
+        setAutoRanging(true);
+    }
+
+    public LogarithmicAxis(double lowerBound, double upperBound) {
+        super(lowerBound, upperBound);
+        try {
+            validateBounds(lowerBound, upperBound);
+            bindLogBoundsToDefaultBounds();
+        } catch (IllegalLogarithmicRangeException e) {
+            e.printStackTrace();
+        }
+    }
+
+    /**
+     * Bind our logarithmic bounds with the super class bounds, consider the base 10 logarithmic scale.
+     */
+    private void bindLogBoundsToDefaultBounds() {
+        logLowerBound.bind(new DoubleBinding() {
+
+            {
+                super.bind(lowerBoundProperty());
+            }
+
+            @Override
+            protected double computeValue() {
+                return Math.log10(lowerBoundProperty().get());
+            }
+        });
+        logUpperBound.bind(new DoubleBinding() {
+
+            {
+                super.bind(upperBoundProperty());
+            }
+
+            @Override
+            protected double computeValue() {
+                return Math.log10(upperBoundProperty().get());
+            }
+        });
+    }
+
+    /**
+     * Validate the bounds by throwing an exception if the values are not conform to the mathematics log interval:
+     * ]0,Double.MAX_VALUE]
+     * 
+     * @param lowerBound
+     * @param upperBound
+     * @throws IllegalLogarithmicRangeException
+     */
+    private void validateBounds(double lowerBound, double upperBound) throws IllegalLogarithmicRangeException {
+        if (lowerBound < 0 || upperBound < 0 || lowerBound > upperBound) {
+            throw new IllegalLogarithmicRangeException(
+                    "The logarithmic range should be include to ]0,Double.MAX_VALUE] and the lowerBound should be less than the upperBound");
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    protected List<Double> calculateMinorTickMarks() {
+        Number[] range = getRange();
+        List<Double> minorTickMarksPositions = new ArrayList<>();
+        if (range != null) {
+
+            Number upperBound = range[1];
+            double logUpperBound = Math.log10(upperBound.doubleValue());
+            int minorTickMarkCount = getMinorTickCount();
+
+            for (double i = 0; i <= logUpperBound; i += 1) {
+                for (double j = 0; j <= 9; j += (1. / minorTickMarkCount)) {
+                    double value = j * Math.pow(10, i);
+                    minorTickMarksPositions.add(value);
+                }
+            }
+        }
+        return minorTickMarksPositions;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    protected List<Double> calculateTickValues(double length, Object range) {
+        List<Double> tickPositions = new ArrayList<>();
+        if (range != null) {
+            Number lowerBound = ((Number[]) range)[0];
+            Number upperBound = ((Number[]) range)[1];
+            double logLowerBound = Math.log10(lowerBound.doubleValue());
+            double logUpperBound = Math.log10(upperBound.doubleValue());
+    
+            for (double i = logLowerBound; i <= logUpperBound; i += 1) {
+                for (double j = 1; j <= 9; j++) {
+                    double value = j * Math.pow(10, i);
+                    tickPositions.add(value);
+                }
+            }
+        }
+        return tickPositions;
+    }
+
+    @Override
+    protected Number[] getRange() {
+        return new Number[] { lowerBoundProperty().get(), upperBoundProperty().get() };
+    }
+
+    @Override
+    protected String getTickMarkLabel(Double value) {
+        NumberFormat formatter = NumberFormat.getInstance();
+        formatter.setMaximumIntegerDigits(6);
+        formatter.setMinimumIntegerDigits(1);
+        formatter.setMaximumFractionDigits(5);
+        return formatter.format(value);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    protected void setRange(Object range, boolean animate) {
+        if (range != null) {
+            Number lowerBound = ((Number[]) range)[0];
+            Number upperBound = ((Number[]) range)[1];
+            try {
+                validateBounds(lowerBound.doubleValue(), upperBound.doubleValue());
+            } catch (IllegalLogarithmicRangeException e) {
+                e.printStackTrace();
+            }
+            if (animate) {
+                try {
+                    lowerRangeTimeline.getKeyFrames().clear();
+                    upperRangeTimeline.getKeyFrames().clear();
+
+                    lowerRangeTimeline.getKeyFrames()
+                            .addAll(new KeyFrame(Duration.ZERO, new KeyValue(lowerBoundProperty(), lowerBoundProperty()
+                                    .get())),
+                                    new KeyFrame(new Duration(ANIMATION_TIME), new KeyValue(lowerBoundProperty(),
+                                            lowerBound.doubleValue())));
+
+                    upperRangeTimeline.getKeyFrames()
+                            .addAll(new KeyFrame(Duration.ZERO, new KeyValue(upperBoundProperty(), upperBoundProperty()
+                                    .get())),
+                                    new KeyFrame(new Duration(ANIMATION_TIME), new KeyValue(upperBoundProperty(),
+                                            upperBound.doubleValue())));
+                    lowerRangeTimeline.play();
+                    upperRangeTimeline.play();
+                } catch (Exception e) {
+                    lowerBoundProperty().set(lowerBound.doubleValue());
+                    upperBoundProperty().set(upperBound.doubleValue());
+                }
+            }
+            lowerBoundProperty().set(lowerBound.doubleValue());
+            upperBoundProperty().set(upperBound.doubleValue());
+        }
+    }
+    
+    
+
+    @Override
+    protected Object autoRange(double minValue, double maxValue, double length, double labelSize) {
+      return new Number[] {minValue, maxValue};
+    }
+
+    @Override
+    public Double getValueForDisplay(double displayPosition) {
+        double delta = logUpperBound.get() - logLowerBound.get();
+        if (getSide().isVertical()) {
+            return Math.pow(10, (((displayPosition - getHeight()) / -getHeight()) * delta) + logLowerBound.get());
+        } else {
+            return Math.pow(10, (((displayPosition / getWidth()) * delta) + logLowerBound.get()));
+        }
+    }
+
+    @Override
+    public double getDisplayPosition(Double value) {
+        double delta = logUpperBound.get() - logLowerBound.get();
+        double deltaV = Math.log10(value.doubleValue()) - logLowerBound.get();
+        if (getSide().isVertical()) {
+            return (1. - ((deltaV) / delta)) * getHeight();
+        } else {
+            return ((deltaV) / delta) * getWidth();
+        }
+    }
+    
+    public static class IllegalLogarithmicRangeException extends Exception {
+
+      /**
+       * @param string
+       */
+      public IllegalLogarithmicRangeException(String message) {
+          super(message);
+      }
+
+  }
+}
diff --git a/src/main/java/cz/vsb/fei/java2/lab04/measurment/Measurment.java b/src/main/java/cz/vsb/fei/java2/lab04/measurment/Measurment.java
new file mode 100644
index 0000000..cf9d8ef
--- /dev/null
+++ b/src/main/java/cz/vsb/fei/java2/lab04/measurment/Measurment.java
@@ -0,0 +1,55 @@
+package cz.vsb.fei.java2.lab04.measurment;
+
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import java.util.stream.Stream;
+
+import cz.vsb.fei.java2.lab04.points.Point;
+
+public class Measurment {
+
+    public record InsertContainsMeasurmentResult(long insertDuration, long containsDuration) {
+    }
+
+    public record ReleabilityMeasurmentResult(int countSameInstance, int countEqualObject) {
+    }
+
+    public static InsertContainsMeasurmentResult mesure(int pointCollectionSize) {
+	//TODO: generate pointCollectionSize random points
+	List<Point> pointsToInsert = Collections.emptyList();
+	//TODO: generate 20 random points
+	List<Point> pointsToTest = Collections.emptyList();
+
+	//TODO: create hash set
+	Set<Point> pointsSet = Collections.emptySet();
+	
+	long start = System.nanoTime();
+	//TODO: insert point to Set
+	long insertDuration = (System.nanoTime() - start) / pointsToInsert.size();
+
+	start = System.nanoTime();
+	//TODO: call method Set.contains with all points in set pointsToTest
+	long containsDuration = (System.nanoTime() - start) / pointsToTest.size();
+	
+	return new InsertContainsMeasurmentResult(insertDuration, containsDuration);
+    }
+
+    public static ReleabilityMeasurmentResult mesureReleability() {
+	//TODO: generate 100 random points
+	List<Point> pointsToInsert = Collections.emptyList();
+	//TODO: create hash set
+	Set<Point> pointsSet = Collections.emptySet();
+	
+	//TODO:insert point to Set
+	
+	int countSameInstance = 0;
+	int countEqualObject = 0;
+
+	//TODO: calculate for how many points in the list the method Set.contains method returns true (should be true for all)
+
+	return new ReleabilityMeasurmentResult(countSameInstance, countEqualObject);
+    }
+
+}
diff --git a/src/main/java/cz/vsb/fei/java2/lab04/points/ColorPoint.java b/src/main/java/cz/vsb/fei/java2/lab04/points/ColorPoint.java
new file mode 100644
index 0000000..3560db2
--- /dev/null
+++ b/src/main/java/cz/vsb/fei/java2/lab04/points/ColorPoint.java
@@ -0,0 +1,50 @@
+package cz.vsb.fei.java2.lab04.points;
+
+import java.util.Objects;
+
+import javafx.scene.paint.Color;
+
+public class ColorPoint extends Point {
+
+    private Color color;
+
+    public ColorPoint(double x, double y, Color color) {
+	super(x, y);
+	this.color = color;
+    }
+
+    @Override
+    public Point createCopy() {
+	return new ColorPoint(getX(), getY(), color);
+    }
+
+    public Color getColor() {
+	return color;
+    }
+
+    @Override
+    public int hashCode() {
+	return super.hashCode();
+	//TODO: compute hash. Choose algorithm base on Point.hashImpl
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+	if (this == obj)
+	    return true;
+	if (!super.equals(obj))
+	    return false;
+	if (!(obj instanceof ColorPoint))
+	    return false;
+	ColorPoint other = (ColorPoint) obj;
+	if (!other.canEqual(this)) {
+	    return false;
+	}
+	return Objects.equals(color, other.color);
+    }
+
+    @Override
+    public boolean canEqual(Point p) {
+	return p instanceof ColorPoint;
+    }
+}
diff --git a/src/main/java/cz/vsb/fei/java2/lab04/points/Point.java b/src/main/java/cz/vsb/fei/java2/lab04/points/Point.java
new file mode 100644
index 0000000..ee382c7
--- /dev/null
+++ b/src/main/java/cz/vsb/fei/java2/lab04/points/Point.java
@@ -0,0 +1,88 @@
+package cz.vsb.fei.java2.lab04.points;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import java.util.Random;
+
+import javafx.scene.paint.Color;
+
+public class Point {
+
+    private static final List<Color> COLORS = Collections.unmodifiableList(Arrays.asList(Color.RED, Color.BLUE, Color.YELLOW, Color.BLACK,
+	    Color.ORANGE, Color.PINK, Color.PURPLE));
+
+    public static final Random RANDOM = new Random();
+    
+    protected static HashImpl hashImpl = HashImpl.SAME;
+    
+    public static void setHashImplTo(HashImpl hashImpl) {
+	Point.hashImpl = hashImpl;
+    }
+    public static HashImpl getHashImpl() {
+	return hashImpl;
+    }
+
+    public static Point generateInRange(double minX, double maxX, double minY, double maxY) {
+	throw new UnsupportedOperationException("Method generateInRange not implemented yet!");
+	//TODO: Generate random point with given constraints. Randomly choose to generate point or color point.
+    }
+
+    public static Point generateInRadius(Point center, double radius) {
+	throw new UnsupportedOperationException("Method generateInRadius not implemented yet!");
+	//TODO: Generate random point with given radius from center. Randomly choose to generate point or color point.   
+    }
+
+    private double x;
+    private double y;
+
+
+    public Point(double x, double y) {
+	this.x = x;
+	this.y = y;
+    }
+
+    public Point createCopy() {
+	return new Point(x, y);
+    }
+
+    public double getX() {
+	return x;
+    }
+
+    public double getY() {
+	return y;
+    }
+
+    protected Integer hashCode = null;
+
+    @Override
+    public int hashCode() {
+	return super.hashCode();
+	//TODO: compute hash. Choose algorithm base on hashImpl
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+	if (this == obj)
+	    return true;
+	if (obj == null)
+	    return false;
+	if (!(obj instanceof Point))
+	    return false;
+	Point other = (Point) obj;
+	if (!other.canEqual(this)) {
+	    return false;
+	}
+	return Double.doubleToLongBits(x) == Double.doubleToLongBits(other.x)
+		&& Double.doubleToLongBits(y) == Double.doubleToLongBits(other.y);
+    }
+
+    public boolean canEqual(Point p) {
+	return p instanceof Point;
+    }
+
+    public enum HashImpl {
+	SAME, FULL_RANDOM, RANDOM, STANDARD;
+    }
+}
\ No newline at end of file
diff --git a/src/main/java/module-info.java b/src/main/java/module-info.java
index c8f3b6f..edaaf74 100644
--- a/src/main/java/module-info.java
+++ b/src/main/java/module-info.java
@@ -1,8 +1,9 @@
 module cz.vsb.fei.java2.lab04 {
     requires transitive javafx.controls;
     requires javafx.fxml;
-	requires lombok;
-	requires org.apache.logging.log4j;
-    opens cz.vsb.fei.java2.lab04 to javafx.fxml;
-    exports cz.vsb.fei.java2.lab04;
+    requires static lombok;
+    requires org.apache.logging.log4j;
+
+    opens cz.vsb.fei.java2.lab04.gui to javafx.fxml,javafx.graphics;
+    opens cz.vsb.fei.java2.lab04.points to javafx.base;
 }
\ No newline at end of file
diff --git a/src/main/resources/cz/vsb/fei/java2/lab04/AppWindow.fxml b/src/main/resources/cz/vsb/fei/java2/lab04/gui/AppWindow.fxml
similarity index 77%
rename from src/main/resources/cz/vsb/fei/java2/lab04/AppWindow.fxml
rename to src/main/resources/cz/vsb/fei/java2/lab04/gui/AppWindow.fxml
index edc5e24..953051b 100644
--- a/src/main/resources/cz/vsb/fei/java2/lab04/AppWindow.fxml
+++ b/src/main/resources/cz/vsb/fei/java2/lab04/gui/AppWindow.fxml
@@ -33,11 +33,6 @@
 -->
 
 <?import javafx.geometry.Insets?>
-<?import javafx.scene.Cursor?>
-<?import javafx.scene.canvas.Canvas?>
-<?import javafx.scene.chart.BarChart?>
-<?import javafx.scene.chart.CategoryAxis?>
-<?import javafx.scene.chart.NumberAxis?>
 <?import javafx.scene.control.Button?>
 <?import javafx.scene.control.Tab?>
 <?import javafx.scene.control.TabPane?>
@@ -45,9 +40,9 @@
 <?import javafx.scene.control.TableView?>
 <?import javafx.scene.layout.BorderPane?>
 <?import javafx.scene.layout.HBox?>
+<?import javafx.scene.layout.VBox?>
 
-
-<TabPane xmlns="http://javafx.com/javafx/21" xmlns:fx="http://javafx.com/fxml/1" fx:controller="cz.vsb.fei.java2.lab04.AppController">
+<TabPane prefHeight="522.0" prefWidth="715.0" xmlns="http://javafx.com/javafx/21" xmlns:fx="http://javafx.com/fxml/1" fx:controller="cz.vsb.fei.java2.lab04.gui.AppController">
    <tabs>
       <Tab text="Points">
          <content>
@@ -70,13 +65,6 @@
                            </HBox.margin>
                         </TableView>
                         <BorderPane fx:id="pane" prefHeight="200.0" prefWidth="200.0" HBox.hgrow="ALWAYS">
-                           <center>
-                              <Canvas fx:id="canvas" height="163.0" width="174.0" BorderPane.alignment="CENTER">
-                                 <cursor>
-                                    <Cursor fx:constant="CROSSHAIR" />
-                                 </cursor>
-                              </Canvas>
-                           </center>
                            <opaqueInsets>
                               <Insets />
                            </opaqueInsets>
@@ -97,6 +85,7 @@
                                     <Insets bottom="10.0" left="10.0" right="10.0" top="10.0" />
                                  </HBox.margin>
                               </Button>
+                              <Button mnemonicParsing="false" onAction="#generateInRadiusPressed" text="Generate in radius" />
                               <Button mnemonicParsing="false" onAction="#clearPressed" text="Clear">
                                  <HBox.margin>
                                     <Insets bottom="10.0" left="10.0" right="10.0" top="10.0" />
@@ -116,23 +105,33 @@
                <top>
                   <BorderPane BorderPane.alignment="CENTER">
                      <center>
-                        <Button fx:id="mesure" mnemonicParsing="false" onAction="#measure" text="Mesure">
+                        <HBox>
                            <BorderPane.margin>
                               <Insets bottom="10.0" left="10.0" right="10.0" top="10.0" />
                            </BorderPane.margin>
-                        </Button>
+                           <children>
+                              <Button fx:id="measure1" mnemonicParsing="false" onAction="#measure1000" text="Mesure to 1 000">
+                                 <HBox.margin>
+                                    <Insets bottom="5.0" left="5.0" right="5.0" top="5.0" />
+                                 </HBox.margin>
+                              </Button>
+                              <Button fx:id="mesure2" mnemonicParsing="false" onAction="#measure10000" text="Mesure to 10 000">
+                                 <HBox.margin>
+                                    <Insets bottom="5.0" left="5.0" right="5.0" top="5.0" />
+                                 </HBox.margin>
+                              </Button>
+                              <Button fx:id="mesure3" mnemonicParsing="false" onAction="#measure100000" text="Mesure to 100 000">
+                                 <HBox.margin>
+                                    <Insets bottom="5.0" left="5.0" right="5.0" top="5.0" />
+                                 </HBox.margin>
+                              </Button>
+                           </children>
+                        </HBox>
                      </center>
                   </BorderPane>
                </top>
                <center>
-                  <BarChart fx:id="chart" BorderPane.alignment="CENTER">
-                    <xAxis>
-                      <CategoryAxis side="BOTTOM" />
-                    </xAxis>
-                    <yAxis>
-                      <NumberAxis side="LEFT" />
-                    </yAxis>
-                  </BarChart>
+                  <VBox fx:id="chartBox" BorderPane.alignment="CENTER" />
                </center>
             </BorderPane>
         </content>
diff --git a/src/main/resources/cz/vsb/fei/java2/lab04/application.css b/src/main/resources/cz/vsb/fei/java2/lab04/gui/application.css
similarity index 100%
rename from src/main/resources/cz/vsb/fei/java2/lab04/application.css
rename to src/main/resources/cz/vsb/fei/java2/lab04/gui/application.css
-- 
GitLab