From 71b9243709802ffab500006a67cc2385f6e42cde Mon Sep 17 00:00:00 2001 From: dorianreineccius Date: Tue, 14 Jan 2020 00:11:58 +0100 Subject: [PATCH 01/18] WIP --- .../com/treasure/hunt/game/GameEngine.java | 8 +- .../com/treasure/hunt/game/GameManager.java | 39 +++-- .../hunt/jts/awt/AdvancedShapeWriter.java | 7 +- .../com/treasure/hunt/jts/geom/Circle.java | 10 +- .../hunt/jts/geom/CircleHighlighter.java | 31 ++++ .../jts/geom/RectangleFixedHighlighter.java | 52 ++++++ .../geom/RectangleVariableHighlighter.java | 38 +++++ .../hunt/strategy/geom/GeometryItem.java | 8 +- .../impl/MaxAreaAngularHintStrategy.java | 4 +- .../hider/impl/RandomAngleHintHider.java | 8 +- .../searcher/impl/NaiveAngleSearcher.java | 14 +- .../treasure/hunt/utils/EventBusUtils.java | 2 + .../treasure/hunt/view/CanvasController.java | 154 +++++++++++++++++- .../treasure/hunt/view/MainController.java | 4 +- src/main/resources/layout/canvas.fxml | 3 +- src/main/resources/layout/scaling.fxml | 10 +- 16 files changed, 345 insertions(+), 47 deletions(-) create mode 100644 src/main/java/com/treasure/hunt/jts/geom/CircleHighlighter.java create mode 100644 src/main/java/com/treasure/hunt/jts/geom/RectangleFixedHighlighter.java create mode 100644 src/main/java/com/treasure/hunt/jts/geom/RectangleVariableHighlighter.java diff --git a/src/main/java/com/treasure/hunt/game/GameEngine.java b/src/main/java/com/treasure/hunt/game/GameEngine.java index 70173767..7cff2725 100644 --- a/src/main/java/com/treasure/hunt/game/GameEngine.java +++ b/src/main/java/com/treasure/hunt/game/GameEngine.java @@ -12,6 +12,7 @@ import com.treasure.hunt.utils.JTSUtils; import com.treasure.hunt.utils.Requires; import lombok.Getter; +import lombok.Setter; import org.locationtech.jts.geom.Coordinate; import org.locationtech.jts.geom.LineSegment; import org.locationtech.jts.geom.Point; @@ -35,6 +36,7 @@ public class GameEngine { * Tells, whether the game is done or not. */ @Getter + @Setter protected boolean finished = false; /** * Tells, whether a first move is happened in the game yet, or not. @@ -113,12 +115,12 @@ public Move init() { treasurePos = hider.getTreasureLocation(); if (treasurePos == null) { - throw new IllegalArgumentException("hider: " + hider + " gave a treasure position which is null."); + throw new IllegalArgumentException(hider + " gave a treasurePosition which is null."); } // Check, whether treasure spawns in range of searcher if (located(Collections.singletonList(new GeometryItem<>(searcherPos, GeometryType.WAY_POINT)), treasurePos)) { - finished = true; + setFinished(true); } return new Move( @@ -143,7 +145,7 @@ public Move move() { searcherMove(); if (located(lastMovement.getPoints(), treasurePos)) { - finished = true; + setFinished(true); return new Move(null, lastMovement, treasurePos); } else { hiderMove(); diff --git a/src/main/java/com/treasure/hunt/game/GameManager.java b/src/main/java/com/treasure/hunt/game/GameManager.java index 58c5016d..62186738 100644 --- a/src/main/java/com/treasure/hunt/game/GameManager.java +++ b/src/main/java/com/treasure/hunt/game/GameManager.java @@ -10,6 +10,7 @@ import com.treasure.hunt.strategy.geom.GeometryType; import com.treasure.hunt.strategy.hider.Hider; import com.treasure.hunt.strategy.searcher.Searcher; +import com.treasure.hunt.utils.JTSUtils; import javafx.application.Platform; import javafx.beans.binding.Bindings; import javafx.beans.binding.BooleanBinding; @@ -21,6 +22,7 @@ import lombok.Getter; import lombok.extern.slf4j.Slf4j; import org.locationtech.jts.geom.Coordinate; +import org.locationtech.jts.geom.Geometry; import org.locationtech.jts.geom.Point; import java.lang.reflect.InvocationTargetException; @@ -45,7 +47,6 @@ public class GameManager implements KryoSerializable { * He executes {@link GameManager#move(int)} in a given interval. */ private Thread beatThread; - @Getter private volatile BooleanProperty beatThreadRunning = new SimpleBooleanProperty(false); /** @@ -76,7 +77,6 @@ public class GameManager implements KryoSerializable { @Getter private ObjectBinding> statistics; - /** * @param searcherClass (Sub-)class of {@link Searcher} * @param hiderClass (Sub-)class of {@link Hider} @@ -178,7 +178,7 @@ public void stopBeat() { } /** - * @return whether the game of the {@link GameEngine} is finished or not. + * Works only for stepSim ≤ stepView  */ public boolean isGameFinished() { return gameEngine.isFinished(); @@ -263,13 +263,6 @@ public void beat(ReadOnlyObjectProperty delay) { beatThread.start(); } - /** - * @return {@code true}, if the shown step is the first one. {@code false}, otherwise. - */ - public boolean isFirstStepShown() { - return stepBackwardImpossibleBinding.getValue(); - } - @Override public void write(Kryo kryo, Output output) { kryo.writeObject(output, gameEngine); @@ -291,4 +284,30 @@ public void read(Kryo kryo, Input input) { finishedProperty = new SimpleBooleanProperty(input.readBoolean()); setBindings(); } + + /** + * @param coordinate the point on the canvas, we want to get the closest {@link GeometryType} to. + * @param distance the maximum distance to a potential {@link GeometryItem}. + * @return a sorted list, containing the nearest {@link GeometryItem}'s to {@code coordinate}, with a maximum distance of {@code distance}. + */ + public List pickGeometryItem(Coordinate coordinate, double distance) { + List geometryItems = getGeometryItems(true); + if (geometryItems.size() < 1) { + return new ArrayList<>(); + } + + Point mouse = JTSUtils.GEOMETRY_FACTORY.createPoint(coordinate); + + geometryItems = geometryItems.stream() + .filter(geometryItem -> + mouse.distance((Geometry) geometryItem.getObject()) <= distance + ) + .sorted((geometryItem, secondGeometryItem) -> + (int) (mouse.distance((Geometry) geometryItem.getObject()) - + mouse.distance((Geometry) secondGeometryItem.getObject())) + ) + .collect(Collectors.toList()); + + return geometryItems; + } } diff --git a/src/main/java/com/treasure/hunt/jts/awt/AdvancedShapeWriter.java b/src/main/java/com/treasure/hunt/jts/awt/AdvancedShapeWriter.java index c658a5ee..5169b601 100644 --- a/src/main/java/com/treasure/hunt/jts/awt/AdvancedShapeWriter.java +++ b/src/main/java/com/treasure/hunt/jts/awt/AdvancedShapeWriter.java @@ -50,12 +50,7 @@ public Shape toShape(Object object) { if (object instanceof Shapeable) { return ((Shapeable) object).toShape(this); } - try { - return super.toShape((Geometry) object); - } catch (IllegalArgumentException e) { - log.debug("Could not render object to shape", e); - } - return null; + return super.toShape((Geometry) object); } /** diff --git a/src/main/java/com/treasure/hunt/jts/geom/Circle.java b/src/main/java/com/treasure/hunt/jts/geom/Circle.java index 04f2b9fd..05807b7f 100644 --- a/src/main/java/com/treasure/hunt/jts/geom/Circle.java +++ b/src/main/java/com/treasure/hunt/jts/geom/Circle.java @@ -16,7 +16,11 @@ public class Circle extends Polygon { /** * The radius of the circle. */ - double radius; + protected double radius; + /** + * The coordinate of this circle's center. + */ + protected Coordinate coordinate; /** * The constructor @@ -28,6 +32,10 @@ public class Circle extends Polygon { */ public Circle(Coordinate coordinate, double radius, int numOfPoints, GeometryFactory geometryFactory) { super(null, null, geometryFactory); + + this.radius = radius; + this.coordinate = coordinate; + GeometricShapeFactory geometricShapeFactory = new GeometricShapeFactory(geometryFactory); geometricShapeFactory.setNumPoints(numOfPoints); geometricShapeFactory.setCentre(coordinate); diff --git a/src/main/java/com/treasure/hunt/jts/geom/CircleHighlighter.java b/src/main/java/com/treasure/hunt/jts/geom/CircleHighlighter.java new file mode 100644 index 00000000..94218ed5 --- /dev/null +++ b/src/main/java/com/treasure/hunt/jts/geom/CircleHighlighter.java @@ -0,0 +1,31 @@ +package com.treasure.hunt.jts.geom; + +import com.treasure.hunt.jts.awt.AdvancedShapeWriter; +import com.treasure.hunt.jts.awt.Shapeable; +import org.locationtech.jts.geom.Coordinate; +import org.locationtech.jts.geom.GeometryFactory; + +import java.awt.*; +import java.awt.geom.Ellipse2D; + +/** + * Non-scaling {@link Circle}, surrounding points to highlight them. + * + * @author dorianreineccius + */ +public class CircleHighlighter extends Circle implements Shapeable { + public CircleHighlighter(Coordinate coordinate, double radius, int numOfPoints, GeometryFactory geometryFactory) { + super(coordinate, radius, numOfPoints, geometryFactory); + } + + @Override + public Shape toShape(AdvancedShapeWriter shapeWriter) { + Point dest = new Point(); + + shapeWriter.transform(coordinate, dest); + + Shape circle = new Ellipse2D.Double(dest.x - radius, dest.y - radius, radius * 2, radius * 2); + + return circle; + } +} diff --git a/src/main/java/com/treasure/hunt/jts/geom/RectangleFixedHighlighter.java b/src/main/java/com/treasure/hunt/jts/geom/RectangleFixedHighlighter.java new file mode 100644 index 00000000..0ec888e0 --- /dev/null +++ b/src/main/java/com/treasure/hunt/jts/geom/RectangleFixedHighlighter.java @@ -0,0 +1,52 @@ +package com.treasure.hunt.jts.geom; + +import com.treasure.hunt.jts.awt.AdvancedShapeWriter; +import com.treasure.hunt.jts.awt.Shapeable; +import org.locationtech.jts.geom.Coordinate; +import org.locationtech.jts.geom.GeometryFactory; + +import java.awt.*; + +/** + * @author dorianreineccius + */ +public class RectangleFixedHighlighter extends RectangleVariableHighlighter implements Shapeable { + /** + * Coordinate of the upper left corner. + */ + public final Coordinate coordinate; + /** + * Width of the rectangle. + */ + public final double width; + /** + * Height of the rectangle. + */ + public final double height; + + public RectangleFixedHighlighter(Coordinate coordinate, double width, double height, GeometryFactory geometryFactory) { + super(coordinate, width, height, geometryFactory); + Coordinate[] coords = new Coordinate[]{ + coordinate, + new Coordinate(coordinate.x + width, coordinate.y), + new Coordinate(coordinate.x + width, coordinate.y - height), + new Coordinate(coordinate.x, coordinate.y - height), + coordinate + }; + this.shell = geometryFactory.createLinearRing(coords); + this.coordinate = coordinate; + this.width = width; + this.height = height; + } + + @Override + public Shape toShape(AdvancedShapeWriter shapeWriter) { + Point dest = new Point(); + + shapeWriter.transform(coordinate, dest); + + Shape rectangle = new Rectangle.Double((dest.x - width / 2), (dest.y - height / 2), width, height); + + return rectangle; + } +} diff --git a/src/main/java/com/treasure/hunt/jts/geom/RectangleVariableHighlighter.java b/src/main/java/com/treasure/hunt/jts/geom/RectangleVariableHighlighter.java new file mode 100644 index 00000000..441b791d --- /dev/null +++ b/src/main/java/com/treasure/hunt/jts/geom/RectangleVariableHighlighter.java @@ -0,0 +1,38 @@ +package com.treasure.hunt.jts.geom; + +import org.locationtech.jts.geom.Coordinate; +import org.locationtech.jts.geom.GeometryFactory; +import org.locationtech.jts.geom.Polygon; + +/** + * @author dorianreineccius + */ +public class RectangleVariableHighlighter extends Polygon { + /** + * Coordinate of the upper left corner. + */ + public final Coordinate coordinate; + /** + * Width of the rectangle. + */ + public final double width; + /** + * Height of the rectangle. + */ + public final double height; + + public RectangleVariableHighlighter(Coordinate coordinate, double width, double height, GeometryFactory geometryFactory) { + super(null, null, geometryFactory); + Coordinate[] coords = new Coordinate[]{ + coordinate, + new Coordinate(coordinate.x + width, coordinate.y), + new Coordinate(coordinate.x + width, coordinate.y - height), + new Coordinate(coordinate.x, coordinate.y - height), + coordinate + }; + this.shell = geometryFactory.createLinearRing(coords); + this.coordinate = coordinate; + this.width = width; + this.height = height; + } +} diff --git a/src/main/java/com/treasure/hunt/strategy/geom/GeometryItem.java b/src/main/java/com/treasure/hunt/strategy/geom/GeometryItem.java index ac2bbd13..ccd661e0 100644 --- a/src/main/java/com/treasure/hunt/strategy/geom/GeometryItem.java +++ b/src/main/java/com/treasure/hunt/strategy/geom/GeometryItem.java @@ -4,6 +4,7 @@ import lombok.Getter; import lombok.NonNull; import org.jfree.fx.FXGraphics2D; +import org.locationtech.jts.geom.Geometry; import java.awt.*; @@ -13,7 +14,6 @@ * @author jotoh, dorianreineccius * @see GeometryType for further information about how to classifiy a geometry item. */ - @Getter public class GeometryItem { @NonNull @@ -34,6 +34,12 @@ public GeometryItem(T object, GeometryType geometryType) { this(object, geometryType, GeometryStyle.getDefaults(geometryType)); } + /** + * This draws {@code this} GeometryItem on the {@code graphics2D}. + * + * @param graphics2D the {@link Graphics2D} to draw {@code this} on. + * @param shapeWriter the {@link org.locationtech.jts.awt.ShapeWriter} converting the {@link Geometry} of {@code this} to a {@link Shape}. + */ public void draw(FXGraphics2D graphics2D, AdvancedShapeWriter shapeWriter) { if (!geometryStyle.isVisible()) { return; diff --git a/src/main/java/com/treasure/hunt/strategy/hider/impl/MaxAreaAngularHintStrategy.java b/src/main/java/com/treasure/hunt/strategy/hider/impl/MaxAreaAngularHintStrategy.java index e5eba5a1..560acef9 100644 --- a/src/main/java/com/treasure/hunt/strategy/hider/impl/MaxAreaAngularHintStrategy.java +++ b/src/main/java/com/treasure/hunt/strategy/hider/impl/MaxAreaAngularHintStrategy.java @@ -8,6 +8,7 @@ import com.treasure.hunt.strategy.geom.GeometryType; import com.treasure.hunt.strategy.hint.impl.AngleHint; import com.treasure.hunt.strategy.searcher.Movement; +import com.treasure.hunt.utils.JTSUtils; import lombok.Getter; import lombok.Setter; import lombok.extern.slf4j.Slf4j; @@ -37,7 +38,7 @@ public class MaxAreaAngularHintStrategy implements HideAndSeekHider { private Point startingPoint; private Point currentPlayersPosition; private List givenHints; - private GeometryFactory gf; + private GeometryFactory gf = JTSUtils.GEOMETRY_FACTORY; private double walkedPathLength; @Getter @@ -64,7 +65,6 @@ public class MaxAreaAngularHintStrategy implements HideAndSeekHider { public MaxAreaAngularHintStrategy() { log.info("MaxAreaAngularHintStrategy init"); - gf = new GeometryFactory(); //TODO swap out with externally defined default factory for project givenHints = new ArrayList<>(); startingPoint = gf.createPoint(new Coordinate(0, 0)); currentPlayersPosition = startingPoint; diff --git a/src/main/java/com/treasure/hunt/strategy/hider/impl/RandomAngleHintHider.java b/src/main/java/com/treasure/hunt/strategy/hider/impl/RandomAngleHintHider.java index 5c8327da..7935a2d2 100644 --- a/src/main/java/com/treasure/hunt/strategy/hider/impl/RandomAngleHintHider.java +++ b/src/main/java/com/treasure/hunt/strategy/hider/impl/RandomAngleHintHider.java @@ -13,14 +13,14 @@ * @author dorianreineccius */ public class RandomAngleHintHider implements Hider { - private Point treasurePos = JTSUtils.createPoint(Math.random() * 100, Math.random() * 100); + private Point treasurePosition = JTSUtils.createPoint(Math.random() * 100, Math.random() * 100); /** - * @return {@link Point} containing treasure location of [0,100)x[0x100) + * @return {@link RandomAngleHintHider#treasurePosition}. */ @Override public Point getTreasureLocation() { - return treasurePos; + return treasurePosition; } @Override @@ -32,7 +32,7 @@ public AngleHint move(Movement movement) { Coordinate searcherPos = movement.getEndPoint().getCoordinate(); return new AngleHint( - JTSUtils.validRandomAngle(searcherPos, treasurePos.getCoordinate(), 2 * Math.PI) + JTSUtils.validRandomAngle(searcherPos, treasurePosition.getCoordinate(), 2 * Math.PI) ); } } diff --git a/src/main/java/com/treasure/hunt/strategy/searcher/impl/NaiveAngleSearcher.java b/src/main/java/com/treasure/hunt/strategy/searcher/impl/NaiveAngleSearcher.java index edbfc9d1..256527ea 100644 --- a/src/main/java/com/treasure/hunt/strategy/searcher/impl/NaiveAngleSearcher.java +++ b/src/main/java/com/treasure/hunt/strategy/searcher/impl/NaiveAngleSearcher.java @@ -43,20 +43,18 @@ public Movement move() { @Override public Movement move(AngleHint angleHint) { Coordinate c1 = JTSUtils.middleOfAngleHint(angleHint); - double x = c1.x; - double y = c1.y; - Movement m = new Movement(startPosition); - startPosition = JTSUtils.createPoint(x, y); - m.addWayPoint(startPosition); + Movement movement = new Movement(startPosition); + startPosition = JTSUtils.GEOMETRY_FACTORY.createPoint(c1); + movement.addWayPoint(startPosition); // Add to additionalItems - Coordinate[] a2 = {angleHint.getGeometryAngle().getCenter(), new Coordinate(x, y)}; - m.addAdditionalItem( + Coordinate[] a2 = {angleHint.getGeometryAngle().getCenter(), c1}; + movement.addAdditionalItem( new GeometryItem(new LineString( new CoordinateArraySequence(a2), JTSUtils.GEOMETRY_FACTORY ), GeometryType.SEARCHER_MOVEMENT)); - return m; + return movement; } } diff --git a/src/main/java/com/treasure/hunt/utils/EventBusUtils.java b/src/main/java/com/treasure/hunt/utils/EventBusUtils.java index 1c2c86a8..3f2ab178 100644 --- a/src/main/java/com/treasure/hunt/utils/EventBusUtils.java +++ b/src/main/java/com/treasure/hunt/utils/EventBusUtils.java @@ -3,10 +3,12 @@ import com.pploder.events.Event; import com.pploder.events.SimpleEvent; import com.treasure.hunt.game.GameManager; +import com.treasure.hunt.strategy.geom.GeometryItem; /** * @author Trostorff */ public class EventBusUtils { public static final Event GAME_MANAGER_LOADED_EVENT = new SimpleEvent<>(); + public static final Event SELECTED_GEOMETRY_ITEMS_EVENT = new SimpleEvent(); } diff --git a/src/main/java/com/treasure/hunt/view/CanvasController.java b/src/main/java/com/treasure/hunt/view/CanvasController.java index 06a7e234..6cd90551 100644 --- a/src/main/java/com/treasure/hunt/view/CanvasController.java +++ b/src/main/java/com/treasure/hunt/view/CanvasController.java @@ -3,6 +3,13 @@ import com.treasure.hunt.game.GameManager; import com.treasure.hunt.jts.awt.AdvancedShapeWriter; import com.treasure.hunt.jts.awt.PointTransformation; +import com.treasure.hunt.jts.geom.CircleHighlighter; +import com.treasure.hunt.jts.geom.RectangleVariableHighlighter; +import com.treasure.hunt.strategy.geom.GeometryItem; +import com.treasure.hunt.strategy.geom.GeometryStyle; +import com.treasure.hunt.strategy.geom.GeometryType; +import com.treasure.hunt.utils.EventBusUtils; +import com.treasure.hunt.utils.JTSUtils; import javafx.application.Platform; import javafx.beans.property.ObjectProperty; import javafx.scene.canvas.Canvas; @@ -10,13 +17,37 @@ import javafx.scene.input.ScrollEvent; import javafx.scene.layout.Pane; import lombok.Getter; +import lombok.extern.slf4j.Slf4j; import org.jfree.fx.FXGraphics2D; +import org.locationtech.jts.geom.Coordinate; +import org.locationtech.jts.geom.Geometry; +import org.locationtech.jts.geom.LineString; +import org.locationtech.jts.geom.Point; import org.locationtech.jts.math.Vector2D; +import java.awt.*; +import java.util.ArrayList; +import java.util.List; + /** * @author axel12, dorianreineccius */ +@Slf4j public class CanvasController { + /** + * The maximum distance on canvas between the mouse and a {@link GeometryItem}, + * in which the mouse can select a {@link GeometryItem} on click. + */ + public static final double MOUSE_RECOGNIZE_DISTANCE = 5; + private Coordinate lastMouseClick; + private GeometryItem highlighter; + private List geometryItemsList = new ArrayList<>(); + private int geometryItemsListIndex = 0; + /** + * Determines, whether the mouse was dragged. + */ + private boolean dragged = false; + @Getter public Canvas canvas; public Pane canvasPane; @@ -38,10 +69,58 @@ public void initialize() { transformation.getScaleProperty().addListener(invalidation -> drawShapes()); transformation.getOffsetProperty().addListener(invalidation -> drawShapes()); + + subscribeToGeometryItem(); } - public void makeCanvasResizable() { + /** + * Subscribes to {@link EventBusUtils#GAME_MANAGER_LOADED_EVENT} + * in order to handle its {@link GeometryItem}s. + */ + public void subscribeToGeometryItem() { + EventBusUtils.SELECTED_GEOMETRY_ITEMS_EVENT.addListener(geometryItem -> { + Platform.runLater(() -> { + log.trace("received: " + geometryItem); + if (geometryItem.getObject() instanceof Point) { + this.highlighter = new GeometryItem( + new CircleHighlighter(((Geometry) geometryItem.getObject()).getCoordinate(), + CanvasController.MOUSE_RECOGNIZE_DISTANCE, 64, JTSUtils.GEOMETRY_FACTORY), + GeometryType.STANDARD, + new GeometryStyle(true, Color.GREEN) + ); + } else if (geometryItem.getObject() instanceof LineString) { + double minX = ((Geometry) geometryItem.getObject()).getCoordinates()[0].x; + double maxY = ((Geometry) geometryItem.getObject()).getCoordinates()[0].y; + double maxX = ((Geometry) geometryItem.getObject()).getCoordinates()[0].x; + double minY = ((Geometry) geometryItem.getObject()).getCoordinates()[0].y; + for (Coordinate coordinate : ((Geometry) geometryItem.getObject()).getCoordinates()) { + if (coordinate.x < minX) { + minX = coordinate.x; + } + if (coordinate.x > maxX) { + maxX = coordinate.x; + } + if (coordinate.y < minY) { + minY = coordinate.y; + } + if (coordinate.y > minY) { + maxY = coordinate.y; + } + } + this.highlighter = new GeometryItem( + new RectangleVariableHighlighter( + new Coordinate(minX, maxY), + maxX - minX, maxY - minY, + JTSUtils.GEOMETRY_FACTORY), + GeometryType.STANDARD, + new GeometryStyle(true, Color.YELLOW)); + } + drawShapes(); + }); + }); + } + public void makeCanvasResizable() { canvas.widthProperty().addListener((observable, oldValue, newValue) -> { transformation.updateCanvasWidth((double) newValue); drawShapes(); @@ -56,7 +135,10 @@ public void makeCanvasResizable() { canvas.widthProperty().bind(canvasPane.widthProperty()); } - public void drawShapes() { + /** + * This method clears and draws all current {@link GeometryItem} given by the {@link GameManager} on the canvas. + */ + void drawShapes() { Platform.runLater(() -> { if (gameManager == null) { return; @@ -66,10 +148,16 @@ public void drawShapes() { gameManager.get().getGeometryItems(true).forEach(geometryItem -> geometryItem.draw(graphics2D, shapeWriter) ); + if (this.highlighter != null) { + this.highlighter.draw(graphics2D, shapeWriter); + } } }); } + /** + * This clears the {@link GeometryItem}'s from the canvas. + */ private void deleteShapes() { if (gameManager == null) { return; @@ -77,11 +165,68 @@ private void deleteShapes() { canvas.getGraphicsContext2D().clearRect(0, 0, canvas.getWidth(), canvas.getHeight()); } + /** + * Executed when the mouse was pressed and released. + * TODO To much game logic in here!!11 maybe wrap into GameManager + * Executing this will select a {@link GeometryItem} nearest to the mouse position, + * with a maximum distance of {@link CanvasController#MOUSE_RECOGNIZE_DISTANCE}. + * + * @param mouseEvent corresponding {@link MouseEvent} + */ public void onCanvasClicked(MouseEvent mouseEvent) { if (gameManager == null) { return; } offsetBackup = transformation.getOffsetProperty().get(); + + if (dragged) { + dragged = false; + return; + } + dragged = false; + + Vector2D mousePositionInGameContext = dragStart.subtract(offsetBackup); + mousePositionInGameContext = mousePositionInGameContext.divide(transformation.getScaleProperty().get()); + + if (lastMouseClick == null) { + lastMouseClick = new Coordinate(mousePositionInGameContext.getX(), mousePositionInGameContext.getY()); + + geometryItemsList = gameManager.get().pickGeometryItem( + new Coordinate(mousePositionInGameContext.getX(), -mousePositionInGameContext.getY()), + MOUSE_RECOGNIZE_DISTANCE / transformation.getScaleProperty().get()); + + EventBusUtils.SELECTED_GEOMETRY_ITEMS_EVENT.trigger(geometryItemsList.get(0)); + geometryItemsListIndex = 0; + } else { + if (lastMouseClick.getX() == mousePositionInGameContext.getX() && + lastMouseClick.getY() == mousePositionInGameContext.getY()) { + geometryItemsListIndex = (geometryItemsListIndex + 1) % geometryItemsList.size(); + EventBusUtils.SELECTED_GEOMETRY_ITEMS_EVENT.trigger(geometryItemsList.get(geometryItemsListIndex)); + log.trace("received: " + geometryItemsListIndex + "/" + geometryItemsList.size()); + } else { + geometryItemsList = gameManager.get().pickGeometryItem( + new Coordinate(mousePositionInGameContext.getX(), -mousePositionInGameContext.getY()), + MOUSE_RECOGNIZE_DISTANCE / transformation.getScaleProperty().get()); + EventBusUtils.SELECTED_GEOMETRY_ITEMS_EVENT.trigger(geometryItemsList.get(0)); + lastMouseClick = new Coordinate(mousePositionInGameContext.getX(), mousePositionInGameContext.getY()); + } + } + } + + /** + * This is executed, when the mouse is pressed + * and not actually released. + *

+ * It will set {@link CanvasController#offsetBackup} and {@link CanvasController#dragStart} + * relative to the mouse position. + * + * @param mouseEvent corresponding {@link MouseEvent} + */ + public void onCanvasPressed(MouseEvent mouseEvent) { + if (gameManager == null) { + return; + } + offsetBackup = transformation.getOffsetProperty().get(); dragStart = Vector2D.create(mouseEvent.getX(), mouseEvent.getY()); } @@ -94,9 +239,11 @@ public void onCanvasClicked(MouseEvent mouseEvent) { * @param mouseEvent corresponding {@link MouseEvent} */ public void onCanvasDragged(MouseEvent mouseEvent) { + dragged = true; if (gameManager == null) { return; } + Vector2D dragOffset = Vector2D.create(mouseEvent.getX(), mouseEvent.getY()).subtract(dragStart); transformation.setOffset(dragOffset.add(offsetBackup)); } @@ -118,7 +265,6 @@ public void setGameManager(ObjectProperty gameManager) { } this.gameManager.get().getViewIndex() .addListener(observable1 -> drawShapes()); - }); } -} +} \ No newline at end of file diff --git a/src/main/java/com/treasure/hunt/view/MainController.java b/src/main/java/com/treasure/hunt/view/MainController.java index 6a97bb29..1f0749de 100644 --- a/src/main/java/com/treasure/hunt/view/MainController.java +++ b/src/main/java/com/treasure/hunt/view/MainController.java @@ -92,10 +92,10 @@ public void initialize() { addToolbarStyleClasses(); bindWidgetBarVisibility(); addBindingsToGameManager(); - listenToGameMangerLoad(); + subscribeToGameMangerLoad(); } - private void listenToGameMangerLoad() { + private void subscribeToGameMangerLoad() { EventBusUtils.GAME_MANAGER_LOADED_EVENT.addListener(loadedGameManager -> { Platform.runLater(() -> { try { diff --git a/src/main/resources/layout/canvas.fxml b/src/main/resources/layout/canvas.fxml index d7aaebb9..74facf4b 100644 --- a/src/main/resources/layout/canvas.fxml +++ b/src/main/resources/layout/canvas.fxml @@ -10,7 +10,8 @@ id="gameCanvas" fx:id="canvas" onMouseDragged="#onCanvasDragged" - onMousePressed="#onCanvasClicked" + onMousePressed="#onCanvasPressed" + onMouseClicked="#onCanvasClicked" onScroll="#onCanvasZoom" /> diff --git a/src/main/resources/layout/scaling.fxml b/src/main/resources/layout/scaling.fxml index b58ae7b9..c756a628 100644 --- a/src/main/resources/layout/scaling.fxml +++ b/src/main/resources/layout/scaling.fxml @@ -7,9 +7,9 @@ - - - - - + + + + + From ba20d5cb4ace1058064c3eba8e527c5a4611da56 Mon Sep 17 00:00:00 2001 From: dorianreineccius Date: Tue, 14 Jan 2020 00:57:06 +0100 Subject: [PATCH 02/18] WIP --- .../hunt/strategy/geom/GeometryStyle.java | 5 +- .../hunt/strategy/geom/GeometryType.java | 7 +- .../treasure/hunt/view/CanvasController.java | 70 ++++++------------- 3 files changed, 30 insertions(+), 52 deletions(-) diff --git a/src/main/java/com/treasure/hunt/strategy/geom/GeometryStyle.java b/src/main/java/com/treasure/hunt/strategy/geom/GeometryStyle.java index cd4a5b4f..2a5e7c37 100644 --- a/src/main/java/com/treasure/hunt/strategy/geom/GeometryStyle.java +++ b/src/main/java/com/treasure/hunt/strategy/geom/GeometryStyle.java @@ -40,8 +40,11 @@ public static GeometryStyle getDefaults(GeometryType type) { return new GeometryStyle(true, new Color(0xFFD700)); case HINT_ANGLE: return new GeometryStyle(true, new Color(0x575757)); + case HIGHLIGHTER: + return new GeometryStyle(true, Color.GREEN); + default: + return new GeometryStyle(true, Color.lightGray); } - return new GeometryStyle(true, Color.lightGray); } public Stroke getStroke() { diff --git a/src/main/java/com/treasure/hunt/strategy/geom/GeometryType.java b/src/main/java/com/treasure/hunt/strategy/geom/GeometryType.java index e69e8417..ecb3bbb9 100644 --- a/src/main/java/com/treasure/hunt/strategy/geom/GeometryType.java +++ b/src/main/java/com/treasure/hunt/strategy/geom/GeometryType.java @@ -10,16 +10,13 @@ */ public enum GeometryType { // hints - FALSE_HINT(false, "False Hint"), + HINT_ANGLE(true, "angle hint", true), HINT_CENTER(false, "hint-center"), - HINT_RADIUS(false, "hint-center"), - TRUE_HINT(false, "True Hint"), // treasure/no-treasure (areas) TREASURE(true, "no treasure"), NO_TREASURE(false, "no treasure"), POSSIBLE_TREASURE(false, "possible treasure"), - HINT_ANGLE(true, "angle hint", true), // searcher movements WAY_POINT(true, "no treasure"), @@ -27,6 +24,8 @@ public enum GeometryType { BOUNDING_CIRCE(false, "bounding circle"), + HIGHLIGHTER(true, "highlighter"), + STANDARD(true, "") // TODO add more.. ; diff --git a/src/main/java/com/treasure/hunt/view/CanvasController.java b/src/main/java/com/treasure/hunt/view/CanvasController.java index 6cd90551..757e546b 100644 --- a/src/main/java/com/treasure/hunt/view/CanvasController.java +++ b/src/main/java/com/treasure/hunt/view/CanvasController.java @@ -6,7 +6,6 @@ import com.treasure.hunt.jts.geom.CircleHighlighter; import com.treasure.hunt.jts.geom.RectangleVariableHighlighter; import com.treasure.hunt.strategy.geom.GeometryItem; -import com.treasure.hunt.strategy.geom.GeometryStyle; import com.treasure.hunt.strategy.geom.GeometryType; import com.treasure.hunt.utils.EventBusUtils; import com.treasure.hunt.utils.JTSUtils; @@ -25,7 +24,6 @@ import org.locationtech.jts.geom.Point; import org.locationtech.jts.math.Vector2D; -import java.awt.*; import java.util.ArrayList; import java.util.List; @@ -81,39 +79,23 @@ public void subscribeToGeometryItem() { EventBusUtils.SELECTED_GEOMETRY_ITEMS_EVENT.addListener(geometryItem -> { Platform.runLater(() -> { log.trace("received: " + geometryItem); - if (geometryItem.getObject() instanceof Point) { - this.highlighter = new GeometryItem( - new CircleHighlighter(((Geometry) geometryItem.getObject()).getCoordinate(), - CanvasController.MOUSE_RECOGNIZE_DISTANCE, 64, JTSUtils.GEOMETRY_FACTORY), - GeometryType.STANDARD, - new GeometryStyle(true, Color.GREEN) - ); + Geometry geometry = (Geometry) geometryItem.getObject(); + if (geometry instanceof Point) { + this.highlighter = new GeometryItem(new CircleHighlighter(geometry.getCoordinate(), + CanvasController.MOUSE_RECOGNIZE_DISTANCE, 64, JTSUtils.GEOMETRY_FACTORY), GeometryType.HIGHLIGHTER); } else if (geometryItem.getObject() instanceof LineString) { - double minX = ((Geometry) geometryItem.getObject()).getCoordinates()[0].x; - double maxY = ((Geometry) geometryItem.getObject()).getCoordinates()[0].y; - double maxX = ((Geometry) geometryItem.getObject()).getCoordinates()[0].x; - double minY = ((Geometry) geometryItem.getObject()).getCoordinates()[0].y; - for (Coordinate coordinate : ((Geometry) geometryItem.getObject()).getCoordinates()) { - if (coordinate.x < minX) { - minX = coordinate.x; - } - if (coordinate.x > maxX) { - maxX = coordinate.x; - } - if (coordinate.y < minY) { - minY = coordinate.y; - } - if (coordinate.y > minY) { - maxY = coordinate.y; - } + double minX = geometry.getCoordinates()[0].x; + double maxX = minX; + double minY = geometry.getCoordinates()[0].y; + double maxY = minY; + for (Coordinate coordinate : geometry.getCoordinates()) { + minX = Math.min(minX, coordinate.x); + maxX = Math.max(maxX, coordinate.x); + minY = Math.min(minY, coordinate.x); + maxY = Math.max(maxY, coordinate.x); } - this.highlighter = new GeometryItem( - new RectangleVariableHighlighter( - new Coordinate(minX, maxY), - maxX - minX, maxY - minY, - JTSUtils.GEOMETRY_FACTORY), - GeometryType.STANDARD, - new GeometryStyle(true, Color.YELLOW)); + this.highlighter = new GeometryItem(new RectangleVariableHighlighter( + new Coordinate(minX, maxY), maxX - minX, maxY - minY, JTSUtils.GEOMETRY_FACTORY), GeometryType.HIGHLIGHTER); } drawShapes(); }); @@ -190,27 +172,21 @@ public void onCanvasClicked(MouseEvent mouseEvent) { if (lastMouseClick == null) { lastMouseClick = new Coordinate(mousePositionInGameContext.getX(), mousePositionInGameContext.getY()); + } + if (lastMouseClick.getX() != mousePositionInGameContext.getX() || + lastMouseClick.getY() != mousePositionInGameContext.getY()) { + geometryItemsListIndex = 0; geometryItemsList = gameManager.get().pickGeometryItem( new Coordinate(mousePositionInGameContext.getX(), -mousePositionInGameContext.getY()), MOUSE_RECOGNIZE_DISTANCE / transformation.getScaleProperty().get()); - EventBusUtils.SELECTED_GEOMETRY_ITEMS_EVENT.trigger(geometryItemsList.get(0)); - geometryItemsListIndex = 0; + lastMouseClick = new Coordinate(mousePositionInGameContext.getX(), mousePositionInGameContext.getY()); } else { - if (lastMouseClick.getX() == mousePositionInGameContext.getX() && - lastMouseClick.getY() == mousePositionInGameContext.getY()) { - geometryItemsListIndex = (geometryItemsListIndex + 1) % geometryItemsList.size(); - EventBusUtils.SELECTED_GEOMETRY_ITEMS_EVENT.trigger(geometryItemsList.get(geometryItemsListIndex)); - log.trace("received: " + geometryItemsListIndex + "/" + geometryItemsList.size()); - } else { - geometryItemsList = gameManager.get().pickGeometryItem( - new Coordinate(mousePositionInGameContext.getX(), -mousePositionInGameContext.getY()), - MOUSE_RECOGNIZE_DISTANCE / transformation.getScaleProperty().get()); - EventBusUtils.SELECTED_GEOMETRY_ITEMS_EVENT.trigger(geometryItemsList.get(0)); - lastMouseClick = new Coordinate(mousePositionInGameContext.getX(), mousePositionInGameContext.getY()); - } + geometryItemsListIndex = (geometryItemsListIndex + 1) % geometryItemsList.size(); } + log.info("received: " + geometryItemsListIndex + "/" + geometryItemsList.size()); + EventBusUtils.SELECTED_GEOMETRY_ITEMS_EVENT.trigger(geometryItemsList.get(geometryItemsListIndex)); } /** From b35513d824e543d4be19cb58768b947b2d0a06dc Mon Sep 17 00:00:00 2001 From: dorianreineccius Date: Tue, 14 Jan 2020 02:08:30 +0100 Subject: [PATCH 03/18] WIP --- src/main/java/com/treasure/hunt/view/CanvasController.java | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/main/java/com/treasure/hunt/view/CanvasController.java b/src/main/java/com/treasure/hunt/view/CanvasController.java index 757e546b..e4ca4993 100644 --- a/src/main/java/com/treasure/hunt/view/CanvasController.java +++ b/src/main/java/com/treasure/hunt/view/CanvasController.java @@ -182,7 +182,14 @@ public void onCanvasClicked(MouseEvent mouseEvent) { MOUSE_RECOGNIZE_DISTANCE / transformation.getScaleProperty().get()); lastMouseClick = new Coordinate(mousePositionInGameContext.getX(), mousePositionInGameContext.getY()); + + if (geometryItemsList.size() < 1) { + return; + } } else { + if (geometryItemsList.size() < 1) { + return; + } geometryItemsListIndex = (geometryItemsListIndex + 1) % geometryItemsList.size(); } log.info("received: " + geometryItemsListIndex + "/" + geometryItemsList.size()); From 3aca491cf44e5f3c04acbbe22dc79886c8922758 Mon Sep 17 00:00:00 2001 From: dorianreineccius Date: Tue, 14 Jan 2020 02:13:11 +0100 Subject: [PATCH 04/18] Added a visible filter for the geometryItems and fixed the exception --- src/main/java/com/treasure/hunt/game/GameManager.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/java/com/treasure/hunt/game/GameManager.java b/src/main/java/com/treasure/hunt/game/GameManager.java index f5012020..a3fc8a72 100644 --- a/src/main/java/com/treasure/hunt/game/GameManager.java +++ b/src/main/java/com/treasure/hunt/game/GameManager.java @@ -370,6 +370,7 @@ public List pickGeometryItem(Coordinate coordinate, double distanc .filter(geometryItem -> mouse.distance((Geometry) geometryItem.getObject()) <= distance ) + .filter(geometryItem -> geometryItem.getGeometryStyle().isVisible()) .sorted((geometryItem, secondGeometryItem) -> (int) (mouse.distance((Geometry) geometryItem.getObject()) - mouse.distance((Geometry) secondGeometryItem.getObject())) From 733ac2651b469a0f54a3de89e1cc7cd437811c55 Mon Sep 17 00:00:00 2001 From: dorianreineccius Date: Tue, 14 Jan 2020 02:16:48 +0100 Subject: [PATCH 05/18] Bugfix --- src/main/java/com/treasure/hunt/view/CanvasController.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/treasure/hunt/view/CanvasController.java b/src/main/java/com/treasure/hunt/view/CanvasController.java index e4ca4993..f2dd76b7 100644 --- a/src/main/java/com/treasure/hunt/view/CanvasController.java +++ b/src/main/java/com/treasure/hunt/view/CanvasController.java @@ -91,8 +91,8 @@ public void subscribeToGeometryItem() { for (Coordinate coordinate : geometry.getCoordinates()) { minX = Math.min(minX, coordinate.x); maxX = Math.max(maxX, coordinate.x); - minY = Math.min(minY, coordinate.x); - maxY = Math.max(maxY, coordinate.x); + minY = Math.min(minY, coordinate.y); + maxY = Math.max(maxY, coordinate.y); } this.highlighter = new GeometryItem(new RectangleVariableHighlighter( new Coordinate(minX, maxY), maxX - minX, maxY - minY, JTSUtils.GEOMETRY_FACTORY), GeometryType.HIGHLIGHTER); From fa6aa83791cc8f0c937ae855ff222527cdaac53d Mon Sep 17 00:00:00 2001 From: dorianreineccius Date: Tue, 14 Jan 2020 15:19:10 +0100 Subject: [PATCH 06/18] resolved conflicts --- src/main/java/com/treasure/hunt/jts/geom/Circle.java | 6 ++++++ src/main/java/com/treasure/hunt/view/CanvasController.java | 2 ++ 2 files changed, 8 insertions(+) diff --git a/src/main/java/com/treasure/hunt/jts/geom/Circle.java b/src/main/java/com/treasure/hunt/jts/geom/Circle.java index 453021e3..e884321e 100644 --- a/src/main/java/com/treasure/hunt/jts/geom/Circle.java +++ b/src/main/java/com/treasure/hunt/jts/geom/Circle.java @@ -13,6 +13,10 @@ * @see org.locationtech.jts.geom.Geometry */ public class Circle extends Polygon { + + protected Coordinate coordinate; + protected double radius; + /** * The constructor * @@ -29,6 +33,8 @@ public Circle(Coordinate coordinate, double radius, int numOfPoints, GeometryFac geometricShapeFactory.setSize(radius * 2); Polygon circle = geometricShapeFactory.createCircle(); this.shell = (LinearRing) circle.getExteriorRing(); + this.coordinate = coordinate; + this.radius = radius; } /** diff --git a/src/main/java/com/treasure/hunt/view/CanvasController.java b/src/main/java/com/treasure/hunt/view/CanvasController.java index f2dd76b7..6d2cd5d4 100644 --- a/src/main/java/com/treasure/hunt/view/CanvasController.java +++ b/src/main/java/com/treasure/hunt/view/CanvasController.java @@ -184,10 +184,12 @@ public void onCanvasClicked(MouseEvent mouseEvent) { lastMouseClick = new Coordinate(mousePositionInGameContext.getX(), mousePositionInGameContext.getY()); if (geometryItemsList.size() < 1) { + highlighter = null; return; } } else { if (geometryItemsList.size() < 1) { + highlighter = null; return; } geometryItemsListIndex = (geometryItemsListIndex + 1) % geometryItemsList.size(); From 56715e61446ed84e3315623b8d83f36b220f3d35 Mon Sep 17 00:00:00 2001 From: dorianreineccius Date: Thu, 5 Mar 2020 21:24:31 +0100 Subject: [PATCH 07/18] Works now --- .idea/codeStyles/Project.xml | 24 ----- .../com/treasure/hunt/game/GameEngine.java | 5 +- .../com/treasure/hunt/game/GameManager.java | 80 +++++++++++++++-- .../hunt/jts/geom/CircleHighlighter.java | 1 - .../jts/geom/RectangleFixedHighlighter.java | 1 - .../hunt/strategy/geom/GeometryItem.java | 6 +- .../treasure/hunt/utils/EventBusUtils.java | 2 - .../com/treasure/hunt/utils/JTSUtils.java | 10 +++ .../com/treasure/hunt/utils/Renderer.java | 69 ++++++++++---- .../treasure/hunt/view/CanvasController.java | 90 ++----------------- 10 files changed, 144 insertions(+), 144 deletions(-) diff --git a/.idea/codeStyles/Project.xml b/.idea/codeStyles/Project.xml index af193ac2..02eb89e5 100644 --- a/.idea/codeStyles/Project.xml +++ b/.idea/codeStyles/Project.xml @@ -1,29 +1,5 @@ - - - - - - - - - - -