📄 fpcube.c
字号:
/* * FAST POLYGON-CUBE INTERSECTION TESTS * by Daniel Green * January 1994 * * * The original inspiration for this routine comes from the triangle-cube * intersection algorithm in Graphics Gems III by Douglas Voorhies. * Aside from the fact that the original code was special-cased for triangles * only, it suffered from some bugs. Don Hatch re-wrote the non-trivial tests * using the same basic ideas, fixed the bugs and also made it more * general and efficient. Don's implementation performs just the * intersection calculations without any trivial accept or reject tests, * and is embodied in the routine polygon_intersects_cube(). * * The function implemented here is simply a wrapper that begins with a * slightly more efficient version of Voorhies' original trivial reject tests * and only calls polygon_intersects_cube() when those tests fail. * The result is a fast and robust polygon-cube tester. * * Also included here is trivial_vertex_tests() which is used by * fast_polygon_intersects_cube(). It can be used to quickly test an entire * set of vertices for trivial reject or accept. This is useful for testing * polyhedra or polygon meshes. * * WARNING: When used to test intersection of a polyhedron with the unit cube, * remember that these routines only test *surfaces* and not volumes. * If polygon_intersects_cube() reports no intersection with any of the faces * of the polyhedron, the caller should be aware that the polyhedron * could still contain the whole unit cube which would then need to be checked * with a point-within-polyhedron test. The origin would be a natural point * to check in such a test. */#include "pcube.h"#ifndef __cplusplus#define inline#endif#define TEST_AGAINST_PARALLEL_PLANES(posbit, negbit, value, limit) \ if (mask & (posbit|negbit)) { \ register real temp = value; \ if ((mask & posbit) && temp > limit) \ outcode |= posbit; \ else if ((mask & negbit) && temp < -limit) \ outcode |= negbit; \ } \/* * Tells which of the six face-planes the given point is outside of. * Only tests faces not represented in "mask". */static inline unsigned longface_plane(const real p[3], unsigned long mask){ register unsigned long outcode = 0L; TEST_AGAINST_PARALLEL_PLANES(0x001, 0x002, p[0], 0.5) TEST_AGAINST_PARALLEL_PLANES(0x004, 0x008, p[1], 0.5) TEST_AGAINST_PARALLEL_PLANES(0x010, 0x020, p[2], 0.5) return(outcode);}/* * Tells which of the twelve edge planes the given point is outside of. * Only tests faces not represented in "mask". */static inline unsigned longbevel_2d(const real p[3], unsigned long mask){ register unsigned long outcode = 0L; TEST_AGAINST_PARALLEL_PLANES(0x001, 0x002, p[0] + p[1], 1.0) TEST_AGAINST_PARALLEL_PLANES(0x004, 0x008, p[0] - p[1], 1.0) TEST_AGAINST_PARALLEL_PLANES(0x010, 0x020, p[0] + p[2], 1.0) TEST_AGAINST_PARALLEL_PLANES(0x040, 0x080, p[0] - p[2], 1.0) TEST_AGAINST_PARALLEL_PLANES(0x100, 0x200, p[1] + p[2], 1.0) TEST_AGAINST_PARALLEL_PLANES(0x400, 0x800, p[1] - p[2], 1.0) return(outcode);}/* * Tells which of the eight corner planes the given point is outside of. * Only tests faces not represented in "mask". */static inline unsigned longbevel_3d(const real p[3], unsigned long mask){ register unsigned long outcode = 0L; TEST_AGAINST_PARALLEL_PLANES(0x001, 0x002, p[0] + p[1] + p[2], 1.5) TEST_AGAINST_PARALLEL_PLANES(0x004, 0x008, p[0] + p[1] - p[2], 1.5) TEST_AGAINST_PARALLEL_PLANES(0x010, 0x020, p[0] - p[1] + p[2], 1.5) TEST_AGAINST_PARALLEL_PLANES(0x040, 0x080, p[0] - p[1] - p[2], 1.5) return(outcode);}/* * Returns 1 if any of the vertices are inside the cube of edge length 1 * centered at the origin (trivial accept), 0 if all vertices are outside * of any testing plane (trivial reject), -1 otherwise (couldn't help). */extern inttrivial_vertex_tests(int nverts, const real verts[][3], int already_know_verts_are_outside_cube){ register unsigned long cum_and; /* cumulative logical ANDs */ register int i; /* * Compare the vertices with all six face-planes. * If it's known that no vertices are inside the unit cube * we can exit the loop early if we run out of bounding * planes that all vertices might be outside of. That simply means * that this test failed and we can go on to the next one. * If we must test for vertices within the cube, the loop is slightly * different in that we can trivially accept if we ever do find a * vertex within the cube, but we can't break the loop early if we run * out of planes to reject against because subsequent vertices might * still be within the cube. */ cum_and = ~0L; /* Set to all "1" bits */ if(already_know_verts_are_outside_cube) { for(i=0; i<nverts; i++) if(0L == (cum_and = face_plane(verts[i], cum_and))) break; /* No planes left to trivially reject */ } else { for(i=0; i<nverts; i++) { /* Note the ~0L mask below to always test all planes */ unsigned long face_bits = face_plane(verts[i], ~0L); if(0L == face_bits) /* vertex is inside the cube */ return 1; /* trivial accept */ cum_and &= face_bits; } } if(cum_and != 0L) /* All vertices outside some face plane. */ return 0; /* Trivial reject */ /* * Now do the just the trivial reject test against the 12 edge planes. */ cum_and = ~0L; /* Set to all "1" bits */ for(i=0; i<nverts; i++) if(0L == (cum_and = bevel_2d(verts[i], cum_and))) break; /* No planes left that might trivially reject */ if(cum_and != 0L) /* All vertices outside some edge plane. */ return 0; /* Trivial reject */ /* * Now do the trivial reject test against the 8 corner planes. */ cum_and = ~0L; /* Set to all "1" bits */ for(i=0; i<nverts; i++) if(0L == (cum_and = bevel_3d(verts[i], cum_and))) break; /* No planes left that might trivially reject */ if(cum_and != 0L) /* All vertices outside some corner plane. */ return 0; /* Trivial reject */ /* * By now we know that the polygon is not to the outside of any of the * test planes and can't be trivially accepted *or* rejected. */ return -1;}/* * This is a version of the same polygon-cube intersection that first calls * trivial_vertex_tests() to hopefully skip the more expensive definitive test. * It simply calls polygon_intersects_cube() when that fails. * Note that after the trivial tests we at least know that all vertices are * outside the cube and can therefore pass a true flag to * polygon_intersects_cube(). */extern intfast_polygon_intersects_cube(int nverts, const real verts[][3], const real polynormal[3], int already_know_verts_are_outside_cube, int already_know_edges_are_outside_cube){ int quick_test = trivial_vertex_tests(nverts, verts, already_know_verts_are_outside_cube); if(-1 == quick_test) return polygon_intersects_cube(nverts, verts, polynormal, 1, already_know_edges_are_outside_cube); else return quick_test;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -