diff --git a/core/src/main/java/com/seibel/lod/core/util/RayCastUtil.java b/core/src/main/java/com/seibel/lod/core/util/RayCastUtil.java index 8905a9d8b..f695ed0fc 100644 --- a/core/src/main/java/com/seibel/lod/core/util/RayCastUtil.java +++ b/core/src/main/java/com/seibel/lod/core/util/RayCastUtil.java @@ -30,15 +30,8 @@ import com.seibel.lod.core.util.math.Vec3i; public class RayCastUtil { - public static boolean rayIntersectsCube(Vec3d rayStartingPos, Vec3f rayDirection, Vec3i cubeMinPos, int cubeWidth) - { - // the ray must intersect all 3 axis in order to have gone through the cube - return rayIntersectsSquare(rayStartingPos.x, rayStartingPos.z, rayDirection.x, rayDirection.z, cubeMinPos.x, cubeMinPos.z, cubeWidth) && - rayIntersectsSquare(rayStartingPos.x, rayStartingPos.y, rayDirection.x, rayDirection.y, cubeMinPos.x, cubeMinPos.y, cubeWidth); - } - /** - * this function works for any perpendicular axis, X and Y are just for simplicity and could easily be replaced with X, Y, or Z + * This function should work for any 2 perpendicular axis, X and Y could be replaced with X, Y, or Z * * @param rayX the ray's starting X position * @param rayY the ray's starting Z position @@ -74,7 +67,7 @@ public class RayCastUtil // should catch if this was true return false; } - else if (isRoughly(Math.abs(rayYDirection), 1, roundingValue)) + else if (isRoughly(Math.abs(rayYDirection), 1, roundingValue) || isRoughly(Math.abs(rayXDirection), 0, roundingValue)) { // slope is straight up or down @@ -91,13 +84,13 @@ public class RayCastUtil return rayX >= squareMinX && rayX <= squareMaxX; } } - else if (isRoughly(rayYDirection, 0, roundingValue)) + else if (isRoughly(Math.abs(rayXDirection), 1, roundingValue) || isRoughly(rayYDirection, 0, roundingValue)) { // slope is 0 (horizontal line) // is the ray pointing towards the square? if ((rayXDirection > 0 && rayX > squareMaxX) || // right - (rayXDirection < 0 && rayX < squareMinX)) // left + (rayXDirection < 0 && rayX < squareMinX)) // left { // the ray is pointing away from the square return false; @@ -132,7 +125,8 @@ public class RayCastUtil double yIntersectMax = slope * squareMaxX; // does the intersection happen before the ray's origin? - if (yIntersectMin <= rayY && (yIntersectMax <= rayY)) + if ((rayYDirection > 0 && (yIntersectMin <= rayY && yIntersectMax <= rayY)) || // moving in pos Y direction + (rayYDirection < 0 && (yIntersectMin >= rayY && yIntersectMax >= rayY))) // moving in neg Y direction { return false; } @@ -153,7 +147,8 @@ public class RayCastUtil double xIntersectMax = squareMaxY / slope; // does the intersection happen before the ray's origin? - if (xIntersectMin <= rayX && (xIntersectMax <= rayX)) + if ((rayXDirection > 0 && (xIntersectMin <= rayX && xIntersectMax <= rayX)) || // moving in pos X direction + (rayXDirection < 0 && (xIntersectMin >= rayX && xIntersectMax >= rayX))) // moving in neg X direction { return false; } diff --git a/core/src/test/java/tests/RaycastingTest.java b/core/src/test/java/tests/RaycastingTest.java index 3e02c03b7..3fb8486c9 100644 --- a/core/src/test/java/tests/RaycastingTest.java +++ b/core/src/test/java/tests/RaycastingTest.java @@ -21,6 +21,9 @@ package tests; import com.seibel.lod.core.api.external.methods.data.DhApiTerrainDataRepo; import com.seibel.lod.core.util.RayCastUtil; +import com.seibel.lod.core.util.math.Vec3d; +import com.seibel.lod.core.util.math.Vec3f; +import com.seibel.lod.core.util.math.Vec3i; import org.junit.Assert; import org.junit.Test; @@ -32,13 +35,8 @@ public class RaycastingTest { @Test - public void DemoTest() + public void HorizontalSquareTests() { - Assert.assertTrue("Example test 1", true); - - double rayX, rayY; - double xDir, yDir; - // 1x1 square at (1,1) - (2,2) double squareMinX = 1; double squareMinY = 1; @@ -46,16 +44,12 @@ public class RaycastingTest - //============// - // horizontal // - //============// - // ray points right - direction <1,0> - xDir = 1; - yDir = 0; + double xDir = 1; + double yDir = 0; // ray origin left of square - rayX = 0; + double rayX = 0; testRay(false, rayX, 0, xDir, yDir, squareMinX, squareMinY, squareWidth); testRay(false, rayX, 0.5, xDir, yDir, squareMinX, squareMinY, squareWidth); @@ -73,16 +67,46 @@ public class RaycastingTest testRay(false, rayX, 2, xDir, yDir, squareMinX, squareMinY, squareWidth); + // ray points left - direction <-1,0> + xDir = -1; + yDir = 0; + + // ray origin left of square + rayX = 0; + testRay(false, rayX, 0, xDir, yDir, squareMinX, squareMinY, squareWidth); + testRay(false, rayX, 0.5, xDir, yDir, squareMinX, squareMinY, squareWidth); + + testRay(false, rayX, 1, xDir, yDir, squareMinX, squareMinY, squareWidth); + testRay(false, rayX, 1.5, xDir, yDir, squareMinX, squareMinY, squareWidth); + testRay(false, rayX, 2, xDir, yDir, squareMinX, squareMinY, squareWidth); + + testRay(false, rayX, 2.5, xDir, yDir, squareMinX, squareMinY, squareWidth); + testRay(false, rayX, 3, xDir, yDir, squareMinX, squareMinY, squareWidth); + + // ray origin right of square + rayX = 2.5; + testRay(true, rayX, 1, xDir, yDir, squareMinX, squareMinY, squareWidth); + testRay(true, rayX, 1.5, xDir, yDir, squareMinX, squareMinY, squareWidth); + testRay(true, rayX, 2, xDir, yDir, squareMinX, squareMinY, squareWidth); + + } + + @Test + public void VerticalSquareTests() + { + // 1x1 square at (1,1) - (2,2) + double squareMinX = 1; + double squareMinY = 1; + int squareWidth = 1; - //==========// - // vertical // - //==========// - xDir = 0; - yDir = 1; // ray points up - direction <0,1> - rayY = 0; + double xDir = 0; + double yDir = 1; + + // ray origin under square // + double rayY = 0; // ray origin below square testRay(false, 0, rayY, xDir, yDir, squareMinX, squareMinY, squareWidth); @@ -110,14 +134,53 @@ public class RaycastingTest - //=======// - // point // - //=======// + // ray points down - direction <0,-1> + xDir = 0; + yDir = -1; + + // ray origin under square // + rayY = 0; + + // ray origin below square + testRay(false, 1, rayY, xDir, yDir, squareMinX, squareMinY, squareWidth); + testRay(false, 1.5, rayY, xDir, yDir, squareMinX, squareMinY, squareWidth); + testRay(false, 2, rayY, xDir, yDir, squareMinX, squareMinY, squareWidth); + + + // ray origin in square + testRay(true, 1, 1, xDir, yDir, squareMinX, squareMinY, squareWidth); + testRay(true, 1.5, 1.5, xDir, yDir, squareMinX, squareMinY, squareWidth); + testRay(true, 2, 2, xDir, yDir, squareMinX, squareMinY, squareWidth); + + + // ray origin above square + rayY = 2.5; + testRay(false, 0, rayY, xDir, yDir, squareMinX, squareMinY, squareWidth); + testRay(false, 0.5, rayY, xDir, yDir, squareMinX, squareMinY, squareWidth); + + testRay(true, 1, rayY, xDir, yDir, squareMinX, squareMinY, squareWidth); + testRay(true, 1.5, rayY, xDir, yDir, squareMinX, squareMinY, squareWidth); + testRay(true, 2, rayY, xDir, yDir, squareMinX, squareMinY, squareWidth); + + testRay(false, 2.5, rayY, xDir, yDir, squareMinX, squareMinY, squareWidth); + testRay(false, 3, rayY, xDir, yDir, squareMinX, squareMinY, squareWidth); + + } + + @Test + public void PerpendicularSquareTests() + { + // 1x1 square at (1,1) - (2,2) + double squareMinX = 1; + double squareMinY = 1; + int squareWidth = 1; + + // AKA the slope is perpendicular to this plane // direction <0,0> - xDir = 0; - yDir = 0; + double xDir = 0; + double yDir = 0; testRay(false, 0, 0, xDir, yDir, squareMinX, squareMinY, squareWidth); testRay(false, 0.5, 0.5, xDir, yDir, squareMinX, squareMinY, squareWidth); @@ -128,18 +191,24 @@ public class RaycastingTest testRay(false, 2.5, 2.5, xDir, yDir, squareMinX, squareMinY, squareWidth); testRay(false, 3, 3, xDir, yDir, squareMinX, squareMinY, squareWidth); + } + + @Test + public void DiagonalSquareTests() + { + // 1x1 square at (1,1) - (2,2) + double squareMinX = 1; + double squareMinY = 1; + int squareWidth = 1; - //==========// - // diagonal // - //==========// - // ray points up right - direction <4,3> (a slope of 3/4) - xDir = 4; - yDir = 3; + // ray points up right - direction <4,3> (a slope of 3/4) // + double xDir = 4; + double yDir = 3; // ray origin bottom left of square - rayX = 0; + double rayX = 0; testRay(false, rayX, -1, xDir, yDir, squareMinX, squareMinY, squareWidth); testRay(true, rayX, -0.5, xDir, yDir, squareMinX, squareMinY, squareWidth); @@ -159,14 +228,73 @@ public class RaycastingTest // ray origin right of square rayX = 2.5; - rayY = (yDir/xDir) * rayX; // y = mx + b // b is the constants defined below + double rayY = (yDir/xDir) * rayX; // y = mx + b // where b is the constants defined below testRay(false, rayX, -0.5 + rayY, xDir, yDir, squareMinX, squareMinY, squareWidth); testRay(false, rayX, 0 + rayY, xDir, yDir, squareMinX, squareMinY, squareWidth); testRay(false, rayX, 0.5 + rayY, xDir, yDir, squareMinX, squareMinY, squareWidth); testRay(false, rayX, 1 + rayY, xDir, yDir, squareMinX, squareMinY, squareWidth); + + + // ray points down right - direction <-4,3> (a slope of -3/4) // + + // move the cube to (1,-2) - (2,-1) + squareMinY = -2; + + //xDir = 4; + yDir = -3; + + // ray origin bottom left of square + rayX = 0; + testRay(false, rayX, 1, xDir, yDir, squareMinX, squareMinY, squareWidth); + + testRay(true, rayX, 0.5, xDir, yDir, squareMinX, squareMinY, squareWidth); + testRay(true, rayX, 0, xDir, yDir, squareMinX, squareMinY, squareWidth); + testRay(true, rayX, -0.5, xDir, yDir, squareMinX, squareMinY, squareWidth); + testRay(true, rayX, -1, xDir, yDir, squareMinX, squareMinY, squareWidth); + + testRay(false, rayX, -1.5, xDir, yDir, squareMinX, squareMinY, squareWidth); + testRay(false, rayX, -2, xDir, yDir, squareMinX, squareMinY, squareWidth); + + + // ray origin in square + testRay(true, 1, -1, xDir, yDir, squareMinX, squareMinY, squareWidth); + testRay(true, 1.5, -1.5, xDir, yDir, squareMinX, squareMinY, squareWidth); + testRay(true, 2, -2, xDir, yDir, squareMinX, squareMinY, squareWidth); + + + + // ray points down left - direction <-4,-3> (a slope of 3/4) // + + // move the cube to (-2,-2) - (-1,-1) + //squareMinY = -2; + squareMinX = -2; + + xDir = -4; + //yDir = -3; + + // ray origin bottom left of square + rayX = 0; + testRay(false, rayX, 1, xDir, yDir, squareMinX, squareMinY, squareWidth); + + testRay(true, rayX, 0.5, xDir, yDir, squareMinX, squareMinY, squareWidth); + testRay(true, rayX, 0, xDir, yDir, squareMinX, squareMinY, squareWidth); + testRay(true, rayX, -0.5, xDir, yDir, squareMinX, squareMinY, squareWidth); + testRay(true, rayX, -1, xDir, yDir, squareMinX, squareMinY, squareWidth); + + testRay(false, rayX, -1.5, xDir, yDir, squareMinX, squareMinY, squareWidth); + testRay(false, rayX, -2, xDir, yDir, squareMinX, squareMinY, squareWidth); + + + // ray origin in square + testRay(true, -1, -1, xDir, yDir, squareMinX, squareMinY, squareWidth); + testRay(true, -1.5, -1.5, xDir, yDir, squareMinX, squareMinY, squareWidth); + testRay(true, -2, -2, xDir, yDir, squareMinX, squareMinY, squareWidth); + + } + private static void testRay(boolean expectedToIntersect, double rayX, double rayY, double xDir, double yDir, double squareMinX, double squareMinY, double squareWidth) { boolean intersects = RayCastUtil.rayIntersectsSquare(rayX, rayY, xDir, yDir, squareMinX, squareMinY, squareWidth); @@ -178,5 +306,4 @@ public class RaycastingTest return "ray: [" + rayX + ", " + rayY + "] <" + xDir + ", " + yDir + "> square: [" + squareMinX + ", " + squareMinY + "] - [" + (squareMinX+squareWidth) + ", " + (squareMinY+squareWidth) + "]"; } - }