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); } }