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