diff --git a/NCPCore/src/main/java/fr/neatmonster/nocheatplus/utilities/collision/CollideRayVsAABB.java b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/utilities/collision/CollideRayVsAABB.java index eb8dc174..6ca0939b 100644 --- a/NCPCore/src/main/java/fr/neatmonster/nocheatplus/utilities/collision/CollideRayVsAABB.java +++ b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/utilities/collision/CollideRayVsAABB.java @@ -9,7 +9,7 @@ public class CollideRayVsAABB implements ICollideRayVsAABB { private double minX, minY, minZ, maxX, maxY, maxZ; /** Collision or closest point. */ - private double closestX, closestY, closestZ, closestTime; + private double closestX, closestY, closestZ, closestDistanceSquared, closestTime; /** * Indicate a collision occurred. Reset with calling loop only. */ @@ -59,6 +59,7 @@ public class CollideRayVsAABB implements ICollideRayVsAABB { closestX = startX; closestY = startY; closestZ = startZ; + closestDistanceSquared = 0.0; // Not applicable by default. closestTime = 0.0; // Determine basic orientation and timing. final double tMinX = CollisionUtil.getMinTimeIncludeEdges(startX, dirX, minX, maxX); @@ -79,7 +80,7 @@ public class CollideRayVsAABB implements ICollideRayVsAABB { closestZ = startZ + dirZ * tMin; } else if (findNearestPointIfNotCollide) { - findNearestPoint(tMinX, tMinY, tMinZ, tMaxX, tMaxY, tMaxZ, tMin, tMax); + findNearestPoint(tMinX, tMinY, tMinZ, tMaxX, tMaxY, tMaxZ); } } else if (findNearestPointIfNotCollide) { @@ -88,28 +89,10 @@ public class CollideRayVsAABB implements ICollideRayVsAABB { return this; } - /** - * Find the nearest point for the case of not hitting the box, but with - * hitting min-max coordinates per axis independently. - * - * @param tMinX - * @param tMinY - * @param tMinZ - * @param tMaxX - * @param tMaxY - * @param tMaxZ - * @param tMin - * @param tMax - */ - private void findNearestPoint(final double tMinX, final double tMinY, final double tMinZ, - final double tMaxX, final double tMaxY, final double tMaxZ, - final double tMin, final double tMax) { - // TODO: Implement. - } - /** * Estimate the nearest point for the case of at least one of the - * coordinates not being possible to match at all. + * coordinates not being possible to match at all. Asserts closestX|Y|Z to + * be set to the start coordinates. * * @param tMinX * @param tMinY @@ -118,9 +101,31 @@ public class CollideRayVsAABB implements ICollideRayVsAABB { * @param tMaxY * @param tMaxZ */ - private void findNearestPoint(final double tMinX, final double tMinY, final double tMinZ, - final double tMaxX, final double tMaxY, final double tMaxZ) { - // TODO: Implement. + private void findNearestPoint(final double... timeValues) { + // TODO: Squared vs. Manhattan vs. maxAxis. + // Update squared distance to 'actual'. + closestDistanceSquared = CollisionUtil.getSquaredDistAABB(this.startX, this.startY, this.startZ, + minX, minY, minZ, maxX, maxY, maxZ); + // Find the closest point using set time values. + for (int i = 0; i < timeValues.length; i++) { + final double time = timeValues[i]; + if (time == Double.NaN || time == Double.POSITIVE_INFINITY) { + // Note that Double.POSITIVE_INFINITY means that we are colliding forever. + continue; + } + final double x = startX + dirX * time; + final double y = startY + dirY * time; + final double z = startZ + dirZ * time; + final double distanceSquared = CollisionUtil.getSquaredDistAABB(x, y, z, + minX, minY, minZ, maxX, maxY, maxZ); + if (distanceSquared < closestDistanceSquared) { + closestX = x; + closestY = y; + closestZ = z; + closestDistanceSquared = distanceSquared; + closestTime = time; + } + } } @Override @@ -143,6 +148,11 @@ public class CollideRayVsAABB implements ICollideRayVsAABB { return closestZ; } + @Override + public double getClosestDistanceSquared() { + return closestDistanceSquared; + } + @Override public double getTime() { return closestTime; diff --git a/NCPCore/src/main/java/fr/neatmonster/nocheatplus/utilities/collision/CollisionUtil.java b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/utilities/collision/CollisionUtil.java index 3731e7c8..786ba8df 100644 --- a/NCPCore/src/main/java/fr/neatmonster/nocheatplus/utilities/collision/CollisionUtil.java +++ b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/utilities/collision/CollisionUtil.java @@ -386,4 +386,92 @@ public class CollisionUtil { } } + /** + * Get the maximum (closest) distance from the given position towards the + * AABB regarding axes independently. + * + * @param x + * Position of the point. + * @param y + * @param z + * @param minX + * Minimum coordinates of the AABB. + * @param minY + * @param minZ + * @param maxX + * Maximum coordinates of the AABB. + * @param maxY + * @param maxZ + * @return + */ + public static double getMaxAxisDistAABB(final double x, final double y, final double z, + final double minX, final double minY, final double minZ, + final double maxX, final double maxY, final double maxZ) { + return Math.max(axisDistance(x, minX, maxX), Math.max(axisDistance(y, minY, maxY), axisDistance(z, minZ, maxZ))); + } + + /** + * Get the maximum (closest) 'Manhattan' distance from the given position + * towards the AABB regarding axes independently. + * + * @param x + * Position of the point. + * @param y + * @param z + * @param minX + * Minimum coordinates of the AABB. + * @param minY + * @param minZ + * @param maxX + * Maximum coordinates of the AABB. + * @param maxY + * @param maxZ + * @return + */ + public static double getManhattanDistAABB(final double x, final double y, final double z, + final double minX, final double minY, final double minZ, + final double maxX, final double maxY, final double maxZ) { + return axisDistance(x, minX, maxX)+ axisDistance(y, minY, maxY) + axisDistance(z, minZ, maxZ); + } + + /** + * Get the squared (closest) distance from the given position towards the + * AABB regarding axes independently. + * + * @param x + * Position of the point. + * @param y + * @param z + * @param minX + * Minimum coordinates of the AABB. + * @param minY + * @param minZ + * @param maxX + * Maximum coordinates of the AABB. + * @param maxY + * @param maxZ + * @return + */ + public static double getSquaredDistAABB(final double x, final double y, final double z, + final double minX, final double minY, final double minZ, + final double maxX, final double maxY, final double maxZ) { + final double dX = axisDistance(x, minX, maxX); + final double dY = axisDistance(y, minY, maxY); + final double dZ = axisDistance(z, minZ, maxZ); + return dX * dX + dY * dY + dZ * dZ; + } + + /** + * Get the distance towards a min-max interval (inside and edge count as 0.0 + * distance). + * + * @param pos + * @param minPos + * @param maxPos + * @return Positive distance always. + */ + public static double axisDistance(final double pos, final double minPos, final double maxPos) { + return pos < minPos ? Math.abs(pos - minPos) : (pos > maxPos ? Math.abs(pos - maxPos) : 0.0); + } + } diff --git a/NCPCore/src/main/java/fr/neatmonster/nocheatplus/utilities/collision/ICollideRayVsAABB.java b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/utilities/collision/ICollideRayVsAABB.java index c925ad7f..d82f6b30 100644 --- a/NCPCore/src/main/java/fr/neatmonster/nocheatplus/utilities/collision/ICollideRayVsAABB.java +++ b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/utilities/collision/ICollideRayVsAABB.java @@ -6,7 +6,9 @@ import fr.neatmonster.nocheatplus.components.location.IGetPosition; * Collide a ray with an axis aligned bounding box (AABB). Allow fetching the * point of time, when the ray is closest to the AABB. The methods getX|Y|Z from * IGetPosition will fetch the coordinates of collision or the nearest point (if - * set so). By default colliding with the edges of the box would count. + * set so). That nearest point may be an estimation, not necessarily consistent + * for all cases/directions. By default colliding with the edges of the box + * would count. * * @author asofold * @@ -90,6 +92,14 @@ public interface ICollideRayVsAABB extends IGetPosition { */ public boolean collides(); + /** + * Get some kind of squared distance for the nearest point, in case of not + * colliding and findNearestPointIfNotCollid being set. + * + * @return 0.0 if not applicable. + */ + public double getClosestDistanceSquared(); + /** * Earliest time of collision if collides() returns true, or of the nearest * point, counted in times of applying the direction.