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 * polygon_intersects_cube() 00029 * by Don Hatch 00030 * January 1994 00031 * 00032 * Algorithm: 00033 * 1. If any edge intersects the cube, return true. 00034 * Testing whether a line segment intersects the cube 00035 * is equivalent to testing whether the origin is contained 00036 * in the rhombic dodecahedron obtained by dragging 00037 * a unit cube from (being centered at) one segment endpoint 00038 * to the other. 00039 * 2. If the polygon interior intersects the cube, return true. 00040 * Since we know no vertex or edge intersects the cube, 00041 * this amounts to testing whether any of the four cube diagonals 00042 * intersects the interior of the polygon. (Same as voorhies's test). 00043 * 3. Return false. 00044 */ 00045 00046 #include "polygon_cube_intersection.h" 00047 #include "vec.h" 00048 00049 namespace sofa 00050 { 00051 namespace helper 00052 { 00053 namespace polygon_cube_intersection 00054 { 00055 00056 #define FOR(i,n) for ((i) = 0; (i) < (n); ++(i)) 00057 #define MAXDIM2(v) ((v)[0] > (v)[1] ? 0 : 1) 00058 #define MAXDIM3(v) ((v)[0] > (v)[2] ? MAXDIM2(v) : MAXDIM2((v)+1)+1) 00059 #define ABS(x) ((x)<0 ? -(x) : (x)) 00060 #define SQR(x) ((x)*(x)) 00061 #define SIGN_NONZERO(x) ((x) < 0 ? -1 : 1) 00062 /* note a and b can be in the reverse order and it still works! */ 00063 #define IN_CLOSED_INTERVAL(a,x,b) (((x)-(a)) * ((x)-(b)) <= 0) 00064 #define IN_OPEN_INTERVAL(a,x,b) (((x)-(a)) * ((x)-(b)) < 0) 00065 00066 00067 00068 #define seg_contains_point(a,b,x) (((b)>(x)) - ((a)>(x))) 00069 /* 00070 * Tells whether a given polygon with nonzero area 00071 * contains a point which is assumed to lie in the plane of the polygon. 00072 * Actually returns the multiplicity of containment. 00073 * This will always be 1 or 0 for non-self-intersecting planar 00074 * polygons with the normal in the standard direction 00075 * (towards the eye when looking at the polygon so that it's CCW). 00076 */ 00077 extern int 00078 polygon_contains_point_3d(int nverts, const float verts[/* nverts */][3], 00079 const float polynormal[3], 00080 float point[3]) 00081 { 00082 float abspolynormal[3]; 00083 int zaxis, xaxis, yaxis, i, count; 00084 int xdirection; 00085 const float *v, *w; 00086 00087 /* 00088 * Determine which axis to ignore 00089 * (the one in which the polygon normal is largest) 00090 */ 00091 FOR(i,3) 00092 abspolynormal[i] = ABS(polynormal[i]); 00093 zaxis = MAXDIM3(abspolynormal); 00094 00095 if (polynormal[zaxis] < 0) { 00096 xaxis = (zaxis+2)%3; 00097 yaxis = (zaxis+1)%3; 00098 } else { 00099 xaxis = (zaxis+1)%3; 00100 yaxis = (zaxis+2)%3; 00101 } 00102 00103 count = 0; 00104 FOR(i,nverts) { 00105 v = verts[i]; 00106 w = verts[(i+1)%nverts]; 00107 if ((xdirection = seg_contains_point(v[xaxis], w[xaxis], point[xaxis]))) { 00108 if (seg_contains_point(v[yaxis], w[yaxis], point[yaxis])) { 00109 if (xdirection * (point[xaxis]-v[xaxis])*(w[yaxis]-v[yaxis]) <= 00110 xdirection * (point[yaxis]-v[yaxis])*(w[xaxis]-v[xaxis])) 00111 count += xdirection; 00112 } else { 00113 if (v[yaxis] <= point[yaxis]) 00114 count += xdirection; 00115 } 00116 } 00117 } 00118 return count; 00119 } 00120 00121 00122 00123 00124 /* 00125 * A segment intersects the unit cube centered at the origin 00126 * iff the origin is contained in the solid obtained 00127 * by dragging a unit cube from one segment endpoint to the other. 00128 * (This solid is a warped rhombic dodecahedron.) 00129 * This amounts to 12 sidedness tests. 00130 * Also, this test works even if one or both of the segment endpoints is 00131 * inside the cube. 00132 */ 00133 extern int 00134 segment_intersects_cube(const float v0[3], const float v1[3]) 00135 { 00136 int i, iplus1, iplus2, edgevec_signs[3]; 00137 float edgevec[3]; 00138 00139 VMV3(edgevec, v1, v0); 00140 00141 FOR(i,3) 00142 edgevec_signs[i] = SIGN_NONZERO(edgevec[i]); 00143 00144 /* 00145 * Test the three cube faces on the v1-ward side of the cube-- 00146 * if v0 is outside any of their planes then there is no intersection. 00147 * Also test the three cube faces on the v0-ward side of the cube-- 00148 * if v1 is outside any of their planes then there is no intersection. 00149 */ 00150 00151 FOR(i,3) { 00152 if (v0[i] * edgevec_signs[i] > .5) return 0; 00153 if (v1[i] * edgevec_signs[i] < -.5) return 0; 00154 } 00155 00156 /* 00157 * Okay, that's the six easy faces of the rhombic dodecahedron 00158 * out of the way. Six more to go. 00159 * The remaining six planes bound an infinite hexagonal prism 00160 * joining the petrie polygons (skew hexagons) of the two cubes 00161 * centered at the endpoints. 00162 */ 00163 00164 FOR(i,3) { 00165 float rhomb_normal_dot_v0, rhomb_normal_dot_cubedge; 00166 00167 iplus1 = (i+1)%3; 00168 iplus2 = (i+2)%3; 00169 00170 #ifdef THE_EASY_TO_UNDERSTAND_WAY 00171 00172 { 00173 float rhomb_normal[3], cubedge_midpoint[3]; 00174 00175 /* 00176 * rhomb_normal = VXV3(edgevec, unit vector in direction i), 00177 * being cavalier about which direction it's facing 00178 */ 00179 rhomb_normal[i] = 0; 00180 rhomb_normal[iplus1] = edgevec[iplus2]; 00181 rhomb_normal[iplus2] = -edgevec[iplus1]; 00182 00183 /* 00184 * We now are describing a plane parallel to 00185 * both segment and the cube edge in question. 00186 * if |DOT3(rhomb_normal, an arbitrary point on the segment)| > 00187 * |DOT3(rhomb_normal, an arbitrary point on the cube edge in question| 00188 * then the origin is outside this pair of opposite faces. 00189 * (This is equivalent to saying that the line 00190 * containing the segment is "outside" (i.e. further away from the 00191 * origin than) the line containing the cube edge. 00192 */ 00193 00194 cubedge_midpoint[i] = 0; 00195 cubedge_midpoint[iplus1] = edgevec_signs[iplus1]*.5; 00196 cubedge_midpoint[iplus2] = -edgevec_signs[iplus2]*.5; 00197 00198 rhomb_normal_dot_v0 = DOT3(rhomb_normal, v0); 00199 rhomb_normal_dot_cubedge = DOT3(rhomb_normal,cubedge_midpoint); 00200 } 00201 00202 #else /* the efficient way */ 00203 00204 rhomb_normal_dot_v0 = edgevec[iplus2] * v0[iplus1] 00205 - edgevec[iplus1] * v0[iplus2]; 00206 00207 rhomb_normal_dot_cubedge = .5f * 00208 (edgevec[iplus2] * edgevec_signs[iplus1] + 00209 edgevec[iplus1] * edgevec_signs[iplus2]); 00210 00211 #endif /* the efficient way */ 00212 00213 if (SQR(rhomb_normal_dot_v0) > SQR(rhomb_normal_dot_cubedge)) 00214 return 0; /* origin is outside this pair of opposite planes */ 00215 } 00216 return 1; 00217 } 00218 00219 00220 00221 00222 00223 /* 00224 * Tells whether a given polygon intersects the cube of edge length 1 00225 * centered at the origin. 00226 * Always returns 1 if a polygon edge intersects the cube; 00227 * returns the multiplicity of containment otherwise. 00228 * (See explanation of polygon_contains_point_3d() above). 00229 */ 00230 extern int 00231 polygon_intersects_cube(int nverts, const float verts[/* nverts */][3], 00232 const float polynormal[3], 00233 int ,/* already_know_vertices_are_outside_cube unused*/ 00234 int already_know_edges_are_outside_cube) 00235 { 00236 int i, best_diagonal[3]; 00237 float p[3], t; 00238 00239 /* 00240 * If any edge intersects the cube, return 1. 00241 */ 00242 if (!already_know_edges_are_outside_cube) 00243 FOR(i,nverts) 00244 if (segment_intersects_cube(verts[i], verts[(i+1)%nverts])) 00245 return 1; 00246 00247 /* 00248 * If the polygon normal is zero and none of its edges intersect the 00249 * cube, then it doesn't intersect the cube 00250 */ 00251 if (ISZEROVEC3(polynormal)) 00252 return 0; 00253 00254 /* 00255 * Now that we know that none of the polygon's edges intersects the cube, 00256 * deciding whether the polygon intersects the cube amounts 00257 * to testing whether any of the four cube diagonals intersects 00258 * the interior of the polygon. 00259 * 00260 * Notice that we only need to consider the cube diagonal that comes 00261 * closest to being perpendicular to the plane of the polygon. 00262 * If the polygon intersects any of the cube diagonals, 00263 * it will intersect that one. 00264 */ 00265 00266 FOR(i,3) 00267 best_diagonal[i] = SIGN_NONZERO(polynormal[i]); 00268 00269 /* 00270 * Okay, we have the diagonal of interest. 00271 * The plane containing the polygon is the set of all points p satisfying 00272 * DOT3(polynormal, p) == DOT3(polynormal, verts[0]) 00273 * So find the point p on the cube diagonal of interest 00274 * that satisfies this equation. 00275 * The line containing the cube diagonal is described parametrically by 00276 * t * best_diagonal 00277 * so plug this into the previous equation and solve for t. 00278 * DOT3(polynormal, t * best_diagonal) == DOT3(polynormal, verts[0]) 00279 * i.e. 00280 * t = DOT3(polynormal, verts[0]) / DOT3(polynormal, best_diagonal) 00281 * 00282 * (Note that the denominator is guaranteed to be nonzero, since 00283 * polynormal is nonzero and best_diagonal was chosen to have the largest 00284 * magnitude dot-product with polynormal) 00285 */ 00286 t = DOT3(polynormal, verts[0]) 00287 / DOT3(polynormal, best_diagonal); 00288 00289 if (!IN_CLOSED_INTERVAL(-.5, t, .5)) 00290 return 0; /* intersection point is not in cube */ 00291 00292 SXV3(p, t, best_diagonal); /* p = t * best_diagonal */ 00293 00294 return polygon_contains_point_3d(nverts, verts, polynormal, p); 00295 } 00296 00297 extern float * 00298 get_polygon_normal(float normal[3], 00299 int nverts, const float verts[/* nverts */][3]) 00300 { 00301 int i; 00302 float tothis[3], toprev[3], cross[3]; 00303 00304 /* 00305 * Triangulate the polygon and sum up the nverts-2 triangle normals. 00306 */ 00307 ZEROVEC3(normal); 00308 VMV3(toprev, verts[1], verts[0]); /* 3 subtracts */ 00309 for (i = 2; i <= nverts-1; ++i) { /* n-2 times... */ 00310 VMV3(tothis, verts[i], verts[0]); /* 3 subtracts */ 00311 VXV3(cross, toprev, tothis); /* 3 subtracts, 6 multiplies */ 00312 VPV3(normal, normal, cross); /* 3 adds */ 00313 SET3(toprev, tothis); 00314 } 00315 return normal; 00316 } 00317 00318 } 00319 } 00320 }
1.5.7.1