diff --git a/docs/src/progress/renderertodo.md b/docs/src/progress/renderertodo.md index 10b6a7b7..36a7b7a9 100644 --- a/docs/src/progress/renderertodo.md +++ b/docs/src/progress/renderertodo.md @@ -2033,6 +2033,7 @@ Fix physics destruction on server via ServerLODComponent More job data scaffolding Config class cleanup Fix jobs data, simplify block chunk gen algo +Convex y-aligned prism intersection checking diff --git a/src/main/java/electrosphere/util/math/GeomUtils.java b/src/main/java/electrosphere/util/math/GeomUtils.java index 16579fd5..44e3eb78 100644 --- a/src/main/java/electrosphere/util/math/GeomUtils.java +++ b/src/main/java/electrosphere/util/math/GeomUtils.java @@ -688,5 +688,41 @@ public class GeomUtils { } return false; } + + /** + * Checks if a point falls within a prism or not + * @param point The point + * @param prismPoints The points defining the base of the prism + * @return true if the point is within the prism, false otherwise + */ + public static boolean pointIntersectsConvexPrism(Vector3d point, Vector3d[] prismPoints, double height){ + //error check quad definition + if(height <= 0){ + throw new Error("Quad has invalid height! " + height); + } + if(prismPoints.length < 3){ + throw new Error("Too few points! " + prismPoints.length); + } + //make sure the base is on the same y level + for(int i = 1; i < prismPoints.length; i++){ + if(prismPoints[i].y != prismPoints[0].y){ + throw new Error("Quadrilateral isn't aligned along y axis " + prismPoints[0].y + " " + prismPoints[i].y + " " + i); + } + } + //outside of y-bounds + if(point.y < prismPoints[0].y || point.y > prismPoints[0].y + height){ + return false; + } + //check if the point is within the x-z quadrilaterial + int crossings = 0; + for(int i = 0; i < prismPoints.length; i++){ + Vector3d point1 = prismPoints[i]; + Vector3d point2 = prismPoints[(i + 1) % prismPoints.length]; + if (((point1.z > point.z) != (point2.z > point.z)) && (point.x < (point2.x - point1.x) * (point.z - point1.z) / (point2.z - point1.z) + point1.x)) { + crossings++; + } + } + return (crossings % 2 == 1); + } } diff --git a/src/test/java/electrosphere/util/math/GeomUtilsTests.java b/src/test/java/electrosphere/util/math/GeomUtilsTests.java index 8d052952..be9e6b6c 100644 --- a/src/test/java/electrosphere/util/math/GeomUtilsTests.java +++ b/src/test/java/electrosphere/util/math/GeomUtilsTests.java @@ -112,4 +112,72 @@ public class GeomUtilsTests { assertTrue(GeomUtils.pointIntersectsSpline(new Vector3d(524298.0,10,524288.0), testSpline, 3)); } + @UnitTest + public void test_pointIntersectsConvexPrism_1(){ + //prism + Vector3d[] basePoints = new Vector3d[]{ + new Vector3d(0,0,0), + new Vector3d(3,0,10), + new Vector3d(10,0,10), + new Vector3d(10,0,7), + }; + double height = 2; + + //point + Vector3d testPt = new Vector3d(5,1,5); + + assertTrue(GeomUtils.pointIntersectsConvexPrism(testPt, basePoints, height)); + } + + @UnitTest + public void test_pointIntersectsConvexPrism_2(){ + //prism + Vector3d[] basePoints = new Vector3d[]{ + new Vector3d(0,0,0), + new Vector3d(3,0,10), + new Vector3d(10,0,10), + new Vector3d(10,0,7), + }; + double height = 2; + + //point + Vector3d testPt = new Vector3d(10,1,5); + + assertFalse(GeomUtils.pointIntersectsConvexPrism(testPt, basePoints, height)); + } + + @UnitTest + public void test_pointIntersectsConvexPrism_3(){ + //prism + Vector3d[] basePoints = new Vector3d[]{ + new Vector3d(0,0,0), + new Vector3d(3,0,10), + new Vector3d(10,0,10), + new Vector3d(10,0,7), + }; + double height = 2; + + //point + Vector3d testPt = new Vector3d(10,5,5); + + assertFalse(GeomUtils.pointIntersectsConvexPrism(testPt, basePoints, height)); + } + + @UnitTest + public void test_pointIntersectsConvexPrism_4(){ + //prism + Vector3d[] basePoints = new Vector3d[]{ + new Vector3d(0,0,0), + new Vector3d(3,0,10), + new Vector3d(10,0,10), + new Vector3d(10,0,7), + }; + double height = 2; + + //point + Vector3d testPt = new Vector3d(10,-1,5); + + assertFalse(GeomUtils.pointIntersectsConvexPrism(testPt, basePoints, height)); + } + }