Tools2D.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 # include <cstdlib>
00028 # include <set>
00029 #endif
00030 
00031 #include "Tools2D.h"
00032 #include "Vector3D.h"
00033 
00034 using namespace Base;
00035 
00036 float Vector2D::GetAngle (const Vector2D &rclVect) const
00037 {
00038   float fDivid, fNum;
00039   
00040   fDivid = Length() * rclVect.Length();
00041  
00042   if ((fDivid < -1e-10f) || (fDivid > 1e-10f))
00043   {
00044     fNum = (*this * rclVect) / fDivid;
00045     if (fNum < -1)
00046       return F_PI;
00047     else
00048       if (fNum > 1)
00049         return 0.0F;
00050       else
00051         return float(acos(fNum));
00052   }
00053   else
00054     return -FLOAT_MAX; // division by zero
00055 }
00056 
00057 void Vector2D::ProjToLine (const Vector2D &rclPt, const Vector2D &rclLine)
00058 {
00059   float l  = rclLine.Length();
00060   float t1 = (rclPt * rclLine) / l;
00061   Vector2D clNormal = rclLine;
00062   clNormal.Normalize();
00063   clNormal.Scale(t1);  
00064   *this = clNormal;
00065 }
00066 
00067 /********************************************************/
00070 bool BoundBox2D::operator|| (const Line2D &rclLine) const
00071 {
00072   Line2D clThisLine;
00073   Vector2D clVct;
00074 
00075   // first line 
00076   clThisLine.clV1.fX = fMinX;
00077   clThisLine.clV1.fY = fMinY;
00078   clThisLine.clV2.fX = fMaxX;
00079   clThisLine.clV2.fY = fMinY;
00080   if (clThisLine.IntersectAndContain (rclLine, clVct)) 
00081     return true;
00082 
00083   // second line
00084   clThisLine.clV1 = clThisLine.clV2;
00085   clThisLine.clV2.fX = fMaxX;
00086   clThisLine.clV2.fY = fMaxY;
00087   if (clThisLine.IntersectAndContain (rclLine, clVct)) 
00088     return true;
00089 
00090   // third line
00091   clThisLine.clV1 = clThisLine.clV2;
00092   clThisLine.clV2.fX = fMinX;
00093   clThisLine.clV2.fY = fMaxY;
00094   if (clThisLine.IntersectAndContain (rclLine, clVct)) 
00095     return true;
00096 
00097   // fourth line
00098   clThisLine.clV1 = clThisLine.clV2;
00099   clThisLine.clV2.fX = fMinX;
00100   clThisLine.clV2.fY = fMinY;
00101   if (clThisLine.IntersectAndContain (rclLine, clVct)) 
00102     return true;
00103 
00104   return false;
00105 }
00106 
00107 bool BoundBox2D::operator|| (const BoundBox2D &rclBB) const
00108 {
00110 //if (Contains (Vector2D (rclBB.fMinX, rclBB.fMinY))) return TRUE;
00111 //if (Contains (Vector2D (rclBB.fMaxX, rclBB.fMinY))) return TRUE;
00112 //if (Contains (Vector2D (rclBB.fMaxX, rclBB.fMaxY))) return TRUE;
00113 //if (Contains (Vector2D (rclBB.fMinX, rclBB.fMaxY))) return TRUE;
00114 //
00116 //if (rclBB.Contains (Vector2D (fMinX, fMinY))) return TRUE;
00117 //if (rclBB.Contains (Vector2D (fMaxX, fMinY))) return TRUE;
00118 //if (rclBB.Contains (Vector2D (fMaxX, fMaxY))) return TRUE;
00119 //if (rclBB.Contains (Vector2D (fMinX, fMaxY))) return TRUE;
00120 
00121   if (fMinX       < rclBB.fMaxX  &&
00122       rclBB.fMinX < fMaxX        &&
00123       fMinY       < rclBB.fMaxY  &&
00124       rclBB.fMinY < fMaxY         )
00125       return true;
00126   else // no intersection
00127       return false;
00128 }
00129 
00130 bool BoundBox2D::operator|| (const Polygon2D &rclPoly) const
00131 {
00132   unsigned long i;
00133   Line2D clLine;
00134   
00135   // points contained in boundbox
00136   for (i = 0; i < rclPoly.GetCtVectors(); i++)
00137     if (Contains (rclPoly[i]))
00138       return true;    /***** RETURN INTERSECTION *********/
00139 
00140   // points contained in polygon
00141   if (rclPoly.Contains (Vector2D (fMinX, fMinY)) ||
00142       rclPoly.Contains (Vector2D (fMaxX, fMinY)) ||
00143       rclPoly.Contains (Vector2D (fMaxX, fMaxY)) ||
00144       rclPoly.Contains (Vector2D (fMinX, fMaxY)))
00145     return true;    /***** RETURN INTERSECTION *********/
00146       
00147   // test intersections of bound-lines
00148   if (rclPoly.GetCtVectors() < 3) return false;
00149   for (i = 0; i < rclPoly.GetCtVectors(); i++)
00150   {
00151     if (i == rclPoly.GetCtVectors() - 1)
00152     {
00153       clLine.clV1 = rclPoly[i];
00154       clLine.clV2 = rclPoly[0];
00155     }
00156     else
00157     {
00158       clLine.clV1 = rclPoly[i];
00159       clLine.clV2 = rclPoly[i + 1];
00160     }
00161     if (*this || clLine) 
00162       return true;    /***** RETURN INTERSECTION *********/
00163   }
00164   // no intersection
00165   return false;
00166 }
00167 
00168 bool BoundBox2D::Contains (const Vector2D &rclV) const
00169 {
00170   return
00171     (rclV.fX >= fMinX) && (rclV.fX <= fMaxX) &&
00172     (rclV.fY >= fMinY) && (rclV.fY <= fMaxY);
00173 }
00174 
00175 /********************************************************/
00178 BoundBox2D Line2D::CalcBoundBox (void) const
00179 {
00180   BoundBox2D clBB;
00181   clBB.fMinX = std::min<float> (clV1.fX, clV2.fX);
00182   clBB.fMinY = std::min<float> (clV1.fY, clV2.fY);
00183   clBB.fMaxX = std::max<float> (clV1.fX, clV2.fX);
00184   clBB.fMaxY = std::max<float> (clV1.fY, clV2.fY);
00185   return clBB;
00186 }
00187 
00188 bool Line2D::Intersect (const Line2D& rclLine, Vector2D &rclV) const
00189 {
00190   float m1, m2, b1, b2;
00191   
00192   // calc coefficients
00193   if (fabs (clV2.fX - clV1.fX) > 1e-10)
00194     m1 = (clV2.fY - clV1.fY) / (clV2.fX - clV1.fX);
00195   else
00196     m1 = FLOAT_MAX;
00197   if (fabs (rclLine.clV2.fX - rclLine.clV1.fX) > 1e-10)
00198     m2 = (rclLine.clV2.fY - rclLine.clV1.fY) / (rclLine.clV2.fX - rclLine.clV1.fX);
00199   else
00200     m2 = FLOAT_MAX;
00201   if (m1 == m2)     /****** RETURN ERR (parallel lines) *************/
00202     return false;
00203   
00204   b1 = clV1.fY - m1 * clV1.fX;
00205   b2 = rclLine.clV1.fY - m2 * rclLine.clV1.fX;
00206 
00207   // calc intersection
00208   if (m1 == FLOAT_MAX)
00209   {
00210     rclV.fX = clV1.fX;
00211     rclV.fY = m2 * rclV.fX + b2;
00212   }
00213   else
00214   if (m2 == FLOAT_MAX)
00215   {
00216     rclV.fX = rclLine.clV1.fX;
00217     rclV.fY = m1 * rclV.fX + b1;
00218   }
00219   else
00220   {
00221     rclV.fX = (b2 - b1) / (m1 - m2);
00222     rclV.fY = m1 * rclV.fX + b1;  
00223   }
00224   
00225   return true;    /*** RETURN TRUE (intersection) **********/
00226 }
00227 
00228 Vector2D Line2D::FromPos (float fDistance) const
00229 {
00230   Vector2D clDir(clV2 - clV1);
00231   clDir.Normalize();
00232   return Vector2D(clV1.fX + (clDir.fX * fDistance), clV1.fY + (clDir.fY * fDistance));
00233 }
00234 
00235 bool Line2D::IntersectAndContain (const Line2D& rclLine, Vector2D &rclV) const
00236 {
00237   bool rc = Intersect (rclLine, rclV);
00238   if (rc)
00239     rc = Contains (rclV) && rclLine.Contains (rclV);
00240   return rc;
00241 }
00242 
00243 /********************************************************/
00246 BoundBox2D Polygon2D::CalcBoundBox (void) const
00247 {
00248   unsigned long i;
00249   BoundBox2D clBB;
00250   for (i = 0; i < _aclVct.size(); i++)
00251   {
00252     clBB.fMinX = std::min<float> (clBB.fMinX, _aclVct[i].fX);
00253     clBB.fMinY = std::min<float> (clBB.fMinY, _aclVct[i].fY);
00254     clBB.fMaxX = std::max<float> (clBB.fMaxX, _aclVct[i].fX);
00255     clBB.fMaxY = std::max<float> (clBB.fMaxY, _aclVct[i].fY);
00256   }
00257   return clBB;  
00258 }
00259 
00260 static short _CalcTorsion (float *pfLine, float fX, float fY)
00261 {
00262   short sQuad[2], i;
00263   float fResX;
00264 
00265   // Klassifizierung der beiden Polygonpunkte in Quadranten
00266   for (i = 0; i < 2; i++)
00267   {
00268     if (pfLine[i * 2] <= fX)
00269       sQuad[i] = (pfLine[i * 2 + 1] > fY) ? 0 : 3;
00270     else
00271       sQuad[i] = (pfLine[i * 2 + 1] > fY) ? 1 : 2;
00272   }
00273 
00274   // Abbruch bei Linienpunkten innerhalb eines Quadranten
00275   // Abbruch bei nichtschneidenden Linienpunkten
00276   if (abs (sQuad[0] - sQuad[1]) <= 1) return 0;
00277 
00278   // Beide Punkte links von ulX
00279   if (abs (sQuad[0] - sQuad[1]) == 3)
00280     return (sQuad[0] == 0) ? 1 : -1;
00281 
00282   // Restfaelle : Quadrantendifferenz von 2
00283   // mathematischer Test auf Schnitt
00284   fResX = pfLine[0] + (fY - pfLine[1]) /
00285                 ((pfLine[3] - pfLine[1]) / (pfLine[2] - pfLine[0]));
00286   if (fResX < fX)
00287 
00288     // oben/unten oder unten/oben
00289     return (sQuad[0] <= 1) ? 1 : -1;
00290 
00291   // Verbleibende Faelle ?
00292   return 0;
00293 }
00294 
00295 bool Polygon2D::Contains (const Vector2D &rclV) const
00296 {
00297   // Ermittelt mit dem Verfahren der Windungszahl, ob ein Punkt innerhalb 
00298   // eines Polygonzugs enthalten ist.
00299   // Summe aller Windungszahlen gibt an, ob ja oder nein.
00300   float pfTmp[4];
00301   unsigned long i;
00302   short sTorsion = 0;
00303 
00304   // Fehlercheck
00305   if (GetCtVectors() < 3)  return false;
00306 
00307   // fuer alle Polygon-Linien
00308   for (i = 0; i < GetCtVectors(); i++)
00309   {
00310     // Linienstruktur belegen
00311     if (i == GetCtVectors() - 1)
00312     {
00313       // Polygon automatisch schliessen
00314       pfTmp[0] = _aclVct[i].fX;
00315       pfTmp[1] = _aclVct[i].fY;
00316       pfTmp[2] = _aclVct[0].fX;
00317       pfTmp[3] = _aclVct[0].fY;
00318     }
00319     else
00320     {
00321       // uebernehmen Punkt i und i+1
00322       pfTmp[0] = _aclVct[i].fX;
00323       pfTmp[1] = _aclVct[i].fY;
00324       pfTmp[2] = _aclVct[i + 1].fX;
00325       pfTmp[3] = _aclVct[i + 1].fY;
00326     }
00327 
00328     // Schnitt-Test durchfuehren und Windungszaehler berechnen
00329     sTorsion += _CalcTorsion (pfTmp, rclV.fX, rclV.fY);
00330   }
00331 
00332   // Windungszaehler auswerten
00333   return sTorsion != 0;
00334 }
00335 
00336 void Polygon2D::Intersect (const Polygon2D &rclPolygon, std::list<Polygon2D> &rclResultPolygonList) const
00337 {
00338   // trimmen des uebergebenen Polygons mit dem aktuellen, Ergebnis ist eine Liste von Polygonen (Untermenge des uebergebenen Polygons)
00339   // das eigene (Trim-) Polygon ist geschlossen
00340   //
00341   if ((rclPolygon.GetCtVectors() < 2) || (GetCtVectors() < 2))
00342     return;
00343 
00344   // position of first points (in or out of polygon)
00345   bool bInner = Contains(rclPolygon[0]);
00346 
00347   Polygon2D clResultPolygon;
00348   if (bInner == true)  // add first point if inner trim-polygon
00349     clResultPolygon.Add(rclPolygon[0]);
00350 
00351   // for each polygon segment
00352   size_t ulPolyCt = rclPolygon.GetCtVectors();
00353   size_t ulTrimCt = GetCtVectors();
00354   for (size_t ulVec = 0; ulVec < (ulPolyCt-1); ulVec++)
00355   {
00356     Vector2D clPt0 = rclPolygon[ulVec];
00357     Vector2D clPt1 = rclPolygon[ulVec+1];
00358     Line2D clLine(clPt0, clPt1);
00359 
00360     // try to intersect with each line of the trim-polygon
00361     std::set<float> afIntersections;  // set of intersections (sorted by line parameter)
00362     Vector2D clTrimPt2;  // second line point
00363     for (size_t i = 0; i < ulTrimCt; i++)
00364     {
00365       clTrimPt2 = At((i + 1) % ulTrimCt);
00366       Line2D clToTrimLine(At(i), clTrimPt2);
00367    
00368       Vector2D clV;
00369       if (clLine.IntersectAndContain(clToTrimLine, clV) == true)
00370       {
00371         // save line parameter of intersection point
00372         float fDist = (clV - clPt0).Length();
00373         afIntersections.insert(fDist);
00374       }
00375     }
00376 
00377     if (afIntersections.size() > 0)  // intersections founded
00378     {
00379       for (std::set<float>::iterator pF = afIntersections.begin(); pF != afIntersections.end(); pF++)
00380       {
00381         // intersection point
00382         Vector2D clPtIS = clLine.FromPos(*pF);
00383         if (bInner == true)
00384         {
00385           clResultPolygon.Add(clPtIS);
00386           rclResultPolygonList.push_back(clResultPolygon);
00387           clResultPolygon.DeleteAll();
00388           bInner = false;
00389         }
00390         else
00391         {
00392           clResultPolygon.Add(clPtIS);
00393           bInner = true;
00394         }
00395       }        
00396 
00397       if (bInner == true) // add line end point if inside
00398         clResultPolygon.Add(clPt1);
00399     }
00400     else
00401     {  // no intersections, add line (means second point of it) if inside trim-polygon
00402       if (bInner == true)
00403         clResultPolygon.Add(clPt1);
00404     }
00405   }  
00406 
00407   // add last segment
00408   if (clResultPolygon.GetCtVectors() > 0)
00409     rclResultPolygonList.push_back(clResultPolygon);
00410 }
00411 

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