Blender  V2.59
BOP_MathUtils.cpp
Go to the documentation of this file.
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 }