Blender V2.61 - r43446

BOP_MathUtils.cpp

Go to the documentation of this file.
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 }