Elements.cpp

Go to the documentation of this file.
00001 /***************************************************************************
00002  *   Copyright (c) 2005 Imetric 3D GmbH                                    *
00003  *                                                                         *
00004  *   This file is part of the FreeCAD CAx development system.              *
00005  *                                                                         *
00006  *   This library is free software; you can redistribute it and/or         *
00007  *   modify it under the terms of the GNU Library General Public           *
00008  *   License as published by the Free Software Foundation; either          *
00009  *   version 2 of the License, or (at your option) any later version.      *
00010  *                                                                         *
00011  *   This library  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 Library General Public License for more details.                  *
00015  *                                                                         *
00016  *   You should have received a copy of the GNU Library General Public     *
00017  *   License along with this library; see the file COPYING.LIB. If not,    *
00018  *   write to the Free Software Foundation, Inc., 59 Temple Place,         *
00019  *   Suite 330, Boston, MA  02111-1307, USA                                *
00020  *                                                                         *
00021  ***************************************************************************/
00022 
00023 
00024 #include "PreCompiled.h"
00025 
00026 #ifndef _PreComp_
00027 #endif
00028 
00029 #include <Mod/Mesh/App/WildMagic4/Wm4IntrSegment3Plane3.h>
00030 #include <Mod/Mesh/App/WildMagic4/Wm4IntrSegment3Box3.h>
00031 #include <Mod/Mesh/App/WildMagic4/Wm4DistVector3Triangle3.h>
00032 #include <Mod/Mesh/App/WildMagic4/Wm4DistSegment3Triangle3.h>
00033 
00034 #include "Elements.h"
00035 #include "Algorithm.h"
00036 #include "tritritest.h"
00037 
00038 using namespace MeshCore;
00039 using namespace Wm4;
00040 
00041 unsigned long MeshPointArray::Get (const MeshPoint &rclPoint)
00042 {
00043   iterator clIter;
00044 
00045   clIter = std::find(begin(), end(), rclPoint);
00046   if (clIter != end())
00047     return clIter - begin();
00048   else
00049     return ULONG_MAX;  
00050 }
00051 
00052 unsigned long MeshPointArray::GetOrAddIndex (const MeshPoint &rclPoint)
00053 {
00054   unsigned long ulIndex;
00055 
00056   if ((ulIndex = Get(rclPoint)) == ULONG_MAX)
00057   {
00058     push_back(rclPoint);
00059     return (unsigned long)(size() - 1);
00060   }
00061   else
00062     return ulIndex;
00063 }
00064 
00065 void MeshPointArray::SetFlag (MeshPoint::TFlagType tF) const
00066 {
00067   for (MeshPointArray::_TConstIterator i = begin(); i < end(); i++) i->SetFlag(tF);
00068 }
00069 
00070 void MeshPointArray::ResetFlag (MeshPoint::TFlagType tF) const
00071 {
00072   for (MeshPointArray::_TConstIterator i = begin(); i < end(); i++) i->ResetFlag(tF);
00073 }
00074 
00075 void MeshPointArray::SetProperty (unsigned long ulVal) const
00076 {
00077   for (_TConstIterator pP = begin(); pP != end(); pP++) pP->SetProperty(ulVal);
00078 }
00079 
00080 void MeshPointArray::ResetInvalid (void) const
00081 {
00082   for (_TConstIterator pP = begin(); pP != end(); pP++) pP->ResetInvalid();
00083 }
00084 
00085 MeshPointArray& MeshPointArray::operator = (const MeshPointArray &rclPAry)
00086 {
00087 //  std::vector<MeshPoint>::operator=(rclPAry);
00088   TMeshPointArray::operator=(rclPAry);
00089 
00090   return *this;
00091 }
00092 
00093 void MeshFacetArray::Erase (_TIterator pIter)
00094 {
00095   unsigned long i, *pulN;
00096   _TIterator  pPass, pEnd;
00097   unsigned long ulInd = pIter - begin();
00098   erase(pIter);
00099   pPass = begin();
00100   pEnd  = end();
00101   while (pPass < pEnd)
00102   {
00103     for (i = 0; i < 3; i++)
00104     {
00105       pulN = &pPass->_aulNeighbours[i];
00106       if ((*pulN > ulInd) && (*pulN != ULONG_MAX))
00107         (*pulN)--;
00108     }
00109     pPass++;
00110   }
00111 }
00112 
00113 void MeshFacetArray::TransposeIndices (unsigned long ulOrig, unsigned long ulNew)
00114 {
00115   _TIterator  pIter = begin(), pEnd = end();
00116 
00117   while (pIter < pEnd)
00118   {
00119     pIter->Transpose(ulOrig, ulNew);
00120     ++pIter;  
00121   }
00122 }
00123 
00124 void MeshFacetArray::DecrementIndices (unsigned long ulIndex)
00125 {
00126   _TIterator  pIter = begin(), pEnd = end();
00127 
00128   while (pIter < pEnd)
00129   {
00130     pIter->Decrement(ulIndex);
00131     ++pIter;  
00132   }
00133 }
00134 
00135 void MeshFacetArray::SetFlag (MeshFacet::TFlagType tF) const
00136 {
00137   for (MeshFacetArray::_TConstIterator i = begin(); i < end(); i++) i->SetFlag(tF);
00138 }
00139 
00140 void MeshFacetArray::ResetFlag (MeshFacet::TFlagType tF) const
00141 {
00142   for (MeshFacetArray::_TConstIterator i = begin(); i < end(); i++) i->ResetFlag(tF);
00143 }
00144 
00145 void MeshFacetArray::SetProperty (unsigned long ulVal) const
00146 {
00147   for (_TConstIterator pF = begin(); pF != end(); pF++) pF->SetProperty(ulVal);
00148 }
00149 
00150 void MeshFacetArray::ResetInvalid (void) const
00151 {
00152   for (_TConstIterator pF = begin(); pF != end(); pF++) pF->ResetInvalid();
00153 }
00154 
00155 MeshFacetArray& MeshFacetArray::operator = (const MeshFacetArray &rclFAry)
00156 {
00157   TMeshFacetArray::operator=(rclFAry);
00158   return *this;
00159 }
00160 
00161 // -----------------------------------------------------------------
00162 
00163 bool MeshGeomEdge::ContainedByOrIntersectBoundingBox ( const Base::BoundBox3f &rclBB ) const
00164 {
00165   // Test, ob alle Eckpunkte der Edge sich auf einer der 6 Seiten der BB befinden
00166   if ((GetBoundBox() && rclBB) == false)
00167     return false;
00168 
00169   // Test, ob Edge-BB komplett in BB liegt
00170   if (rclBB.IsInBox(GetBoundBox()))
00171     return true;
00172 
00173   // Test, ob einer der Eckpunkte in BB liegt
00174   for (int i=0;i<2;i++)
00175   {
00176     if (rclBB.IsInBox(_aclPoints[i]))
00177       return true;
00178   }
00179 
00180   // "echter" Test auf Schnitt
00181   if (IntersectBoundingBox(rclBB))
00182     return true;
00183 
00184   return false;
00185 }
00186 
00187 Base::BoundBox3f MeshGeomEdge::GetBoundBox () const
00188 {
00189   return Base::BoundBox3f(_aclPoints,2);
00190 }
00191 
00192 bool MeshGeomEdge::IntersectBoundingBox (const Base::BoundBox3f &rclBB) const
00193 {
00194   const Base::Vector3f& rclP0 = _aclPoints[0];
00195   const Base::Vector3f& rclP1 = _aclPoints[1];
00196 
00197   Vector3<float> A(rclP0.x, rclP0.y, rclP0.z);
00198   Vector3<float> B(rclP1.x, rclP1.y, rclP1.z);
00199 
00200   Vector3<float> n = B - A;
00201   float len = n.Length();
00202   n.Normalize();
00203   Vector3<float> p = 0.5f*(A + B);
00204 
00205   Segment3<float> akSeg(p, n, 0.5f*len);
00206 
00207   Base::Vector3f clCenter  = rclBB.CalcCenter();
00208   Vector3<float> center(clCenter.x, clCenter.y, clCenter.z);
00209   Vector3<float> axis0(1.0f, 0.0f, 0.0f);
00210   Vector3<float> axis1(0.0f, 1.0f, 0.0f);
00211   Vector3<float> axis2(0.0f, 0.0f, 1.0f);
00212   float extent0 = 0.5f*rclBB.LengthX();
00213   float extent1 = 0.5f*rclBB.LengthY();
00214   float extent2 = 0.5f*rclBB.LengthZ();
00215 
00216   Box3<float> kBox(center, axis0, axis1, axis2, extent0, extent1, extent2);
00217 
00218   IntrSegment3Box3<float> intrsectbox(akSeg, kBox, false);
00219   return intrsectbox.Test();
00220 }
00221 
00222 // -----------------------------------------------------------------
00223 
00224 MeshGeomFacet::MeshGeomFacet (void) 
00225   : _bNormalCalculated(false),
00226     _ucFlag(0), _ulProp(0)
00227 { 
00228 
00229 }
00230 
00231 
00232 MeshGeomFacet::MeshGeomFacet (const Base::Vector3f &v1,const Base::Vector3f &v2,const Base::Vector3f &v3)
00233   : _bNormalCalculated(false), 
00234     _ucFlag(0),
00235     _ulProp(0)
00236 {
00237   _aclPoints[0] = v1;
00238   _aclPoints[1] = v2;
00239   _aclPoints[2] = v3;
00240 }
00241 
00242 
00243 
00244 bool MeshGeomFacet::IsPointOf (const Base::Vector3f &rclPoint, float fDistance) const
00245 {
00246   if (DistancePlaneToPoint(rclPoint) > fDistance)
00247     return false;
00248 
00249   // force internal normal to be computed if not done yet
00250   Base::Vector3f clNorm(GetNormal()), clProjPt(rclPoint), clEdge;
00251   Base::Vector3f clP0(_aclPoints[0]), clP1(_aclPoints[1]), clP2(_aclPoints[2]);
00252   float     fLP, fLE;
00253 
00254   clNorm.Normalize();
00255   clProjPt.ProjToPlane(_aclPoints[0], clNorm);
00256 
00257     
00258   // Kante P0 --> P1
00259   clEdge = clP1 - clP0;
00260   fLP = clProjPt.DistanceToLine(clP0, clEdge); 
00261   if (fLP > 0.0f)
00262   {
00263     fLE = clP2.DistanceToLine(clP0, clEdge);
00264     if (fLP <= fLE)
00265     {
00266       if (clProjPt.DistanceToLine(clP2, clEdge) > fLE)
00267         return false;
00268     }
00269     else
00270       return false;
00271   }      
00272 
00273   // Kante P0 --> P2
00274   clEdge = clP2 - clP0;
00275   fLP = clProjPt.DistanceToLine(clP0, clEdge); 
00276   if (fLP > 0.0f)
00277   {
00278     fLE = clP1.DistanceToLine(clP0, clEdge);
00279     if (fLP <= fLE)
00280     {
00281       if (clProjPt.DistanceToLine(clP1, clEdge) > fLE) 
00282         return false;
00283     }
00284     else
00285       return false;
00286   }      
00287 
00288   // Kante P1 --> P2
00289   clEdge = clP2 - clP1;
00290   fLP = clProjPt.DistanceToLine(clP1, clEdge); 
00291   if (fLP > 0.0f)
00292   {
00293     fLE = clP0.DistanceToLine(clP1, clEdge);
00294     if (fLP <= fLE)
00295     {
00296       if (clProjPt.DistanceToLine(clP0, clEdge) > fLE) 
00297         return false;
00298     }
00299     else
00300       return false;
00301   }      
00302 
00303   return true;
00304 }
00305 
00306 bool MeshGeomFacet::IsPointOfFace (const Base::Vector3f& rclP, float fDistance) const
00307 {
00308   // effektivere Implementierung als in MeshGeomFacet::IsPointOf
00309   //
00310   Base::Vector3f a(_aclPoints[0].x, _aclPoints[0].y, _aclPoints[0].z);
00311   Base::Vector3f b(_aclPoints[1].x, _aclPoints[1].y, _aclPoints[1].z);
00312   Base::Vector3f c(_aclPoints[2].x, _aclPoints[2].y, _aclPoints[2].z);
00313   Base::Vector3f p(rclP);
00314 
00315   Base::Vector3f n  = (b - a) % (c - a);
00316   Base::Vector3f n1 = (a - p) % (b - p);
00317   Base::Vector3f n2 = (c - p) % (a - p);
00318   Base::Vector3f n3 = (b - p) % (c - p);
00319 
00320   if (n * (p - a) > fDistance * n.Length())
00321     return false;
00322 
00323   if (n * (a - p) > fDistance * n.Length())
00324     return false;
00325 
00326   if (n * n1 <= 0.0f)
00327     return false;
00328 
00329   if (n * n2 <= 0.0f)
00330     return false;
00331 
00332   if (n * n3 <= 0.0f)
00333     return false;
00334 
00335   return true;
00336 }
00337 
00338 bool MeshGeomFacet::Weights(const Base::Vector3f& rclP, float& w0, float& w1, float& w2) const
00339 {
00340   float fAreaABC = Area();
00341   float fAreaPBC = MeshGeomFacet(rclP,_aclPoints[1],_aclPoints[2]).Area();
00342   float fAreaPCA = MeshGeomFacet(rclP,_aclPoints[2],_aclPoints[0]).Area();
00343   float fAreaPAB = MeshGeomFacet(rclP,_aclPoints[0],_aclPoints[1]).Area();
00344 
00345   w0=fAreaPBC/fAreaABC;
00346   w1=fAreaPCA/fAreaABC;
00347   w2=fAreaPAB/fAreaABC;
00348 
00349   return fabs(w0+w1+w2-1.0f)<0.001f;
00350 }
00351 
00352 void MeshGeomFacet::ProjectPointToPlane (Base::Vector3f &rclPoint) const
00353 {
00354   rclPoint.ProjToPlane(_aclPoints[0], GetNormal());
00355 }
00356 
00357 void MeshGeomFacet::ProjectFacetToPlane (MeshGeomFacet &rclFacet) const
00358 {
00359   // project facet 2 onto facet 1
00360   IntersectPlaneWithLine( rclFacet._aclPoints[0], GetNormal(), rclFacet._aclPoints[0] );
00361   IntersectPlaneWithLine( rclFacet._aclPoints[1], GetNormal(), rclFacet._aclPoints[1] );
00362   IntersectPlaneWithLine( rclFacet._aclPoints[2], GetNormal(), rclFacet._aclPoints[2] );
00363 }
00364 
00365 void MeshGeomFacet::Enlarge (float fDist)
00366 {
00367   Base::Vector3f  clM, clU, clV, clPNew[3];
00368   float      fA, fD;
00369   unsigned long i, ulP1, ulP2, ulP3;
00370 
00371   for (i = 0; i < 3; i++)
00372   {
00373     ulP1  = i;
00374     ulP2  = (i + 1) % 3;
00375     ulP3  = (i + 2) % 3;
00376     clU   = _aclPoints[ulP2] - _aclPoints[ulP1];
00377     clV   = _aclPoints[ulP3] - _aclPoints[ulP1];
00378     clM   = -(clU + clV);
00379     fA    = clM.GetAngle(-clU);
00380     fD    = fDist / float(sin(fA));
00381     clM.Normalize();
00382     clM.Scale(fD, fD, fD);
00383     clPNew[ulP1] = _aclPoints[ulP1] + clM;
00384   }
00385 
00386   _aclPoints[0] = clPNew[0];
00387   _aclPoints[1] = clPNew[1];
00388   _aclPoints[2] = clPNew[2];
00389 }
00390 
00391 bool MeshGeomFacet::IsDegenerated() const
00392 {
00393     // The triangle has the points A,B,C where we can define the vector u and v
00394     // u = b-a and v = c-a. Then we define the line g: r = a+t*u and the plane
00395     // E: (x-c)*u=0. The intersection point of g and E is S.
00396     // The vector to S can be computed with a+(uv)/(uu)*u. The difference of 
00397     // C and S then is v-(u*v)/(u*u)*u. The square distance leads to the formula
00398     // (v-(u*v)/(u*u)*u)^2 < eps which means that C and S is considered equal if
00399     // the square distance is less than an epsilon and thus the triangle is de-
00400     // generated.
00401     // After a few calculation step we get the formula:
00402     // (u*u)*(v*v)-(u*v)*(u*v) < eps*(u*u)
00403     // So, if we do the same except that we define a line h which goes through
00404     // A and C and a plane going through B we get a similar formula:
00405     // (u*u)*(v*v)-(u*v)*(u*v) < eps*(v*v).
00406     // As end formula we can write then:
00407     // (u*u)*(v*v)-(u*v)*(u*v) < max(eps*(u*u),eps*(v*v)).
00408     //
00409     // BTW (u*u)*(v*v)-(u*v)*(u*v) is the same as (uxv)*(uxv).
00410     Base::Vector3f u = _aclPoints[1] - _aclPoints[0];
00411     Base::Vector3f v = _aclPoints[2] - _aclPoints[0];
00412     float eps = MeshDefinitions::_fMinPointDistanceP2;
00413     float uu = u*u; if (uu < eps) return true;
00414     float vv = v*v; if (vv < eps) return true;
00415     float uv = u*v;
00416     if (uu*vv-uv*uv < eps*std::max<float>(uu,vv))
00417         return true;
00418     return false;
00419 }
00420 
00421 bool MeshGeomFacet::IsDeformed() const
00422 {
00423   float fCosAngle;
00424   Base::Vector3f u,v;
00425 
00426   for (int i=0; i<3; i++)
00427   {
00428     u = _aclPoints[(i+1)%3]-_aclPoints[i];
00429     v = _aclPoints[(i+2)%3]-_aclPoints[i];
00430     u.Normalize();
00431     v.Normalize();
00432 
00433     fCosAngle = u * v;
00434 
00435     // x < 30° => cos(x) > sqrt(3)/2 or x > 120° => cos(x) < -0.5
00436     if (fCosAngle > 0.86f || fCosAngle < -0.5f)
00437       return true;
00438   }
00439 
00440   return false;
00441 }
00442 
00443 bool MeshGeomFacet::IntersectBoundingBox ( const Base::BoundBox3f &rclBB ) const
00444 {
00445   // the triangle's corner points
00446   const Base::Vector3f& v0 = _aclPoints[0];
00447   const Base::Vector3f& v1 = _aclPoints[1];
00448   const Base::Vector3f& v2 = _aclPoints[2];
00449 
00450   // first check if at least one point is inside the box
00451   if ( rclBB.IsInBox( v0 ) || rclBB.IsInBox( v1 ) || rclBB.IsInBox( v2 ) )
00452     return true;
00453 
00454   // edge lengths
00455   float len0 = (v0-v1).Length();
00456   float len1 = (v1-v2).Length();
00457   float len2 = (v2-v0).Length();
00458 
00459   // Build up the line segments
00460   Vector3<float> p0(0.5f*(v0.x+v1.x), 0.5f*(v0.y+v1.y), 0.5f*(v0.z+v1.z));
00461   Vector3<float> p1(0.5f*(v1.x+v2.x), 0.5f*(v1.y+v2.y), 0.5f*(v1.z+v2.z));
00462   Vector3<float> p2(0.5f*(v2.x+v0.x), 0.5f*(v2.y+v0.y), 0.5f*(v2.z+v0.z));
00463 
00464   Vector3<float> d0(v1.x - v0.x, v1.y - v0.y, v1.z - v0.z);
00465   d0.Normalize();
00466   Vector3<float> d1(v2.x - v1.x, v2.y - v1.y, v2.z - v1.z);
00467   d1.Normalize();
00468   Vector3<float> d2(v0.x - v2.x, v0.y - v2.y, v0.z - v2.z);
00469   d2.Normalize();
00470 
00471   Segment3<float> akSeg0(p0, d0, len0/2.0f  );
00472   Segment3<float> akSeg1(p1, d1, len1/2.0f);
00473   Segment3<float> akSeg2(p2, d2, len2/2.0f);
00474 
00475   // Build up the box
00476   Base::Vector3f clCenter  = rclBB.CalcCenter();
00477   Vector3<float> center(clCenter.x, clCenter.y, clCenter.z);
00478   Vector3<float> axis0(1.0f, 0.0f, 0.0f);
00479   Vector3<float> axis1(0.0f, 1.0f, 0.0f);
00480   Vector3<float> axis2(0.0f, 0.0f, 1.0f);
00481   float extent0 = 0.5f*rclBB.LengthX();
00482   float extent1 = 0.5f*rclBB.LengthY();
00483   float extent2 = 0.5f*rclBB.LengthZ();
00484 
00485   Box3<float> akBox(center, axis0, axis1, axis2, extent0, extent1, extent2);
00486 
00487   // Check for intersection of line segments and box
00488   IntrSegment3Box3<float> akSec0(akSeg0, akBox, false);
00489   if ( akSec0.Test() )
00490     return true;
00491   IntrSegment3Box3<float> akSec1(akSeg1, akBox, false);
00492   if ( akSec1.Test() )
00493     return true;
00494   IntrSegment3Box3<float> akSec2(akSeg2, akBox, false);
00495   if ( akSec2.Test() )
00496     return true;
00497 
00498   // no intersection
00499   return false;
00500 }
00501 
00502 bool MeshGeomFacet::IntersectWithPlane (const Base::Vector3f &rclBase, const Base::Vector3f &rclNormal, Base::Vector3f &rclP1, Base::Vector3f &rclP2) const
00503 {
00504   // the triangle's corner points
00505   const Base::Vector3f& v0 = _aclPoints[0];
00506   const Base::Vector3f& v1 = _aclPoints[1];
00507   const Base::Vector3f& v2 = _aclPoints[2];
00508 
00509   // edge lengths
00510   float len0 = (v0-v1).Length();
00511   float len1 = (v1-v2).Length();
00512   float len2 = (v2-v0).Length();
00513 
00514   // Build up the line segments
00515   Vector3<float> p0(0.5f*(v0.x+v1.x), 0.5f*(v0.y+v1.y), 0.5f*(v0.z+v1.z));
00516   Vector3<float> p1(0.5f*(v1.x+v2.x), 0.5f*(v1.y+v2.y), 0.5f*(v1.z+v2.z));
00517   Vector3<float> p2(0.5f*(v2.x+v0.x), 0.5f*(v2.y+v0.y), 0.5f*(v2.z+v0.z));
00518 
00519   Vector3<float> d0(v1.x - v0.x, v1.y - v0.y, v1.z - v0.z);
00520   d0.Normalize();
00521   Vector3<float> d1(v2.x - v1.x, v2.y - v1.y, v2.z - v1.z);
00522   d1.Normalize();
00523   Vector3<float> d2(v0.x - v2.x, v0.y - v2.y, v0.z - v2.z);
00524   d2.Normalize();
00525 
00526   Segment3<float> akSeg0(p0, d0, len0/2.0f  );
00527   Segment3<float> akSeg1(p1, d1, len1/2.0f);
00528   Segment3<float> akSeg2(p2, d2, len2/2.0f);
00529 
00530   // Build up the plane
00531   Vector3<float> p(rclBase.x, rclBase.y, rclBase.z);
00532   Vector3<float> n(rclNormal.x, rclNormal.y, rclNormal.z);
00533   Plane3<float> akPln(n, p);
00534 
00535   // Check for intersection with plane for each line segment
00536   IntrSegment3Plane3<float> test0(akSeg0, akPln);
00537   IntrSegment3Plane3<float> test1(akSeg1, akPln);
00538   IntrSegment3Plane3<float> test2(akSeg2, akPln);
00539 
00540   Vector3<float> intr;
00541   if ( test0.Find() )
00542   {
00543     intr = p0 + test0.GetSegmentT() * d0; 
00544     rclP1.Set( intr[0], intr[1], intr[2]);
00545 
00546     if ( test1.Find() )
00547     {
00548       intr = p1 + test1.GetSegmentT() * d1; 
00549       rclP2.Set( intr[0], intr[1], intr[2]);
00550       return true;
00551     }
00552     else if ( test2.Find() )
00553     {
00554       intr = p2 + test2.GetSegmentT() * d2; 
00555       rclP2.Set( intr[0], intr[1], intr[2]);
00556       return true;
00557     }
00558   }
00559   else if ( test1.Find() )
00560   {
00561     intr = p1 + test1.GetSegmentT() * d1; 
00562     rclP1.Set( intr[0], intr[1], intr[2]);
00563 
00564     if ( test2.Find() )
00565     {
00566       intr = p2 + test2.GetSegmentT() * d2; 
00567       rclP2.Set( intr[0], intr[1], intr[2]);
00568       return true;
00569     }
00570   }
00571 
00572   return false;
00573 }
00574 
00575 bool MeshGeomFacet::Foraminate (const Base::Vector3f &P, const Base::Vector3f &dir, Base::Vector3f &I, float fMaxAngle) const
00576 {
00577     const float eps = 1e-06f;
00578     Base::Vector3f n = this->GetNormal();
00579 
00580     // check angle between facet normal and the line direction, FLOAT_MAX is
00581     // returned for degenerated facets
00582     if (dir.GetAngle(n) > fMaxAngle)
00583         return false;
00584 
00585     float nn = n * n;
00586     float nd = n * dir;
00587     float dd = dir * dir;
00588 
00589     // the line mustn't be parallel to the triangle
00590     if ((nd * nd) <= (eps * dd * nn))
00591         return false;
00592 
00593     Base::Vector3f u = this->_aclPoints[1] - this->_aclPoints[0];
00594     Base::Vector3f v = this->_aclPoints[2] - this->_aclPoints[0];
00595 
00596     Base::Vector3f w0 = P - this->_aclPoints[0];
00597     float r = -(n * w0) / nd;
00598     Base::Vector3f  w = w0 + r * dir;
00599 
00600     float uu = u * u;
00601     float uv = u * v;
00602     float vv = v * v;
00603     float wu = w * u;
00604     float wv = w * v;
00605     float det = float(fabs((uu * vv) - (uv * uv)));
00606 
00607     float s  = (vv * wu) - (uv * wv);
00608     float t  = (uu * wv) - (uv * wu);
00609 
00610     // is the intersection point inside the triangle?
00611     if ((s >= 0.0f) && (t >= 0.0f) && ((s + t) <= det)) {
00612         I = w + this->_aclPoints[0];
00613         return true;
00614     }
00615 
00616     return false;
00617 }
00618 
00619 bool MeshGeomFacet::IntersectPlaneWithLine (const Base::Vector3f &rclPt, const Base::Vector3f &rclDir, Base::Vector3f &rclRes) const
00620 {
00621   // berechne den Schnittpunkt Gerade <-> Ebene
00622   if ( fabs(rclDir * GetNormal()) < 1e-3f )
00623     return false; // line and plane are parallel
00624 
00625   float s = ( ( GetGravityPoint() - rclPt ) * GetNormal() ) 
00626             / ( rclDir * GetNormal() );
00627   rclRes = rclPt + s * rclDir;
00628 
00629   return true;
00630 }
00631 
00632 bool MeshGeomFacet::IntersectWithLine (const Base::Vector3f &rclPt, const Base::Vector3f &rclDir, Base::Vector3f &rclRes) const
00633 {
00634   if ( !IntersectPlaneWithLine( rclPt, rclDir, rclRes ) )
00635     return false; // line and plane are parallel
00636   // Check if the intersection point is inside the facet
00637   return IsPointOfFace(rclRes, 1e-03f);
00638 }
00639 
00640 float MeshGeomFacet::DistanceToLineSegment (const Base::Vector3f &rclP1, const Base::Vector3f &rclP2) const
00641 {
00642   // line segment
00643   Vector3<float> A(rclP1.x, rclP1.y, rclP1.z);
00644   Vector3<float> B(rclP2.x, rclP2.y, rclP2.z);
00645 
00646   Vector3<float> n = B - A;
00647   float len = n.Length();
00648   n.Normalize();
00649   Vector3<float> p = 0.5f*(A + B);
00650 
00651   Segment3<float> akSeg(p, n, 0.5f*len);
00652 
00653   // triangle
00654   Vector3<float>  akF0(_aclPoints[0].x, _aclPoints[0].y, _aclPoints[0].z);
00655   Vector3<float>  akF1(_aclPoints[1].x, _aclPoints[1].y, _aclPoints[1].z);
00656   Vector3<float>  akF2(_aclPoints[2].x, _aclPoints[2].y, _aclPoints[2].z);
00657 
00658   Triangle3<float> akTria(akF0, akF1, akF2);
00659 
00660   DistSegment3Triangle3<float> akDistSegTria(akSeg, akTria);
00661   return akDistSegTria.Get();
00662 }
00663 
00664 float MeshGeomFacet::DistanceToPoint (const Base::Vector3f &rclPt, Base::Vector3f &rclNt) const
00665 {
00666   Vector3<float>  akPt(rclPt.x, rclPt.y, rclPt.z);
00667   Vector3<float>  akF0(_aclPoints[0].x, _aclPoints[0].y, _aclPoints[0].z);
00668   Vector3<float>  akF1(_aclPoints[1].x, _aclPoints[1].y, _aclPoints[1].z);
00669   Vector3<float>  akF2(_aclPoints[2].x, _aclPoints[2].y, _aclPoints[2].z);
00670 
00671   Triangle3<float> akTria(akF0, akF1, akF2);
00672   DistVector3Triangle3<float> akDistPtTria(akPt, akTria);
00673   
00674   float fDist = akDistPtTria.Get();
00675 
00676   // get nearest point of the facet
00677   Vector3<float> akNt = akDistPtTria.GetClosestPoint1();
00678   rclNt.Set(akNt.X(), akNt.Y(), akNt.Z());
00679 
00680   return fDist;
00681 }
00682 
00683 void MeshGeomFacet::SubSample (float fStep, std::vector<Base::Vector3f> &rclPoints) const
00684 {
00685   std::vector<Base::Vector3f> clPoints;
00686   Base::Vector3f A = _aclPoints[0];
00687   Base::Vector3f B = _aclPoints[1];
00688   Base::Vector3f C = _aclPoints[2];
00689   Base::Vector3f clVecAB(B - A);
00690   Base::Vector3f clVecAC(C - A);
00691   Base::Vector3f clVecBC(C - B);
00692 
00693   // laengste Achse entspricht AB
00694   float fLenAB = clVecAB.Length();
00695   float fLenAC = clVecAC.Length();
00696   float fLenBC = clVecBC.Length();
00697 
00698   if (fLenAC > fLenAB)
00699   {
00700     std::swap(B, C);
00701     std::swap(fLenAB, fLenAC);
00702   }
00703   if (fLenBC > fLenAB)
00704   {
00705     std::swap(A, C);
00706     std::swap(fLenBC, fLenAB);
00707   }
00708 
00709   clVecAB = (B - A);
00710   clVecAC = (C - A);
00711   clVecBC = (C - B);
00712   Base::Vector3f clVecABNorm(clVecAB);
00713   Base::Vector3f clVecHNorm((clVecAB % clVecAC) % clVecAB);
00714   clVecABNorm.Normalize();
00715   clVecHNorm.Normalize();
00716 
00717   float bx = fLenAB;                
00718   float cy = float(sin(clVecAB.GetAngle(clVecAC)) * fLenAC);
00719   float cx = float(sqrt(fabs(fLenAC * fLenAC - cy * cy)));
00720  
00721   float fDetABC = bx*cy;
00722 
00723   for (float px = (fStep / 2.0f); px < fLenAB; px += fStep)
00724   {
00725     for (float py = (fStep / 2.0f); py < cy; py += fStep)
00726     {
00727       float u = (bx*cy + cx*py - px*cy - bx*py) / fDetABC;
00728       float v = (px*cy - cx*py) / fDetABC;
00729       float w = (bx*py) / fDetABC;
00730 
00731       if ((u >= 0.0f) && (v >= 0.0f) && (w >= 0.0f) && ((u + v) < 1.0f))
00732       {
00733        // rclPoints.push_back(CBase::Vector3f(u*A + v*B + w*C));
00734         Base::Vector3f clV = A + (px * clVecABNorm) + (py * clVecHNorm);
00735         clPoints.push_back(clV);
00736 
00737       }
00738       else 
00739         break;
00740     }
00741   }
00742 
00743   // if couldn't subsample the facet take gravity center
00744   if (clPoints.size() == 0)
00745       clPoints.push_back(this->GetGravityPoint());
00746 
00747   rclPoints.insert(rclPoints.end(), clPoints.begin(), clPoints.end());
00748 }
00749 
00755 bool MeshGeomFacet::IntersectWithFacet(const MeshGeomFacet &rclFacet) const
00756 {
00757   float V[3][3], U[3][3];
00758   for (int i = 0; i < 3; i++)
00759   {
00760     V[i][0] = _aclPoints[i].x;
00761     V[i][1] = _aclPoints[i].y;
00762     V[i][2] = _aclPoints[i].z;
00763     U[i][0] = rclFacet._aclPoints[i].x;
00764     U[i][1] = rclFacet._aclPoints[i].y;
00765     U[i][2] = rclFacet._aclPoints[i].z;
00766   }
00767 
00768   if (tri_tri_intersect(V[0], V[1], V[2], U[0], U[1], U[2]) == 0)
00769     return false; // no intersections
00770   return true;
00771 }
00772 
00778 int MeshGeomFacet::IntersectWithFacet (const MeshGeomFacet& rclFacet, 
00779                                        Base::Vector3f& rclPt0, 
00780                                        Base::Vector3f& rclPt1) const
00781 {
00782     float V[3][3], U[3][3];
00783     int coplanar = 0;
00784     float isectpt1[3], isectpt2[3];
00785 
00786     for (int i = 0; i < 3; i++)
00787     {
00788         V[i][0] = _aclPoints[i].x;
00789         V[i][1] = _aclPoints[i].y;
00790         V[i][2] = _aclPoints[i].z;
00791         U[i][0] = rclFacet._aclPoints[i].x;
00792         U[i][1] = rclFacet._aclPoints[i].y;
00793         U[i][2] = rclFacet._aclPoints[i].z;
00794     }
00795 
00796     if (tri_tri_intersect_with_isectline(V[0], V[1], V[2], U[0], U[1], U[2], 
00797                                          &coplanar, isectpt1, isectpt2) == 0)
00798         return 0; // no intersections
00799 
00800     rclPt0.x = isectpt1[0]; rclPt0.y = isectpt1[1]; rclPt0.z = isectpt1[2];
00801     rclPt1.x = isectpt2[0]; rclPt1.y = isectpt2[1]; rclPt1.z = isectpt2[2];
00802 
00803     // Note: The algorithm delivers sometimes false-positives, i.e. it claims
00804     // that the two triangles intersect but they don't. It seems that this bad
00805     // behaviour occurs if the triangles are nearly co-planar
00806     float mult = (float)fabs(this->GetNormal() * rclFacet.GetNormal());
00807     if (rclPt0 == rclPt1) {
00808         if (mult < 0.995) // not co-planar, thus no test needed
00809             return 1;
00810         if (this->IsPointOf(rclPt0) && rclFacet.IsPointOf(rclPt0))
00811             return 1;
00812     }
00813     else {
00814         if (mult < 0.995) // not co-planar, thus no test needed
00815             return 2;
00816         if (this->IsPointOf(rclPt0) && rclFacet.IsPointOf(rclPt0) &&
00817             this->IsPointOf(rclPt1) && rclFacet.IsPointOf(rclPt1))
00818             return 2;
00819     }
00820 
00821     // the intersection algorithm delivered a false-positive
00822     return 0;
00823 }
00824 
00825 bool MeshGeomFacet::IsPointOf (const Base::Vector3f &P) const
00826 {
00827     Base::Vector3d p1(this->_aclPoints[0].x,this->_aclPoints[0].y,this->_aclPoints[0].z);
00828     Base::Vector3d p2(this->_aclPoints[1].x,this->_aclPoints[1].y,this->_aclPoints[1].z);
00829     Base::Vector3d p3(this->_aclPoints[2].x,this->_aclPoints[2].y,this->_aclPoints[2].z);
00830     Base::Vector3d p4(P.x,P.y,P.z);
00831 
00832     Base::Vector3d u = p2 - p1;
00833     Base::Vector3d v = p3 - p1;
00834     Base::Vector3d w = p4 - p1;
00835 
00836     double uu = u * u;
00837     double uv = u * v;
00838     double vv = v * v;
00839     double wu = w * u;
00840     double wv = w * v;
00841     double det = fabs((uu * vv) - (uv * uv));
00842 
00843     // Note: Due to roundoff errros it can happen that we get very small
00844     // negative values for s or t. This e.g. can happen if the point lies
00845     // at the border of the facet. And as det could also become very small
00846     // we need an adaptive tolerance.
00847     const double eps=std::min<double>(1.0e-6, det*det);
00848 
00849     double s  = (vv * wu) - (uv * wv);
00850     double t  = (uu * wv) - (uv * wu);
00851 
00852     // is the point inside the triangle?
00853     if ((s >= -eps) && (t >= -eps) && ((s + t) <= det+eps)) {
00854         return true;
00855     }
00856 
00857     return false;
00858 }
00859 
00860 float MeshGeomFacet::CenterOfInscribedCircle(Base::Vector3f& rclCenter) const
00861 {
00862   const Base::Vector3f& p0 = _aclPoints[0];
00863   const Base::Vector3f& p1 = _aclPoints[1];
00864   const Base::Vector3f& p2 = _aclPoints[2];
00865 
00866   float a = Base::Distance(p1,p2);
00867   float b = Base::Distance(p2,p0);
00868   float c = Base::Distance(p0,p1);
00869 
00870   // radius of the circle
00871   float fRadius = Area();
00872   fRadius *= 2.0f/(a + b + c); 
00873 
00874   // center of the circle
00875   float w = a + b + c;
00876   rclCenter.x = (a*p0.x + b*p1.x + c*p2.x)/w;
00877   rclCenter.y = (a*p0.y + b*p1.y + c*p2.y)/w;
00878   rclCenter.z = (a*p0.z + b*p1.z + c*p2.z)/w;
00879 
00880   return fRadius;
00881 }
00882 
00883 float MeshGeomFacet::CenterOfCircumCircle(Base::Vector3f& rclCenter) const
00884 {
00885   const Base::Vector3f& p0 = _aclPoints[0];
00886   const Base::Vector3f& p1 = _aclPoints[1];
00887   const Base::Vector3f& p2 = _aclPoints[2];
00888 
00889   Base::Vector3f u = (p1-p0);
00890   Base::Vector3f v = (p2-p1);
00891   Base::Vector3f w = (p0-p2);
00892 
00893   float uu =   (u * u);
00894   float vv =   (v * v);
00895   float ww =   (w * w);
00896   float uv = - (u * v);
00897   float vw = - (v * w);
00898   float uw = - (w * u);
00899 
00900   float w0 = (float)(2 * sqrt(uu * ww - uw * uw) * uw / (uu * ww));
00901   float w1 = (float)(2 * sqrt(uu * vv - uv * uv) * uv / (uu * vv));
00902   float w2 = (float)(2 * sqrt(vv * ww - vw * vw) * vw / (vv * ww));
00903 
00904   // center of the circle
00905   float wx = w0 + w1 + w2;
00906   rclCenter.x = (w0*p0.x + w1*p1.x + w2*p2.x)/wx;
00907   rclCenter.y = (w0*p0.y + w1*p1.y + w2*p2.y)/wx;
00908   rclCenter.z = (w0*p0.z + w1*p1.z + w2*p2.z)/wx;
00909 
00910   // radius of the circle
00911   float fRadius = (float)(sqrt(uu * vv * ww) / (4 * Area()));
00912 
00913   return fRadius;
00914 }
00915 
00916 unsigned short MeshGeomFacet::NearestEdgeToPoint(const Base::Vector3f& rclPt) const
00917 {
00918   unsigned short usSide;
00919 
00920   const Base::Vector3f& rcP1 = _aclPoints[0];
00921   const Base::Vector3f& rcP2 = _aclPoints[1];
00922   const Base::Vector3f& rcP3 = _aclPoints[2];
00923 
00924   float fD1 = FLOAT_MAX;
00925   float fD2 = FLOAT_MAX;
00926   float fD3 = FLOAT_MAX;
00927 
00928   // 1st edge
00929   Base::Vector3f clDir = rcP2 - rcP1;
00930   float fLen = Base::Distance(rcP2, rcP1);
00931   float t = ( ( rclPt - rcP1 ) * clDir ) / ( fLen * fLen );
00932   if ( t < 0.0f )
00933     fD1 = Base::Distance(rclPt, rcP1);
00934   else if ( t > 1.0f )
00935     fD1 = Base::Distance(rclPt, rcP2);
00936   else
00937     fD1 = ( ( ( rclPt - rcP1 ) % clDir).Length() ) / fLen;
00938 
00939   // 2nd edge
00940   clDir = rcP3 - rcP2;
00941   fLen = Base::Distance(rcP3, rcP2);
00942   t = ( ( rclPt - rcP2 ) * clDir ) / ( fLen * fLen );
00943   if ( t < 0.0f )
00944     fD2 = Base::Distance(rclPt, rcP2);
00945   else if ( t > 1.0f )
00946     fD2 = Base::Distance(rclPt, rcP3);
00947   else
00948     fD2 = ( ( ( rclPt - rcP2 ) % clDir).Length() ) / fLen;
00949 
00950   // 3rd edge
00951   clDir = rcP1 - rcP3;
00952   fLen = Base::Distance(rcP1, rcP3);
00953   t = ( ( rclPt - rcP3 ) * clDir ) / ( fLen * fLen );
00954   if ( t < 0.0f )
00955     fD3 = Base::Distance(rclPt, rcP3);
00956   else if ( t > 1.0f )
00957     fD3 = Base::Distance(rclPt, rcP1);
00958   else
00959     fD3 = ( ( ( rclPt - rcP3 ) % clDir).Length() ) / fLen;
00960 
00961   if ( fD1 < fD2 )
00962   {
00963     if ( fD1 < fD3 )
00964     {
00965       usSide = 0;
00966     }
00967     else
00968     {
00969       usSide = 2;
00970     }
00971   }
00972   else
00973   {
00974     if ( fD2 < fD3 )
00975     {
00976       usSide = 1;
00977     }
00978     else
00979     {
00980       usSide = 2;
00981     }
00982   }
00983 
00984   return usSide;
00985 }
00986 
00987 void MeshGeomFacet::NearestEdgeToPoint(const Base::Vector3f& rclPt, float& fDistance, unsigned short& usSide) const
00988 {
00989   const Base::Vector3f& rcP1 = _aclPoints[0];
00990   const Base::Vector3f& rcP2 = _aclPoints[1];
00991   const Base::Vector3f& rcP3 = _aclPoints[2];
00992 
00993   float fD1 = FLOAT_MAX;
00994   float fD2 = FLOAT_MAX;
00995   float fD3 = FLOAT_MAX;
00996 
00997   // 1st edge
00998   Base::Vector3f clDir = rcP2 - rcP1;
00999   float fLen = Base::Distance(rcP2, rcP1);
01000   float t = ( ( rclPt - rcP1 ) * clDir ) / ( fLen * fLen );
01001   if ( t < 0.0f )
01002     fD1 = Base::Distance(rclPt, rcP1);
01003   else if ( t > 1.0f )
01004     fD1 = Base::Distance(rclPt, rcP2);
01005   else
01006     fD1 = ( ( ( rclPt - rcP1 ) % clDir).Length() ) / fLen;
01007 
01008   // 2nd edge
01009   clDir = rcP3 - rcP2;
01010   fLen = Base::Distance(rcP3, rcP2);
01011   t = ( ( rclPt - rcP2 ) * clDir ) / ( fLen * fLen );
01012   if ( t < 0.0f )
01013     fD2 = Base::Distance(rclPt, rcP2);
01014   else if ( t > 1.0f )
01015     fD2 = Base::Distance(rclPt, rcP3);
01016   else
01017     fD2 = ( ( ( rclPt - rcP2 ) % clDir).Length() ) / fLen;
01018 
01019   // 3rd edge
01020   clDir = rcP1 - rcP3;
01021   fLen = Base::Distance(rcP1, rcP3);
01022   t = ( ( rclPt - rcP3 ) * clDir ) / ( fLen * fLen );
01023   if ( t < 0.0f )
01024     fD3 = Base::Distance(rclPt, rcP3);
01025   else if ( t > 1.0f )
01026     fD3 = Base::Distance(rclPt, rcP1);
01027   else
01028     fD3 = ( ( ( rclPt - rcP3 ) % clDir).Length() ) / fLen;
01029 
01030   if ( fD1 < fD2 )
01031   {
01032     if ( fD1 < fD3 )
01033     {
01034       usSide = 0;
01035       fDistance = fD1;
01036     }
01037     else
01038     {
01039       usSide = 2;
01040       fDistance = fD3;
01041     }
01042   }
01043   else
01044   {
01045     if ( fD2 < fD3 )
01046     {
01047       usSide = 1;
01048       fDistance = fD2;
01049     }
01050     else
01051     {
01052       usSide = 2;
01053       fDistance = fD3;
01054     }
01055   }
01056 }
01057 
01058 float MeshGeomFacet::VolumeOfPrism (const MeshGeomFacet& rclF1) const
01059 {
01060   Base::Vector3f P1 = this->_aclPoints[0];
01061   Base::Vector3f P2 = this->_aclPoints[1];
01062   Base::Vector3f P3 = this->_aclPoints[2];
01063   Base::Vector3f Q1 = rclF1._aclPoints[0];
01064   Base::Vector3f Q2 = rclF1._aclPoints[1];
01065   Base::Vector3f Q3 = rclF1._aclPoints[2];
01066 
01067   if ((P1-Q2).Length() < (P1-Q1).Length())
01068   {
01069     Base::Vector3f tmp = Q1;
01070     Q1 = Q2;
01071     Q2 = tmp;
01072   }
01073   if ((P1-Q3).Length() < (P1-Q1).Length())
01074   {
01075     Base::Vector3f tmp = Q1;
01076     Q1 = Q3;
01077     Q3 = tmp;
01078   }
01079   if ((P2-Q3).Length() < (P2-Q2).Length())
01080   {
01081     Base::Vector3f tmp = Q2;
01082     Q2 = Q3;
01083     Q3 = tmp;
01084   }
01085 
01086   Base::Vector3f N1 = (P2-P1) % (P3-P1);
01087   Base::Vector3f N2 = (P2-P1) % (Q2-P1);
01088   Base::Vector3f N3 = (Q2-P1) % (Q1-P1);
01089 
01090   float fVol=0.0f;
01091   fVol += float(fabs((Q3-P1) * N1));
01092   fVol += float(fabs((Q3-P1) * N2));
01093   fVol += float(fabs((Q3-P1) * N3));
01094 
01095   fVol /= 6.0f;
01096 
01097   return fVol;;
01098 }
01099 
01100 float MeshGeomFacet::MaximumAngle () const
01101 {
01102   float fMaxAngle = 0.0f;
01103   
01104   for ( int i=0; i<3; i++ ) {
01105     Base::Vector3f dir1(_aclPoints[(i+1)%3]-_aclPoints[i]);
01106     Base::Vector3f dir2(_aclPoints[(i+2)%3]-_aclPoints[i]);
01107     float fAngle = dir1.GetAngle(dir2);
01108     if (fAngle > fMaxAngle)
01109       fMaxAngle = fAngle;
01110   }
01111 
01112   return fMaxAngle;
01113 }
01114 
01115 bool MeshGeomFacet::IsPointOfSphere(const Base::Vector3f& rP) const
01116 {
01117   float radius;
01118   Base::Vector3f center;
01119   radius = CenterOfCircumCircle(center);
01120   radius *= radius;
01121 
01122   float dist = Base::DistanceP2(rP, center);
01123   return dist < radius;
01124 }
01125 
01126 bool MeshGeomFacet::IsPointOfSphere(const MeshGeomFacet& rFacet) const
01127 {
01128   float radius;
01129   Base::Vector3f center;
01130   radius = CenterOfCircumCircle(center);
01131   radius *= radius;
01132 
01133   for (int i=0; i<3; i++) {
01134     float dist = Base::DistanceP2(rFacet._aclPoints[i], center);
01135     if (dist < radius)
01136       return true;
01137   }
01138 
01139   return false;
01140 }
01141 

Generated on Wed Nov 23 19:00:10 2011 for FreeCAD by  doxygen 1.6.1