package aima.gui.fx.views; import java.util.ArrayList; import java.util.List; import java.util.Objects; import aima.core.agent.Agent; import aima.core.agent.Environment; import aima.core.environment.map.Map; import aima.core.environment.map.MapEnvironment; import aima.core.util.math.geom.shapes.Point2D; import javafx.scene.layout.Pane; import javafx.scene.layout.StackPane; import javafx.scene.paint.Color; import javafx.scene.shape.Circle; import javafx.scene.shape.Line; import javafx.scene.shape.Shape; import javafx.scene.text.Font; import javafx.scene.text.Text; /** * Environment view controller class which is specialized for map environments. * It adds a map environment state view to the text-based view of the * {@link SimpleEnvironmentViewCtrl}. * * @author Ruediger Lunde */ public class MapEnvironmentViewCtrl extends SimpleEnvironmentViewCtrl { protected Pane envStateView; protected MapEnvironment env; protected String goal; protected List<String> track; public MapEnvironmentViewCtrl(StackPane viewRoot) { super(viewRoot); envStateView = new Pane(); splitPane.getItems().add(0, envStateView); splitPane.setDividerPosition(0, 0.7); splitPane.setStyle("-fx-background-color: white"); envStateView.setMinWidth(0.0); envStateView.widthProperty().addListener((obs, o, n) -> update()); envStateView.heightProperty().addListener((obs, o, n) -> update()); track = new ArrayList<String>(); } public void setGoal(String goal) { this.goal = goal; } @Override public void initialize(Environment env) { if (env instanceof MapEnvironment) this.env = (MapEnvironment) env; track.clear(); super.initialize(env); } @Override protected void updateEnvStateView(Environment env) { update(); } protected void update() { envStateView.getChildren().clear(); if (env != null) { double scale = adjustTransform(); Map map = env.getMap(); // print connections for (String loc1 : map.getLocations()) { Point2D pt1 = map.getPosition(loc1); for (String loc2 : map.getPossibleNextLocations(loc1)) { Point2D pt2 = map.getPosition(loc2); Shape line = new Line(pt1.getX(), pt1.getY(), pt2.getX(), pt2.getY()); line.setStroke(Color.LIGHTGRAY); envStateView.getChildren().add(line); } } // print track of first agent if (!env.getAgents().isEmpty()) { String aLoc = env.getAgentLocation(env.getAgents().get(0)); if (track.isEmpty() || !Objects.equals(track.get(track.size() - 1), aLoc)) track.add(aLoc); for (int i = 1; i < track.size(); i++) { Point2D pt1 = map.getPosition(track.get(i - 1)); Point2D pt2 = map.getPosition(track.get(i)); Shape line = new Line(pt1.getX(), pt1.getY(), pt2.getX(), pt2.getY()); line.setStroke(Color.RED); line.setStrokeWidth(2); envStateView.getChildren().add(line); } } // print locations for (String loc : map.getLocations()) { Point2D point = map.getPosition(loc); Text text = new Text(point.getX() + 10 / scale, point.getY(), loc); text.setFont(new Font(12.0 / scale)); envStateView.getChildren().add(text); envStateView.getChildren().add(new Circle(point.getX(), point.getY(), 2 / scale)); } // print agent locations for (Agent agent : env.getAgents()) { String loc = env.getAgentLocation(agent); if (loc != null) { Point2D pt = map.getPosition(loc); envStateView.getChildren().add(new Circle(pt.getX(), pt.getY(), 8 / scale, Color.RED)); } } // print goal if (goal != null) { Point2D pt = map.getPosition(goal); envStateView.getChildren().add(new Circle(pt.getX(), pt.getY(), 6 / scale, Color.GREEN)); } } } /** * Computes transforms (translations and scaling) and applies them to the * environment state view. Those transforms map location positions in the * map to screen positions in the viewer pane. * @return The scale value. */ private double adjustTransform() { double xMin = Double.POSITIVE_INFINITY; double xMax = Double.NEGATIVE_INFINITY; double yMin = Double.POSITIVE_INFINITY; double yMax = Double.NEGATIVE_INFINITY; for (String loc : env.getMap().getLocations()) { Point2D point = env.getMap().getPosition(loc); xMin = Math.min(xMin, point.getX()); xMax = Math.max(xMax, point.getX()); yMin = Math.min(yMin, point.getY()); yMax = Math.max(yMax, point.getY()); } double scale = Math.min((envStateView.getWidth() - 150) / (xMax - xMin), (envStateView.getHeight() - 60) / (yMax - yMin)); envStateView.setTranslateX((scale * (envStateView.getWidth() - xMin - xMax) / 2.0 - 30)); envStateView.setTranslateY((scale * (envStateView.getHeight() - yMin - yMax) / 2.0 - 10)); envStateView.setScaleX(scale); envStateView.setScaleY(scale); return scale; } }