diff --git a/src/main/java/com/treasure/hunt/geom/GeometryAngle.java b/src/main/java/com/treasure/hunt/geom/GeometryAngle.java
index 77cc6d08..f275f848 100644
--- a/src/main/java/com/treasure/hunt/geom/GeometryAngle.java
+++ b/src/main/java/com/treasure/hunt/geom/GeometryAngle.java
@@ -1,6 +1,7 @@
package com.treasure.hunt.geom;
import com.treasure.hunt.jts.AdvancedShapeWriter;
+import com.treasure.hunt.utils.JTSUtils;
import org.locationtech.jts.geom.Coordinate;
import org.locationtech.jts.geom.GeometryFactory;
import org.locationtech.jts.geom.LineString;
@@ -22,7 +23,7 @@
public class GeometryAngle extends LineString implements Shapeable {
/**
- * Creates a new Geometry
via the specified GeometryFactory.
+ * GeometryAngle constructor via three {@link Coordinate}s.
*
* @param factory The GeometryFactory suggested to create the Angle
* @param right the right angles arm end point
@@ -37,6 +38,34 @@ public GeometryAngle(GeometryFactory factory, Coordinate right, Coordinate cente
);
}
+ /**
+ * GeometryAngle with standard geometry factory.
+ *
+ * @param right the right angles arm end point
+ * @param center the central point of the angle
+ * @param left the left angles arm end point
+ */
+ public GeometryAngle(Coordinate right, Coordinate center, Coordinate left) {
+ this(JTSUtils.GEOMETRY_FACTORY, right, center, left);
+ }
+
+ /**
+ * GeometryAngle constructor via the central {@link Coordinate}, the start angle and the angles extend.
+ *
+ * @param factory The GeometryFactory suggested to create the Angle
+ * @param center the central point of the angle
+ * @param start starting angle relative to x-axis
+ * @param extend angle extend
+ */
+ public GeometryAngle(GeometryFactory factory, Coordinate center, double start, double extend) {
+ this(
+ factory,
+ Vector2D.create(1, 0).rotate(start).translate(center),
+ center,
+ Vector2D.create(1, 0).rotate(start + extend).translate(center)
+ );
+ }
+
private void setCoordinate(int i, Coordinate c) {
points.getCoordinate(i).setX(c.getX());
points.getCoordinate(i).setY(c.getY());
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 cddd8158..5dc0bf73 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
@@ -4,7 +4,6 @@
import com.treasure.hunt.strategy.hint.impl.AngleHint;
import com.treasure.hunt.strategy.searcher.Movement;
import com.treasure.hunt.utils.JTSUtils;
-import org.locationtech.jts.algorithm.Angle;
import org.locationtech.jts.geom.Coordinate;
import org.locationtech.jts.geom.Point;
@@ -26,27 +25,8 @@ public Point getTreasureLocation() {
public AngleHint move(Movement movement) {
Coordinate searcherPos = movement.getEndPoint().getCoordinate();
- // generate angle
- double randomAngle = Math.random() * 2 * Math.PI; // in [0, PI)
- double random = Math.random();
- double leftAngle = Angle.angle(searcherPos,
- treasurePos.getCoordinate()) + random * randomAngle;
- double leftX = searcherPos.getX() + (Math.cos(leftAngle) * 1);
- double leftY = searcherPos.getY() + (Math.sin(leftAngle) * 1);
- double rightAngle = Angle.angle(searcherPos,
- treasurePos.getCoordinate()) - (1 - random) * randomAngle;
- double rightX = searcherPos.getX() + (Math.cos(rightAngle) * 1);
- double rightY = searcherPos.getY() + (Math.sin(rightAngle) * 1);
-
- /*double angleHintToTreasure = angleBetweenOriented(treasureLocation.getCoordinate(), middle.getCoordinate(), angleLeft.getCoordinate());
- if (angleHintToTreasure > angle || angleHintToTreasure < 0) {
- throw new UserControlledAngleHintHider.WrongAngleException("Treasure Location not contained in angle");
- }*/
-
return new AngleHint(
- new Coordinate(rightX, rightY),
- searcherPos,
- new Coordinate(leftX, leftY)
+ JTSUtils.validRandomAngle(searcherPos, treasurePos.getCoordinate(), 2 * Math.PI)
);
}
}
diff --git a/src/main/java/com/treasure/hunt/strategy/hint/impl/AngleHint.java b/src/main/java/com/treasure/hunt/strategy/hint/impl/AngleHint.java
index a389f692..f45be68a 100644
--- a/src/main/java/com/treasure/hunt/strategy/hint/impl/AngleHint.java
+++ b/src/main/java/com/treasure/hunt/strategy/hint/impl/AngleHint.java
@@ -21,8 +21,12 @@ public class AngleHint extends Hint {
GeometryAngle geometryAngle;
public AngleHint(Coordinate right, Coordinate center, Coordinate left) {
- geometryAngle = new GeometryAngle(JTSUtils.GEOMETRY_FACTORY, right, center, left);
- log.trace(geometryAngle.toString());
+ this(new GeometryAngle(JTSUtils.GEOMETRY_FACTORY, right, center, left));
+ }
+
+ public AngleHint(GeometryAngle angle) {
+ geometryAngle = angle;
+ log.trace(angle.toString());
}
public List> getGeometryItems() {
diff --git a/src/main/java/com/treasure/hunt/utils/JTSUtils.java b/src/main/java/com/treasure/hunt/utils/JTSUtils.java
index f4c40f50..48eb4d95 100644
--- a/src/main/java/com/treasure/hunt/utils/JTSUtils.java
+++ b/src/main/java/com/treasure/hunt/utils/JTSUtils.java
@@ -2,6 +2,7 @@
import com.treasure.hunt.geom.GeometryAngle;
import com.treasure.hunt.strategy.hint.impl.AngleHint;
+import org.locationtech.jts.algorithm.Angle;
import org.locationtech.jts.geom.*;
import org.locationtech.jts.math.Vector2D;
@@ -175,4 +176,14 @@ public static boolean pointInAngle(Coordinate right, Coordinate center, Coordina
public static Vector2D lineVector(LineSegment lineSegment) {
return new Vector2D(lineSegment.p0, lineSegment.p1);
}
+
+ public static GeometryAngle validRandomAngle(Coordinate searcher, Coordinate treasure, double maxExtend) {
+ if (maxExtend <= 0) {
+ return null;
+ }
+ double givenAngle = Angle.angle(searcher, treasure);
+ double extend = Math.random() * maxExtend;
+ double start = givenAngle - extend * Math.random();
+ return new GeometryAngle(GEOMETRY_FACTORY, searcher, start, extend);
+ }
}
diff --git a/src/test/java/com/treasure/hunt/utils/JTSUtilsTest.java b/src/test/java/com/treasure/hunt/utils/JTSUtilsTest.java
index b1d3e63b..8a7ee26d 100644
--- a/src/test/java/com/treasure/hunt/utils/JTSUtilsTest.java
+++ b/src/test/java/com/treasure/hunt/utils/JTSUtilsTest.java
@@ -1,10 +1,12 @@
package com.treasure.hunt.utils;
+import com.treasure.hunt.geom.GeometryAngle;
import com.treasure.hunt.strategy.hint.impl.AngleHint;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.locationtech.jts.geom.Coordinate;
+import static org.junit.jupiter.api.Assertions.assertNull;
import static org.junit.jupiter.api.Assertions.assertTrue;
class JTSUtilsTest {
@@ -195,4 +197,33 @@ private void neq(Coordinate expected, Coordinate actual) {
assertTrue(Math.abs(expected.x - actual.x) > 0.0001 || Math.abs(expected.y - actual.y) > 0.0001,
"Expected: x≠" + expected.x + " or y≠" + expected.y + ", but was ≈(" + actual.x + ", " + actual.y + ").");
}
+
+ @Test
+ void randomAngleTest() {
+ for (int i = 0; i < 100; i++) {
+ final Coordinate searcher = new Coordinate(Math.random() * 100, Math.random() * 100);
+ final Coordinate treasure = new Coordinate(Math.random() * 100, Math.random() * 100);
+ final GeometryAngle angle = JTSUtils.validRandomAngle(searcher, treasure, 2 * Math.PI);
+ assertInAngle(angle, treasure);
+ }
+ }
+
+ @Test
+ void invalidRandomAngles() {
+ final Coordinate searcher = new Coordinate(Math.random() * 100, Math.random() * 100);
+ final Coordinate treasure = new Coordinate(Math.random() * 100, Math.random() * 100);
+ final GeometryAngle invalidExtend = JTSUtils.validRandomAngle(searcher, treasure, 0);
+ assertNull(invalidExtend);
+ }
+
+ @Test
+ void treasureAtRandomAngleCenter() {
+ final Coordinate sameCoordinate = new Coordinate();
+ final GeometryAngle emptyAngle = JTSUtils.validRandomAngle(sameCoordinate, sameCoordinate, 2 * Math.PI);
+ assertInAngle(emptyAngle, sameCoordinate);
+ }
+
+ void assertInAngle(GeometryAngle angle, Coordinate coordinate) {
+ assertTrue(JTSUtils.pointInAngle(angle, coordinate));
+ }
}