fast_polygon_cube_intersection.cpp

Go to the documentation of this file.
00001 /******************************************************************************
00002 *       SOFA, Simulation Open-Framework Architecture, version 1.0 beta 3      *
00003 *                (c) 2006-2008 MGH, INRIA, USTL, UJF, CNRS                    *
00004 *                                                                             *
00005 * This library is free software; you can redistribute it and/or modify it     *
00006 * under the terms of the GNU Lesser General Public License as published by    *
00007 * the Free Software Foundation; either version 2.1 of the License, or (at     *
00008 * your option) any later version.                                             *
00009 *                                                                             *
00010 * This library is distributed in the hope that it will be useful, but WITHOUT *
00011 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or       *
00012 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License *
00013 * for more details.                                                           *
00014 *                                                                             *
00015 * You should have received a copy of the GNU Lesser General Public License    *
00016 * along with this library; if not, write to the Free Software Foundation,     *
00017 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301 USA.          *
00018 *******************************************************************************
00019 *                              SOFA :: Framework                              *
00020 *                                                                             *
00021 * Authors: M. Adam, J. Allard, B. Andre, P-J. Bensoussan, S. Cotin, C. Duriez,*
00022 * H. Delingette, F. Falipou, F. Faure, S. Fonteneau, L. Heigeas, C. Mendoza,  *
00023 * M. Nesme, P. Neumann, J-P. de la Plata Alcade, F. Poyer and F. Roy          *
00024 *                                                                             *
00025 * Contact information: contact@sofa-framework.org                             *
00026 ******************************************************************************/
00027 /*
00028  *                  FAST POLYGON-CUBE INTERSECTION TESTS
00029  *                  by Daniel Green
00030  *                  January 1994
00031  *
00032  *
00033  * The original inspiration for this routine comes from the triangle-cube
00034  * intersection algorithm in Graphics Gems III by Douglas Voorhies.
00035  * Aside from the fact that the original code was special-cased for triangles
00036  * only, it suffered from some bugs.  Don Hatch re-wrote the non-trivial tests
00037  * using the same basic ideas, fixed the bugs and also made it more
00038  * general and efficient.  Don's implementation performs just the
00039  * intersection calculations without any trivial accept or reject tests,
00040  * and is embodied in the routine polygon_intersects_cube().
00041  *
00042  * The function implemented here is simply a wrapper that begins with a
00043  * slightly more efficient version of Voorhies' original trivial reject tests
00044  * and only calls polygon_intersects_cube() when those tests fail.
00045  * The result is a fast and robust polygon-cube tester.
00046  *
00047  * Also included here is trivial_vertex_tests() which is used by
00048  * fast_polygon_intersects_cube().  It can be used to quickly test an entire
00049  * set of vertices for trivial reject or accept.  This is useful for testing
00050  * polyhedra or polygon meshes.
00051  *
00052  * WARNING: When used to test intersection of a polyhedron with the unit cube,
00053  * remember that these routines only test *surfaces* and not volumes.
00054  * If polygon_intersects_cube() reports no intersection with any of the faces
00055  * of the polyhedron, the caller should be aware that the polyhedron
00056  * could still contain the whole unit cube which would then need to be checked
00057  * with a point-within-polyhedron test.  The origin would be a natural point
00058  * to check in such a test.
00059  */
00060 
00061 
00062 #include "polygon_cube_intersection.h"
00063 
00064 namespace sofa
00065 {
00066 namespace helper
00067 {
00068 namespace polygon_cube_intersection
00069 {
00070 
00071 #ifndef __cplusplus
00072 #define inline
00073 #endif
00074 
00075 
00076 #define TEST_AGAINST_PARALLEL_PLANES(posbit, negbit, value, limit)  \
00077     if (mask & (posbit|negbit)) {                   \
00078         register real temp = value;             \
00079         if ((mask & posbit) && temp > limit)            \
00080             outcode |= posbit;              \
00081         else if ((mask & negbit) && temp < -limit)      \
00082             outcode |= negbit;              \
00083     }                               \
00084 
00085 
00086 /*
00087  * Tells which of the six face-planes the given point is outside of.
00088  * Only tests faces not represented in "mask".
00089  */
00090 
00091 static inline unsigned long
00092 face_plane(const real p[3], unsigned long mask)
00093 {
00094     register unsigned long outcode = 0L;
00095 
00096     TEST_AGAINST_PARALLEL_PLANES(0x001, 0x002, p[0], 0.5)
00097     TEST_AGAINST_PARALLEL_PLANES(0x004, 0x008, p[1], 0.5)
00098     TEST_AGAINST_PARALLEL_PLANES(0x010, 0x020, p[2], 0.5)
00099 
00100     return(outcode);
00101 }
00102 
00103 
00104 
00105 /*
00106  * Tells which of the twelve edge planes the given point is outside of.
00107  * Only tests faces not represented in "mask".
00108  */
00109 
00110 static inline unsigned long
00111 bevel_2d(const real p[3], unsigned long mask)
00112 {
00113     register unsigned long outcode = 0L;
00114 
00115     TEST_AGAINST_PARALLEL_PLANES(0x001, 0x002, p[0] + p[1], 1.0)
00116     TEST_AGAINST_PARALLEL_PLANES(0x004, 0x008, p[0] - p[1], 1.0)
00117     TEST_AGAINST_PARALLEL_PLANES(0x010, 0x020, p[0] + p[2], 1.0)
00118     TEST_AGAINST_PARALLEL_PLANES(0x040, 0x080, p[0] - p[2], 1.0)
00119     TEST_AGAINST_PARALLEL_PLANES(0x100, 0x200, p[1] + p[2], 1.0)
00120     TEST_AGAINST_PARALLEL_PLANES(0x400, 0x800, p[1] - p[2], 1.0)
00121 
00122     return(outcode);
00123 }
00124 
00125 
00126 
00127 /*
00128  * Tells which of the eight corner planes the given point is outside of.
00129  * Only tests faces not represented in "mask".
00130  */
00131 
00132 static inline unsigned long
00133 bevel_3d(const real p[3], unsigned long mask)
00134 {
00135     register unsigned long outcode = 0L;
00136 
00137     TEST_AGAINST_PARALLEL_PLANES(0x001, 0x002, p[0] + p[1] + p[2], 1.5)
00138     TEST_AGAINST_PARALLEL_PLANES(0x004, 0x008, p[0] + p[1] - p[2], 1.5)
00139     TEST_AGAINST_PARALLEL_PLANES(0x010, 0x020, p[0] - p[1] + p[2], 1.5)
00140     TEST_AGAINST_PARALLEL_PLANES(0x040, 0x080, p[0] - p[1] - p[2], 1.5)
00141 
00142     return(outcode);
00143 }
00144 
00145 
00146 
00147 /*
00148  * Returns 1 if any of the vertices are inside the cube of edge length 1
00149  * centered at the origin (trivial accept), 0 if all vertices are outside
00150  * of any testing plane (trivial reject), -1 otherwise (couldn't help).
00151  */
00152 
00153 extern int
00154 trivial_vertex_tests(int nverts, const real verts[][3],
00155             int already_know_verts_are_outside_cube)
00156 {
00157     register unsigned long cum_and;  /* cumulative logical ANDs */
00158     register int i;
00159 
00160     /*
00161      * Compare the vertices with all six face-planes.
00162      * If it's known that no vertices are inside the unit cube
00163      * we can exit the loop early if we run out of bounding
00164      * planes that all vertices might be outside of.  That simply means
00165      * that this test failed and we can go on to the next one.
00166      * If we must test for vertices within the cube, the loop is slightly
00167      * different in that we can trivially accept if we ever do find a
00168      * vertex within the cube, but we can't break the loop early if we run
00169      * out of planes to reject against because subsequent vertices might
00170      * still be within the cube.
00171      */
00172     cum_and = ~0L;  /* Set to all "1" bits */
00173     if(already_know_verts_are_outside_cube) {
00174         for(i=0; i<nverts; i++)
00175             if(0L == (cum_and = face_plane(verts[i], cum_and)))
00176                 break; /* No planes left to trivially reject */
00177     }
00178     else {
00179         for(i=0; i<nverts; i++) {
00180             /* Note the ~0L mask below to always test all planes */
00181             unsigned long face_bits = face_plane(verts[i], ~0L);
00182             if(0L == face_bits)  /* vertex is inside the cube */
00183                 return 1; /* trivial accept */
00184             cum_and &= face_bits;
00185         }
00186     }
00187     if(cum_and != 0L)  /* All vertices outside some face plane. */
00188         return 0;  /* Trivial reject */
00189 
00190     /*
00191      * Now do the just the trivial reject test against the 12 edge planes.
00192      */
00193     cum_and = ~0L;  /* Set to all "1" bits */
00194     for(i=0; i<nverts; i++)
00195         if(0L == (cum_and = bevel_2d(verts[i], cum_and)))
00196             break; /* No planes left that might trivially reject */
00197     if(cum_and != 0L)  /* All vertices outside some edge plane. */
00198         return 0;  /* Trivial reject */
00199 
00200     /*
00201      * Now do the trivial reject test against the 8 corner planes.
00202      */
00203     cum_and = ~0L;  /* Set to all "1" bits */
00204     for(i=0; i<nverts; i++)
00205         if(0L == (cum_and = bevel_3d(verts[i], cum_and)))
00206             break; /* No planes left that might trivially reject */
00207     if(cum_and != 0L)  /* All vertices outside some corner plane. */
00208         return 0;  /* Trivial reject */
00209 
00210     /*
00211      * By now we know that the polygon is not to the outside of any of the
00212      * test planes and can't be trivially accepted *or* rejected.
00213      */
00214     return -1;
00215 }
00216 
00217 
00218 
00219 /*
00220  * This is a version of the same polygon-cube intersection that first calls
00221  * trivial_vertex_tests() to hopefully skip the more expensive definitive test.
00222  * It simply calls polygon_intersects_cube() when that fails.
00223  * Note that after the trivial tests we at least know that all vertices are
00224  * outside the cube and can therefore pass a true flag to
00225  * polygon_intersects_cube().
00226  */
00227 extern int
00228 fast_polygon_intersects_cube(int nverts, const real verts[][3],
00229                         const real polynormal[3],
00230             int already_know_verts_are_outside_cube,
00231             int already_know_edges_are_outside_cube)
00232 {
00233     int quick_test = trivial_vertex_tests(nverts, verts,
00234                 already_know_verts_are_outside_cube);
00235     if(-1 == quick_test)
00236         return polygon_intersects_cube(nverts, verts, polynormal, 1,
00237                 already_know_edges_are_outside_cube);
00238     else
00239         return quick_test;
00240 }
00241 
00242 }
00243 }
00244 }

Generated on Sun Nov 23 02:29:30 2008 for Sofa by  doxygen 1.5.7.1