Blender V2.61 - r43446
|
00001 /* 00002 * 00003 * 00004 * ***** BEGIN GPL LICENSE BLOCK ***** 00005 * 00006 * This program is free software; you can redistribute it and/or 00007 * modify it under the terms of the GNU General Public License 00008 * as published by the Free Software Foundation; either version 2 00009 * of the License, or (at your option) any later version. 00010 * 00011 * This program is distributed in the hope that it will be useful, 00012 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00014 * GNU General Public License for more details. 00015 * 00016 * You should have received a copy of the GNU General Public License 00017 * along with this program; if not, write to the Free Software Foundation, 00018 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 00019 * 00020 * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. 00021 * All rights reserved. 00022 * 00023 * The Original Code is: all of this file. 00024 * 00025 * Contributor(s): Marc Freixas, Ken Hughes 00026 * 00027 * ***** END GPL LICENSE BLOCK ***** 00028 */ 00029 00035 #include "BOP_MathUtils.h" 00036 #include <iostream> 00037 00044 int BOP_comp(const MT_Scalar A, const MT_Scalar B) 00045 { 00046 #ifndef VAR_EPSILON 00047 if (A >= B + BOP_EPSILON) return 1; 00048 else if (B >= A + BOP_EPSILON) return -1; 00049 else return 0; 00050 #else 00051 int expA, expB; 00052 float mant; 00053 frexp(A, &expA); /* get exponents of each number */ 00054 frexp(B, &expB); 00055 00056 if(expA < expB) /* find the larger exponent */ 00057 expA = expB; 00058 mant = frexp((A-B), &expB); /* get exponent of the difference */ 00059 /* mantissa will only be zero is (A-B) is really zero; otherwise, also 00060 * also allow a "reasonably" small exponent or "reasonably large" 00061 * difference in exponents to be considers "close to zero" */ 00062 if( mant == 0 || expB < -30 || expA - expB > 31) return 0; 00063 else if( mant > 0) return 1; 00064 else return -1; 00065 #endif 00066 } 00067 00073 int BOP_comp0(const MT_Scalar A) 00074 { 00075 if (A >= BOP_EPSILON) return 1; 00076 else if (0 >= A + BOP_EPSILON) return -1; 00077 else return 0; 00078 } 00079 00086 int BOP_comp(const MT_Tuple3& A, const MT_Tuple3& B) 00087 { 00088 #ifndef VAR_EPSILON 00089 if (A.x() >= (B.x() + BOP_EPSILON)) return 1; 00090 else if (B.x() >= (A.x() + BOP_EPSILON)) return -1; 00091 else if (A.y() >= (B.y() + BOP_EPSILON)) return 1; 00092 else if (B.y() >= (A.y() + BOP_EPSILON)) return -1; 00093 else if (A.z() >= (B.z() + BOP_EPSILON)) return 1; 00094 else if (B.z() >= (A.z() + BOP_EPSILON)) return -1; 00095 else return 0; 00096 #else 00097 int result = BOP_comp(A.x(), B.x()); 00098 if (result != 0) return result; 00099 result = BOP_comp(A.y(), B.y()); 00100 if (result != 0) return result; 00101 return BOP_comp(A.z(), B.z()); 00102 #endif 00103 } 00104 00111 int BOP_exactComp(const MT_Scalar A, const MT_Scalar B) 00112 { 00113 if (A > B) return 1; 00114 else if (B > A) return -1; 00115 else return 0; 00116 } 00123 int BOP_exactComp(const MT_Tuple3& A, const MT_Tuple3& B) 00124 { 00125 if (A.x() > B.x()) return 1; 00126 else if (B.x() > A.x()) return -1; 00127 else if (A.y() > B.y()) return 1; 00128 else if (B.y() > A.y()) return -1; 00129 else if (A.z() > B.z()) return 1; 00130 else if (B.z() > A.z()) return -1; 00131 else return 0; 00132 } 00133 00141 bool BOP_between(const MT_Point3& p1, const MT_Point3& p2, const MT_Point3& p3) 00142 { 00143 MT_Scalar distance = p2.distance(p3); 00144 return (p1.distance(p2) < distance && p1.distance(p3) < distance) && BOP_collinear(p1,p2,p3); 00145 } 00146 00154 bool BOP_collinear(const MT_Point3& p1, const MT_Point3& p2, const MT_Point3& p3) 00155 { 00156 if( BOP_comp(p1,p2) == 0 || BOP_comp(p2,p3) == 0 ) return true; 00157 00158 MT_Vector3 v1 = p2 - p1; 00159 MT_Vector3 v2 = p3 - p2; 00160 00161 /* normalize vectors before taking their cross product, so its length 00162 * has some actual meaning */ 00163 // if(MT_fuzzyZero(v1.length()) || MT_fuzzyZero(v2.length())) return true; 00164 v1.normalize(); 00165 v2.normalize(); 00166 00167 MT_Vector3 w = v1.cross(v2); 00168 00169 return (BOP_fuzzyZero(w.x()) && BOP_fuzzyZero(w.y()) && BOP_fuzzyZero(w.z())); 00170 } 00171 00176 bool BOP_convex(const MT_Point3& p1, const MT_Point3& p2, const MT_Point3& p3, const MT_Point3& p4) 00177 { 00178 MT_Vector3 v1 = p3 - p1; 00179 MT_Vector3 v2 = p4 - p2; 00180 MT_Vector3 quadPlane = v1.cross(v2); 00181 // plane1 is the perpendicular plane that contains the quad diagonal (p2,p4) 00182 MT_Plane3 plane1(quadPlane.cross(v2),p2); 00183 // if p1 and p3 are classified in the same region, the quad is not convex 00184 if (BOP_classify(p1,plane1) == BOP_classify(p3,plane1)) return false; 00185 else { 00186 // Test the other quad diagonal (p1,p3) and perpendicular plane 00187 MT_Plane3 plane2(quadPlane.cross(v1),p1); 00188 // if p2 and p4 are classified in the same region, the quad is not convex 00189 return (BOP_classify(p2,plane2) != BOP_classify(p4,plane2)); 00190 } 00191 } 00192 00198 int BOP_concave(const MT_Point3& p1, const MT_Point3& p2, const MT_Point3& p3, const MT_Point3& p4) 00199 { 00200 MT_Vector3 v1 = p3 - p1; 00201 MT_Vector3 v2 = p4 - p2; 00202 MT_Vector3 quadPlane = v1.cross(v2); 00203 // plane1 is the perpendicular plane that contains the quad diagonal (p2,p4) 00204 MT_Plane3 plane1(quadPlane.cross(v2),p2); 00205 // if p1 and p3 are classified in the same region, the quad is not convex 00206 if (BOP_classify(p1,plane1) == BOP_classify(p3,plane1)) return 1; 00207 else { 00208 // Test the other quad diagonal (p1,p3) and perpendicular plane 00209 MT_Plane3 plane2(quadPlane.cross(v1),p1); 00210 // if p2 and p4 are classified in the same region, the quad is not convex 00211 if (BOP_classify(p2,plane2) == BOP_classify(p4,plane2)) return -1; 00212 else return 0; 00213 } 00214 } 00215 00225 bool BOP_intersect(const MT_Vector3& vL1, const MT_Point3& pL1, const MT_Vector3& vL2, 00226 const MT_Point3& pL2, MT_Point3 &intersection) 00227 { 00228 // NOTE: 00229 // If the lines aren't on the same plane, the intersection point will not be valid. 00230 // So be careful !! 00231 00232 MT_Scalar t = -1; 00233 MT_Scalar den = (vL1.y()*vL2.x() - vL1.x() * vL2.y()); 00234 00235 if (!BOP_fuzzyZero(den)) { 00236 t = (pL2.y()*vL1.x() - vL1.y()*pL2.x() + pL1.x()*vL1.y() - pL1.y()*vL1.x()) / den ; 00237 } 00238 else { 00239 den = (vL1.y()*vL2.z() - vL1.z() * vL2.y()); 00240 if (!BOP_fuzzyZero(den)) { 00241 t = (pL2.y()*vL1.z() - vL1.y()*pL2.z() + pL1.z()*vL1.y() - pL1.y()*vL1.z()) / den ; 00242 } 00243 else { 00244 den = (vL1.x()*vL2.z() - vL1.z() * vL2.x()); 00245 if (!BOP_fuzzyZero(den)) { 00246 t = (pL2.x()*vL1.z() - vL1.x()*pL2.z() + pL1.z()*vL1.x() - pL1.x()*vL1.z()) / den ; 00247 } 00248 else { 00249 return false; 00250 } 00251 } 00252 } 00253 00254 intersection.setValue(vL2.x()*t + pL2.x(), vL2.y()*t + pL2.y(), vL2.z()*t + pL2.z()); 00255 return true; 00256 } 00257 00266 bool BOP_getCircleCenter(const MT_Point3& p1, const MT_Point3& p2, const MT_Point3& p3, 00267 MT_Point3& center) 00268 { 00269 // Compute quad plane 00270 MT_Vector3 p1p2 = p2-p1; 00271 MT_Vector3 p1p3 = p3-p1; 00272 MT_Plane3 plane1(p1,p2,p3); 00273 MT_Vector3 plane = plane1.Normal(); 00274 00275 // Compute first line vector, perpendicular to plane vector and edge (p1,p2) 00276 MT_Vector3 vL1 = p1p2.cross(plane); 00277 if( MT_fuzzyZero(vL1.length() ) ) 00278 return false; 00279 vL1.normalize(); 00280 00281 // Compute first line point, middle point of edge (p1,p2) 00282 MT_Point3 pL1 = p1.lerp(p2, 0.5); 00283 00284 // Compute second line vector, perpendicular to plane vector and edge (p1,p3) 00285 MT_Vector3 vL2 = p1p3.cross(plane); 00286 if( MT_fuzzyZero(vL2.length() ) ) 00287 return false; 00288 vL2.normalize(); 00289 00290 // Compute second line point, middle point of edge (p1,p3) 00291 MT_Point3 pL2 = p1.lerp(p3, 0.5); 00292 00293 // Compute intersection (the lines lay on the same plane, so the intersection exists 00294 // only if they are not parallel!!) 00295 return BOP_intersect(vL1,pL1,vL2,pL2,center); 00296 } 00297 00307 bool BOP_isInsideCircle(const MT_Point3& p1, const MT_Point3& p2, const MT_Point3& p3, 00308 const MT_Point3& q) 00309 { 00310 MT_Point3 center; 00311 00312 // Compute circle center 00313 bool ok = BOP_getCircleCenter(p1,p2,p3,center); 00314 00315 if (!ok) return true; // p1,p2 and p3 are collinears 00316 00317 // Check if q is inside the circle 00318 MT_Scalar r = p1.distance(center); 00319 MT_Scalar d = q.distance(center); 00320 return (BOP_comp(d,r) <= 0); 00321 } 00322 00333 bool BOP_isInsideCircle(const MT_Point3& p1, const MT_Point3& p2, const MT_Point3& p3, 00334 const MT_Point3& p4, const MT_Point3& p5) 00335 { 00336 MT_Point3 center; 00337 bool ok = BOP_getCircleCenter(p1,p2,p3,center); 00338 00339 if (!ok) return true; // Collinear points! 00340 00341 // Check if p4 or p5 is inside the circle 00342 MT_Scalar r = p1.distance(center); 00343 MT_Scalar d1 = p4.distance(center); 00344 MT_Scalar d2 = p5.distance(center); 00345 return (BOP_comp(d1,r) <= 0 || BOP_comp(d2,r) <= 0); 00346 } 00347 00352 MT_Scalar BOP_orientation(const MT_Plane3& p1, const MT_Plane3& p2) 00353 { 00354 // Dot product between plane normals 00355 return (p1.x()*p2.x() + p1.y()*p2.y() + p1.z()*p2.z()); 00356 } 00357 00366 int BOP_classify(const MT_Point3& p, const MT_Plane3& plane) 00367 { 00368 // Compare plane - point distance with zero 00369 return BOP_comp0(plane.signedDistance(p)); 00370 } 00371 00379 MT_Point3 BOP_intersectPlane(const MT_Plane3& plane, const MT_Point3& p1, const MT_Point3& p2) 00380 { 00381 // Compute intersection between plane and line ... 00382 // 00383 // L: (p2-p1)lambda + p1 00384 // 00385 // supposes resolve equation ... 00386 // 00387 // coefA*((p2.x - p1.y)*lambda + p1.x) + ... + coefD = 0 00388 00389 MT_Point3 intersection = MT_Point3(0,0,0); //never ever return anything undefined! 00390 MT_Scalar den = plane.x()*(p2.x()-p1.x()) + 00391 plane.y()*(p2.y()-p1.y()) + 00392 plane.z()*(p2.z()-p1.z()); 00393 if (den != 0) { 00394 MT_Scalar lambda = (-plane.x()*p1.x()-plane.y()*p1.y()-plane.z()*p1.z()-plane.w()) / den; 00395 intersection.setValue(p1.x() + (p2.x()-p1.x())*lambda, 00396 p1.y() + (p2.y()-p1.y())*lambda, 00397 p1.z() + (p2.z()-p1.z())*lambda); 00398 return intersection; 00399 } 00400 return intersection; 00401 } 00402 00409 bool BOP_containsPoint(const MT_Plane3& plane, const MT_Point3& point) 00410 { 00411 return BOP_fuzzyZero(plane.signedDistance(point)); 00412 } 00413 00438 MT_Point3 BOP_4PointIntersect(const MT_Point3& p0, const MT_Point3& p1, const MT_Point3& p2, 00439 const MT_Point3& q) 00440 { 00441 MT_Vector3 v(p0.x()-p1.x(), p0.y()-p1.y(), p0.z()-p1.z()); 00442 MT_Vector3 w(p2.x()-q.x(), p2.y()-q.y(), p2.z()-q.z()); 00443 MT_Point3 I; 00444 00445 BOP_intersect(v,p0,w,p2,I); 00446 return I; 00447 } 00448 00461 MT_Scalar BOP_EpsilonDistance(const MT_Point3& p0, const MT_Point3& p1, const MT_Point3& q) 00462 { 00463 MT_Scalar d0 = p0.distance(p1); 00464 MT_Scalar d1 = p0.distance(q); 00465 MT_Scalar d; 00466 00467 if (BOP_fuzzyZero(d0)) d = 1.0; 00468 else if (BOP_fuzzyZero(d1)) d = 0.0; 00469 else d = d1 / d0; 00470 return d; 00471 }