package aima.gui.fx.views;
import java.util.Optional;
import java.util.function.Function;
import javafx.scene.canvas.Canvas;
import javafx.scene.canvas.GraphicsContext;
import javafx.scene.paint.Color;
import javafx.scene.paint.Paint;
/**
* Controller class which provides functionality for using a canvas as function
* plotter.
*
* @author Ruediger Lunde
*/
public class FunctionPlotterCtrl {
private Canvas canvas;
private Optional<Function<Double, Double>> function = Optional.empty();
private double minX;
private double maxX = 1;
private double minY;
private double maxY = 1;
public FunctionPlotterCtrl(Canvas canvas) {
this.canvas = canvas;
canvas.widthProperty().addListener((obs, o, n) -> update());
canvas.heightProperty().addListener((obs, o, n) -> update());
}
public Optional<Function<Double, Double>> getFunction() {
return function;
}
public void setFunction(Function<Double, Double> function) {
this.function = Optional.of(function);
update();
}
public void setLimits(double minX, double maxX, double minY, double maxY) {
this.minX = minX;
this.minY = minY;
this.maxX = maxX;
this.maxY = maxY;
}
public void update() {
GraphicsContext gc = canvas.getGraphicsContext2D();
gc.clearRect(0, 0, canvas.getWidth(), canvas.getHeight());
gc.setStroke(Color.GRAY);
gc.strokeLine(0.01 * canvas.getWidth(), yToScreen(0), canvas.getWidth() * 0.99, yToScreen(0));
gc.strokeLine(xToScreen(0), 0.01 * canvas.getHeight(), xToScreen(0), 0.99 * canvas.getHeight());
gc.strokeLine(xToScreen(1), yToScreen(0) - 5, xToScreen(1), yToScreen(0) + 5);
gc.strokeLine(xToScreen(0) - 5, yToScreen(1), xToScreen(0) + 5, yToScreen(1));
if (function.isPresent()) {
gc.setStroke(Color.BLACK);
double lastVal = function.get().apply(minX);
for (int i = 1; i < canvas.getWidth(); i++) {
double newVal = function.get().apply(screenToX(i));
gc.strokeLine(i - 1, yToScreen(lastVal), i, yToScreen(newVal));
lastVal = newVal;
}
}
}
public void setMarker(double x, Optional<Paint> fill) {
if (function.isPresent()) {
double y = function.get().apply(x);
GraphicsContext gc = canvas.getGraphicsContext2D();
gc.setStroke(Color.RED);
if (fill.isPresent()) {
gc.setFill(fill.get());
gc.fillOval(xToScreen(x) - 10, yToScreen(y) - 10, 20, 20);
} else
gc.strokeOval(xToScreen(x) - 10, yToScreen(y) - 10, 20, 20);
}
}
/* Returns pixel width. */
public double getDeltaX() {
return (maxX - minX) / canvas.getWidth();
}
private double yToScreen(double y) {
return (1.1 - (y - minY) / (maxY - minY)) * canvas.getHeight() * 0.8;
}
private double screenToX(double xScreen) {
return xScreen / canvas.getWidth() * (maxX - minX) + minX;
}
private double xToScreen(double x) {
return (x - minX) * canvas.getWidth() / (maxX - minX);
}
}