polygon.cpp

Go to the documentation of this file.
00001 
00005 /* Copyright, 2000 Nevrax Ltd.
00006  *
00007  * This file is part of NEVRAX NEL.
00008  * NEVRAX NEL is free software; you can redistribute it and/or modify
00009  * it under the terms of the GNU General Public License as published by
00010  * the Free Software Foundation; either version 2, or (at your option)
00011  * any later version.
00012 
00013  * NEVRAX NEL is distributed in the hope that it will be useful, but
00014  * WITHOUT ANY WARRANTY; without even the implied warranty of
00015  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
00016  * General Public License for more details.
00017 
00018  * You should have received a copy of the GNU General Public License
00019  * along with NEVRAX NEL; see the file COPYING. If not, write to the
00020  * Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
00021  * MA 02111-1307, USA.
00022  */
00023 
00024 #include "stdmisc.h"
00025 
00026 #include "nel/misc/polygon.h"
00027 #include "nel/misc/plane.h"
00028 #include "nel/misc/triangle.h"
00029 
00030 
00031 using namespace std;
00032 using namespace NLMISC;
00033 
00034 
00035 namespace NLMISC
00036 {
00037 
00038 
00039 //==================================//
00040 //      CPolygon implementation     //
00041 //==================================//
00042 
00043 // ***************************************************************************
00044 CPolygon::CPolygon(const CVector &a, const CVector &b, const CVector &c)
00045 {
00046     Vertices.reserve(3);
00047     Vertices.push_back(a);
00048     Vertices.push_back(b);
00049     Vertices.push_back(c);
00050 }
00051 
00052 // ***************************************************************************
00053 void CPolygon::toTriFan(std::vector<NLMISC::CTriangle> &dest) const
00054 {
00055     sint count = (sint) Vertices.size() - 2;
00056     for(sint k = 0; k < count; ++k)
00057     {
00058         dest.push_back(CTriangle(Vertices[0], Vertices[k + 1], Vertices[k + 2]));
00059     }
00060 }
00061 
00062 // ***************************************************************************
00063 float CPolygon::computeArea() const
00064 {
00065     float area = 0.f;
00066     sint numVerts = (sint) Vertices.size();
00067     for(sint k = 0; k < numVerts - 2; ++k)
00068     {
00069         CVector v0 = Vertices[k + 1] - Vertices[0];
00070         CVector v1 = Vertices[k + 2] - Vertices[0];
00071         area += (v0 ^ v1).norm();
00072     }
00073     return 0.5f * fabsf(area);
00074 }
00075 
00076 // ***************************************************************************
00077 void            CPolygon::clip(const CPlane  *planes, uint nPlanes)
00078 {
00079     if(nPlanes==0 || getNumVertices()==0)
00080         return;
00081 
00082     // The final polygon has at maximum currentVertices+number of clipping planes.
00083     // For performance, the vectors are static, so reallocation rarely occurs.
00084     static  vector<CVector>     tab0, tab1;
00085     tab0.resize(getNumVertices()+nPlanes);
00086     tab1.resize(getNumVertices()+nPlanes);
00087     // Init tab0 with Vertices.
00088     copy(Vertices.begin(), Vertices.end(), tab0.begin());
00089     CVector             *in=&(*tab0.begin()), *out= &(*tab1.begin());
00090     sint                nin= getNumVertices(), nout;
00091     for(sint i=0;i<(sint)nPlanes;i++)
00092     {
00093         nout= planes[i].clipPolygonBack(in, out, nin);
00094         swap(in, out);
00095         nin= nout;
00096         if(nin==0)
00097             break;
00098     }
00099 
00100     // Final result in "in".
00101     Vertices.resize(nin);
00102     if(nin>0)
00103     {
00104         memcpy(&(*Vertices.begin()), in, nin*sizeof(CVector));
00105     }
00106 }
00107 
00108 
00109 // ***************************************************************************
00110 void            CPolygon::clip(const std::vector<CPlane> &planes)
00111 {
00112     if(planes.size()==0)
00113         return;
00114     clip(&(*planes.begin()), planes.size());
00115 }
00116 
00117 
00118 
00119 // ***************************************************************************
00120 void CPolygon::serial(NLMISC::IStream &f) throw(NLMISC::EStream)
00121 {
00122     f.serialVersion(0);
00123     f.serialCont(Vertices);
00124 }
00125 
00126 // ***************************************************************************
00127 void CPolygon::getBestTriplet(uint &index0,uint &index1,uint &index2)
00128 {
00129     nlassert(Vertices.size() >= 3);
00130     uint i, j, k;
00131     float bestArea = 0.f;
00132     const uint numVerts = Vertices.size();
00133     for (i = 0; i < numVerts; ++i)
00134     {
00135         for (j = 0; j < numVerts; ++j)
00136         {
00137             if (i != j)
00138             {
00139                 for (k = 0; k < numVerts; ++k)
00140                 {
00141                     if (k != i && k != j)
00142                     {
00143                         CVector v0 = Vertices[j] - Vertices[i];
00144                         CVector v1 = Vertices[k] - Vertices[i];
00145                         float area = (v0 ^ v1).norm();
00146                         if (area > bestArea)
00147                         {
00148                             bestArea = area;
00149                             index0 = i;
00150                             index1 = j;
00151                             index2 = k;
00152                         }
00153                     }
00154                 }
00155             }
00156         }
00157     }
00158 
00159 }
00160 
00161 // ***************************************************************************
00162 void CPolygon::buildBasis(CMatrix &dest)
00163 {
00164     nlassert(Vertices.size() > 3);
00165     uint i1, i2, i3;
00166     getBestTriplet(i1, i2, i3);
00167     CVector v1 = (Vertices[i2] - Vertices[i1]).normed();
00168     CVector v2 = (Vertices[i3] - Vertices[i1]).normed();
00169     CVector K = v2 ^ v1;
00170     CVector I = v1 - (v1 * K) * v1;
00171     CVector J = K ^ I;
00172     dest.setRot(I, J, K);
00173     dest.setPos(Vertices[i1]);
00174 }
00175 
00176 // ***************************************************************************
00177 
00178 class CConcavePolygonsVertexDesc
00179 {
00180 public:
00181 
00182     CConcavePolygonsVertexDesc (float length, uint index)
00183     {
00184         Length = length;
00185         Index = index;
00186     }
00187 
00188     // Length > 0
00189     float   Length;
00190 
00191     // First vertex index
00192     uint    Index;
00193 };
00194 typedef std::map<float, CConcavePolygonsVertexDesc> TCConcavePolygonsVertexMap;
00195 
00196 
00197 // ***************************************************************************
00198 bool CPolygon::toConvexPolygonsEdgeIntersect (const CVector2f& a0, const CVector2f& a1, const CVector2f& b0, const CVector2f& b1)
00199 {
00200     // both vertical?
00201     if( a0.x-a1.x==0 && b0.x-b1.x==0 )
00202         return false;
00203 
00204     // compute intersection of both lines
00205     CVector2f intersection;
00206 
00207     // first edge vertical?
00208     if(a0.x - a1.x==0)
00209     {
00210         float Ab = (b0.y - b1.y) / (b0.x - b1.x);
00211 
00212         // Intersection
00213         intersection.x = a0.x;
00214         intersection.y = b0.y + (a0.x-b0.x) * Ab;
00215     }
00216     // second edge vertical?
00217     else if(b0.x - b1.x==0)
00218     {
00219         float Aa = (a0.y - a1.y) / (a0.x - a1.x);
00220 
00221         // Intersection
00222         intersection.x = b0.x;
00223         intersection.y = a0.y + (b0.x-a0.x) * Aa;
00224     }
00225     // standard case
00226     else
00227     {
00228         float Aa = (a0.y - a1.y) / (a0.x - a1.x);
00229         float Ba = a0.y - a0.x * Aa;
00230         float Ab = (b0.y - b1.y) / (b0.x - b1.x);
00231         float Bb = b0.y - b0.x * Ab;
00232 
00233         // colinear?
00234         if(Aa==Ab)
00235             return false;
00236 
00237         // Intersection
00238         intersection.x = (Bb - Ba) / (Aa - Ab);
00239         intersection.y = Aa * intersection.x + Ba;
00240     }
00241 
00242     // In it ?
00243     return ( ( (a0-intersection)*(a1-intersection) < 0 ) && ( (b0-intersection)*(b1-intersection) < 0 ) );
00244 }
00245 
00246 // ***************************************************************************
00247 
00248 class CBSPNode2v
00249 {
00250 public:
00251     CBSPNode2v ()
00252     {
00253         Back = NULL;
00254         Front = NULL;
00255     }
00256     CBSPNode2v ( const CPlane &plane, CVector p0, CVector p1, uint v0, uint v1 ) : Plane (plane), P0 (p0), P1 (p1)
00257     {
00258         Back = NULL;
00259         Front = NULL;
00260         Parent = NULL;
00261         V0 = v0;
00262         V1 = v1;
00263     }
00264     ~CBSPNode2v ()
00265     {
00266         if (Front)
00267             delete Front;
00268         if (Back)
00269             delete Back;
00270     }
00271 
00272     void insert (CBSPNode2v *node)
00273     {
00274         // Front ?
00275         bool p0Front = (Plane * node->P0) > 0;
00276         bool p1Front = (Plane * node->P1) > 0;
00277         if (p0Front && p1Front)
00278         {
00279             // Front child ?
00280             if (Front)
00281                 Front->insert (node);
00282             else
00283             {
00284                 // Link left
00285                 Front = node;
00286                 node->Parent = this;
00287             }
00288         }
00289         else if ((!p0Front) && (!p1Front))
00290         {
00291             // Back child ?
00292             if (Back)
00293                 Back->insert (node);
00294             else
00295             {
00296                 // Link left
00297                 Back = node;
00298                 node->Parent = this;
00299             }
00300         }
00301         else
00302         {
00303             // Split vertex
00304             CVector newVertex = Plane.intersect (node->P0, node->P1);
00305 
00306             // New node
00307             CBSPNode2v *newNode = new CBSPNode2v (node->Plane, node->P0, newVertex, node->V0, node->V1);
00308 
00309             // Old node
00310             node->P0 = newVertex;
00311 
00312             // Insert child
00313             CBSPNode2v **p0Parent;
00314             CBSPNode2v **p1Parent;
00315 
00316             // Get insertion pointer
00317             if (p0Front)
00318             {
00319                 p0Parent = &Front;
00320                 p1Parent = &Back;
00321             }
00322             else
00323             {
00324                 p0Parent = &Back;
00325                 p1Parent = &Front;
00326             }
00327 
00328             // Insert children
00329             if (*p0Parent)
00330             {
00331                 (*p0Parent)->insert (newNode);
00332             }
00333             else
00334             {
00335                 *p0Parent = newNode;
00336                 newNode->Parent = this;
00337             }
00338 
00339             // Insert children
00340             if (*p1Parent)
00341             {
00342                 (*p1Parent)->insert (node);
00343             }
00344             else
00345             {
00346                 *p1Parent = node;
00347                 node->Parent = this;
00348             }
00349         }
00350     }
00351 
00352     bool intersect (const CVector &p0, const CVector &p1, uint v0, uint v1) const
00353     {
00354         // Front ?
00355         bool p0Front = (Plane * p0) > 0;
00356         bool p1Front = (Plane * p1) > 0;
00357 
00358         if (p0Front != p1Front)
00359             if ( (v0 != V0) && (v0 != V1) && (v1 != V0) && (v1 != V1) )
00360                 if (CPolygon::toConvexPolygonsEdgeIntersect ((CVector2f) P0, (CVector2f) P1, (CVector2f) p0, (CVector2f) p1))
00361                     return true;
00362 
00363         if (p0Front || p1Front)
00364         {
00365             if (Front)
00366                 if (Front->intersect (p0, p1, v0, v1))
00367                     return true;
00368         }
00369 
00370         if ((!p0Front) || (!p1Front))
00371         {
00372             if (Back)
00373                 if (Back->intersect (p0, p1, v0, v1))
00374                     return true;
00375         }
00376 
00377         return false;
00378     }
00379 
00380     CBSPNode2v  *Back, *Front, *Parent;
00381     CPlane      Plane;
00382     CVector     P0;
00383     CVector     P1;
00384     uint        V0;
00385     uint        V1;
00386 };
00387 
00388 // ***************************************************************************
00389 
00390 bool CPolygon::toConvexPolygonsLeft (const std::vector<CVector> &vertex, uint a, uint b, uint c)
00391 {
00392     return ( (vertex[b].x - vertex[a].x) * (vertex[c].y - vertex[a].y) - (vertex[c].x - vertex[a].x) * (vertex[b].y - vertex[a].y) ) < 0;
00393 }
00394 
00395 // ***************************************************************************
00396 
00397 bool CPolygon::toConvexPolygonsLeftOn (const std::vector<CVector> &vertex, uint a, uint b, uint c)
00398 {
00399     return ( (vertex[b].x - vertex[a].x) * (vertex[c].y - vertex[a].y) - (vertex[c].x - vertex[a].x) * (vertex[b].y - vertex[a].y) ) <= 0;
00400 }
00401 
00402 // ***************************************************************************
00403 
00404 bool CPolygon::toConvexPolygonsInCone (const std::vector<CVector> &vertex, uint a, uint b)
00405 {
00406     // Prev and next
00407     uint a0 = a+1;
00408     if (a0==vertex.size())
00409         a0=0;
00410     uint a1;
00411     if (a==0)
00412         a1=vertex.size()-1;
00413     else
00414         a1= a-1;
00415 
00416     if (toConvexPolygonsLeftOn (vertex, a, a1, a0) )
00417     {
00418         return toConvexPolygonsLeft ( vertex, a, b, a0) && toConvexPolygonsLeft ( vertex, b, a, a1);
00419     }
00420     else
00421     {
00422         return !( toConvexPolygonsLeft ( vertex, a, b, a1) && toConvexPolygonsLeft ( vertex, b, a, a0) );
00423     }
00424 }
00425 
00426 // ***************************************************************************
00427 
00428 bool CPolygon::toConvexPolygonsDiagonal (const std::vector<CVector> &vertex, const CBSPNode2v &bsp, uint a, uint b)
00429 {
00430     // Check it is a border
00431     if ( ( (b - a) == 1) || ( (a - b) == 1) || ( (a==0) && (b ==(vertex.size()-1))) || ( (b==0) && (a ==(vertex.size()-1))) )
00432         return true;
00433 
00434     // Check visibility
00435     if (toConvexPolygonsInCone (vertex, a, b) && toConvexPolygonsInCone (vertex, b, a))
00436     {
00437         // Intersection ?
00438         return !bsp.intersect (vertex[a], vertex[b], a, b);
00439     }
00440     return false;
00441 }
00442 
00443 // ***************************************************************************
00444 
00445 void CPolygon::toConvexPolygonsLocalAndBSP (std::vector<CVector> &localVertices, CBSPNode2v &root, const CMatrix &basis) const
00446 {
00447     // Invert matrix
00448     CMatrix invert = basis;
00449     invert.invert ();
00450 
00451     // Insert vertices in an ordered table
00452     uint vertexCount = Vertices.size();
00453     TCConcavePolygonsVertexMap vertexMap;
00454     localVertices.resize (vertexCount);
00455     uint i, j;
00456 
00457     // Transform the vertex
00458     for (i=0; i<vertexCount; i++)
00459     {
00460         CVector local = invert*Vertices[i];
00461         localVertices[i] = CVector (local.x, local.y, 0);
00462     }
00463 
00464     // Plane direction
00465     i=0;
00466     j=Vertices.size()-1;
00467     CVector normal = localVertices[i] - localVertices[j];
00468     normal = normal ^ CVector::K;
00469     CPlane clipPlane;
00470     clipPlane.make(normal, localVertices[i]);
00471 
00472     // Build the BSP root
00473     root = CBSPNode2v (clipPlane, localVertices[i], localVertices[j], i, j);
00474 
00475     // Insert all others edges
00476     j=i++;
00477     for (; i<Vertices.size(); i++)
00478     {
00479         // Plane direction
00480         normal = localVertices[i] - localVertices[j];
00481         normal = normal ^ CVector::K;
00482         clipPlane.make(normal, localVertices[i]);
00483 
00484         // Build the BSP root
00485         root.insert ( new CBSPNode2v (clipPlane, localVertices[i], localVertices[j], i, j) );
00486 
00487         j=i;
00488     }
00489 }
00490 
00491 
00492 // ***************************************************************************
00493 bool CPolygon::toConvexPolygons (std::list<CPolygon>& outputPolygons, const CMatrix& basis) const
00494 {
00495     // Some vertices ?
00496     if (Vertices.size()>2)
00497     {
00498         // Local vertices
00499         std::vector<CVector>    localVertices;
00500 
00501         // Build the BSP root
00502         CBSPNode2v root;
00503 
00504         // Build the local array and the BSP
00505         toConvexPolygonsLocalAndBSP (localVertices, root, basis);
00506 
00507         // Build a vertex list
00508         std::list<uint> vertexList;
00509         uint i;
00510         for (i=0; i<Vertices.size(); i++)
00511             vertexList.push_back (i);
00512 
00513         // Clip ears while there is some polygons
00514         std::list<uint>::iterator current=vertexList.begin();
00515         std::list<uint>::iterator begin=vertexList.begin();
00516         do
00517         {
00518 again:;
00519             // Search for a diagonal
00520             bool found = false;
00521 
00522             // Get next vertex
00523             std::list<uint>::iterator first = current;
00524             std::list<uint>::iterator lastPreviousPrevious=current;
00525             std::list<uint>::iterator lastPrevious=current;
00526             lastPrevious++;
00527             if (lastPrevious==vertexList.end())
00528                 lastPrevious = vertexList.begin();
00529             std::list<uint>::iterator currentNext = lastPrevious;
00530             std::list<uint>::iterator last = lastPrevious;
00531             last++;
00532             if (last==vertexList.end())
00533                 last = vertexList.begin();
00534             while (last != current)
00535             {
00536                 // Is a diagonal ?
00537                 if (
00538                     (toConvexPolygonsDiagonal (localVertices, root, *lastPreviousPrevious, *last)) &&
00539                     (toConvexPolygonsDiagonal (localVertices, root, *currentNext, *last)) &&
00540                     (toConvexPolygonsDiagonal (localVertices, root, *last, *current))
00541                     )
00542                 {
00543                     // Find one
00544                     found = true;
00545                 }
00546                 else
00547                 {
00548                     // Come back
00549                     last = lastPrevious;
00550                     lastPrevious = lastPreviousPrevious;
00551                     break;
00552                 }
00553 
00554                 // Next vertex
00555                 lastPreviousPrevious = lastPrevious;
00556                 lastPrevious = last++;
00557                 if (last==vertexList.end())
00558                     last = vertexList.begin();
00559             }
00560 
00561             // Last polygon ?
00562             if (last==current)
00563             {
00564                 // Add a polygon
00565                 outputPolygons.push_back (CPolygon());
00566                 CPolygon &back = outputPolygons.back ();
00567                 back.Vertices.reserve (vertexList.size());
00568 
00569                 // Add each vertex in the new polygon
00570                 current=vertexList.begin();
00571                 while (current!=vertexList.end())
00572                 {
00573                     back.Vertices.push_back (Vertices[*current]);
00574                     current++;
00575                 }
00576 
00577                 // Exit
00578                 return true;
00579             }
00580             else
00581             {
00582                 std::list<uint>::iterator firstNext = current;
00583                 std::list<uint>::iterator firstNextNext = currentNext;
00584                 if (first != vertexList.begin())
00585                     first--;
00586                 else
00587                 {
00588                     first = vertexList.end();
00589                     first--;
00590                 }
00591 
00592                 while (current != first)
00593                 {
00594                     // Is a diagonal ?
00595                     if (
00596                         (toConvexPolygonsDiagonal (localVertices, root, *firstNextNext, *first)) &&
00597                         (toConvexPolygonsDiagonal (localVertices, root, *lastPrevious, *first)) &&
00598                         (toConvexPolygonsDiagonal (localVertices, root, *last, *first))
00599                         )
00600                     {
00601                         // Find one
00602                         found = true;
00603                     }
00604                     else
00605                     {
00606                         // Come back
00607                         first = firstNext;
00608                         break;
00609                     }
00610 
00611                     // Next vertex
00612                     firstNextNext = firstNext;
00613                     firstNext = first;
00614                     if (first==vertexList.begin())
00615                     {
00616                         first = vertexList.end();
00617                         first--;
00618                     }
00619                     else
00620                         first--;
00621                 }
00622             }
00623 
00624             // Found ?
00625             if (found)
00626             {
00627                 // Count vertex
00628                 outputPolygons.push_back (CPolygon());
00629                 CPolygon &back = outputPolygons.back ();
00630 
00631                 // Vertex count
00632                 uint vertexCount = 1;
00633                 current = first;
00634                 while (current != last)
00635                 {
00636                     vertexCount++;
00637                     current++;
00638                     if (current == vertexList.end())
00639                         current = vertexList.begin();
00640                 }
00641 
00642                 // Alloc vertices
00643                 back.Vertices.reserve (vertexCount);
00644 
00645                 // Copy and remove vertices
00646                 back.Vertices.push_back (Vertices[*first]);
00647                 first++;
00648                 if (first == vertexList.end())
00649                     first = vertexList.begin();
00650                 while (first != last)
00651                 {
00652                     back.Vertices.push_back (Vertices[*first]);
00653 
00654                     // Remove from list
00655                     first = vertexList.erase (first);
00656                     if (first == vertexList.end())
00657                         first = vertexList.begin();
00658                     nlassert (first != vertexList.end());
00659                 }
00660                 back.Vertices.push_back (Vertices[*first]);
00661                 current = begin = last;
00662                 goto again;
00663             }
00664 
00665             // Next current
00666             current++;
00667             if (current == vertexList.end())
00668                 current = vertexList.begin ();
00669         }
00670         while (current != begin);
00671     }
00672     return false;
00673 }
00674 
00675 // ***************************************************************************
00676 
00677 bool CPolygon::chain (const std::vector<CPolygon> &other, const CMatrix& basis)
00678 {
00679     // Local vertices
00680     std::vector<CVector>    localVertices;
00681 
00682     // Build the BSP root
00683     CBSPNode2v root;
00684 
00685     // Build the local array and the BSP
00686     toConvexPolygonsLocalAndBSP (localVertices, root, basis);
00687 
00688     // Local vertices
00689     std::vector<std::vector<CVector> >  localVerticesOther (other.size());
00690 
00691     // Build the BSP root
00692     std::vector<CBSPNode2v> rootOther (other.size());
00693 
00694     // Build a copy of the polygons
00695     std::vector<CPolygon> copy = other;
00696 
00697     // Main copy
00698     CPolygon mainCopy = *this;
00699 
00700     // For each other polygons
00701     uint o;
00702     for (o=0; o<other.size(); o++)
00703     {
00704         // Build the local array and the BSP
00705         other[o].toConvexPolygonsLocalAndBSP (localVerticesOther[o], rootOther[o], basis);
00706     }
00707 
00708     // Look for a couple..
00709     uint thisCount = Vertices.size();
00710     uint i, j;
00711     for (o=0; o<other.size(); o++)
00712     {
00713         uint otherCount = other[o].Vertices.size();
00714 
00715         // Try to link in the main polygon
00716         for (i=0; i<thisCount; i++)
00717         {
00718             for (j=0; j<otherCount; j++)
00719             {
00720                 // Test this segement
00721                 if (!root.intersect (localVertices[i], localVerticesOther[o][j], i, 0xffffffff))
00722                 {
00723                     // Test each other polygons
00724                     uint otherO;
00725                     for (otherO=0; otherO<other.size(); otherO++)
00726                     {
00727                         // Intersect ?
00728                         if (rootOther[otherO].intersect (localVertices[i], localVerticesOther[o][j], 0xffffffff, (otherO == o)?j:0xffffffff))
00729                             break;
00730                     }
00731 
00732                     // Continue ?
00733                     if (otherO==other.size())
00734                     {
00735                         // Insert new vertices
00736                         mainCopy.Vertices.insert (mainCopy.Vertices.begin()+i, 2+otherCount, CVector());
00737 
00738                         // Copy the first vertex
00739                         mainCopy.Vertices[i] = mainCopy.Vertices[i+otherCount+2];
00740 
00741                         // Copy the new vertices
00742                         uint k;
00743                         for (k=0; k<otherCount; k++)
00744                         {
00745                             uint index = j+k;
00746                             if (index>=otherCount)
00747                                 index -= otherCount;
00748                             mainCopy.Vertices[i+k+1] = copy[o].Vertices[index];
00749                         }
00750 
00751                         // Copy the last one
00752                         mainCopy.Vertices[i+otherCount+1] = copy[o].Vertices[j];
00753                         break;
00754                     }
00755                 }
00756             }
00757             if (j!=otherCount)
00758                 break;
00759         }
00760 
00761         // Not found ?
00762         if (i==thisCount)
00763         {
00764             // Try to link in the sub polygons
00765             uint otherToCheck;
00766             for (otherToCheck=o+1; otherToCheck<other.size(); otherToCheck++)
00767             {
00768                 uint otherToCheckCount = other[otherToCheck].Vertices.size();
00769                 for (i=0; i<otherToCheckCount; i++)
00770                 {
00771                     for (j=0; j<otherCount; j++)
00772                     {
00773                         // Test this segement
00774                         if (!rootOther[otherToCheck].intersect (localVerticesOther[otherToCheck][i], localVerticesOther[o][j], i, 0xffffffff))
00775                         {
00776                             // Test each other polygons
00777                             uint otherO;
00778                             for (otherO=0; otherO<other.size(); otherO++)
00779                             {
00780                                 // Intersect ?
00781                                 if (rootOther[otherO].intersect (localVerticesOther[otherToCheck][i], localVerticesOther[o][j],  (otherToCheck == otherO)?i:0xffffffff,  (otherO == o)?j:0xffffffff))
00782                                     break;
00783                             }
00784 
00785                             // Continue ?
00786                             if (otherO==other.size())
00787                             {
00788                                 // Insert new vertices
00789                                 copy[otherToCheck].Vertices.insert (copy[otherToCheck].Vertices.begin()+i, 2+otherCount, CVector());
00790 
00791                                 // Copy the first vertex
00792                                 copy[otherToCheck].Vertices[i] = copy[otherToCheck].Vertices[i+otherCount+2];
00793 
00794                                 // Copy the new vertices
00795                                 uint k;
00796                                 for (k=0; k<otherCount; k++)
00797                                 {
00798                                     uint index = j+k;
00799                                     if (index>=otherCount)
00800                                         index -= otherCount;
00801                                     copy[otherToCheck].Vertices[i+k+1] = copy[otherO].Vertices[index];
00802                                 }
00803 
00804                                 // Copy the last one
00805                                 copy[otherToCheck].Vertices[i+otherCount+1] = copy[otherO].Vertices[j];
00806                                 break;
00807                             }
00808                         }
00809                     }
00810                     if (j!=otherCount)
00811                         break;
00812                 }
00813                 if (i!=otherToCheckCount)
00814                     break;
00815             }
00816             if (otherToCheck==other.size())
00817             {
00818                 // Not ok
00819                 return false;
00820             }
00821         }
00822     }
00823 
00824     // Ok
00825     *this = mainCopy;
00826     return true;
00827 }
00828 
00829 // ***************************************************************************
00830 
00831 
00832 //====================================//
00833 //      CPolygon2d implementation     //
00834 //====================================//
00835 
00836 
00837 
00838 // ***************************************************************************
00839 CPolygon2D::CPolygon2D(const CPolygon &src, const CMatrix &projMat)
00840 {
00841     fromPolygon(src, projMat);
00842 }
00843 
00844 // ***************************************************************************
00845 void CPolygon2D::fromPolygon(const CPolygon &src, const CMatrix &projMat /*=CMatrix::Identity*/)
00846 {
00847     uint size = src.Vertices.size();
00848     Vertices.resize(size);
00849     for (uint k = 0; k < size; ++k)
00850     {
00851         CVector proj = projMat * src.Vertices[k];
00852         Vertices[k].set(proj.x, proj.y);
00853     }
00854 }
00855 
00856 // ***************************************************************************
00857 bool        CPolygon2D::isConvex()
00858 {
00859     bool Front  = true, Back = false;
00860     // we apply a dummy algo for now : check whether every vertex is in the same side
00861     // of every plane defined by a segment of this poly
00862     uint numVerts = Vertices.size();
00863     if (numVerts < 3) return true;
00864     CVector     segStart, segEnd;
00865     CPlane      clipPlane;
00866     for (TVec2fVect::const_iterator it = Vertices.begin(); it != Vertices.end(); ++it)
00867     {
00868         segStart.set(it->x, it->y, 0);            // segment start
00869         segEnd.set((it + 1)->x, (it + 1)->y, 0);  // segment end
00870         float n = (segStart - segEnd).norm();     // segment norm
00871         if (n != 0)
00872         {
00873             clipPlane.make(segStart, segEnd, (n > 10 ? n : 10) * CVector::K + segStart); // make a plane, with this segment and the poly normal
00874             // check each other vertices against this plane
00875             for (TVec2fVect::const_iterator it2 = Vertices.begin(); it2 != Vertices.end(); ++it2)
00876             {
00877                 if (it2 != it && it2 != (it + 1)) // the vertices must not be part of the test plane (because of imprecision)
00878                 {
00879 
00880                     float dist  = clipPlane * CVector(it2->x, it2-> y, 0);
00881                     if (dist != 0) // midlle pos
00882                     {
00883                         if (dist > 0) Front = true; else Back = true;
00884                         if (Front && Back) return false; // there are both front end back vertices -> failure
00885                     }
00886                 }
00887             }
00888         }
00889     }
00890     return true;
00891 }
00892 
00893 // ***************************************************************************
00894 
00895 void        CPolygon2D::buildConvexHull(CPolygon2D &dest) const
00896 {
00897     nlassert(&dest != this);
00898 
00899     if (this->Vertices.size() == 3) // with 3 points it is always convex
00900     {
00901         dest = *this;
00902         return;
00903     }
00904     uint k, l;
00905     uint numVerts = Vertices.size();
00906     CVector2f p, curr, prev;
00907     uint      pIndex, p1Index, p2Index, pCurr, pPrev;
00908     // this is not optimized, but not used in realtime.. =)
00909     nlassert(numVerts >= 3);
00910     dest.Vertices.clear();
00911 
00912     typedef std::set<uint> TIndexSet;
00913     TIndexSet leftIndex;
00914     for (k = 0; k < Vertices.size(); ++k)
00915     {
00916         leftIndex.insert(k);
00917     }
00918 
00919 
00920     // 1) find the highest point p of the set. We are sure it belongs to the hull
00921     pIndex = 0;
00922     p = Vertices[0];
00923     for (k = 1; k < numVerts; ++k)
00924     {
00925         if (Vertices[k].y < p.y)
00926         {
00927             pIndex = k;
00928             p = Vertices[k];
00929         }
00930     }
00931 
00932     leftIndex.erase(pIndex);
00933 
00934 
00935     float bestCP = 1.1f;
00936     p1Index = p2Index = pIndex;
00937 
00938     for (k = 0; k < numVerts; ++k)
00939     {
00940         if (k != pIndex)
00941         {
00942             for (l = 0; l < numVerts; ++l)
00943             {
00944                 if (l != pIndex && l != k)
00945                 {
00946                     CVector2f seg1 = (Vertices[l] - p).normed();
00947                     CVector2f seg2 = (Vertices[k] - p).normed();
00948 
00949                     //CVector cp = CVector(seg1.x, seg1.y, 0) ^ CVector(seg2.x, seg2.y, 0);
00950                     //float n = fabsf(cp.z);
00951                     float n = seg1 * seg2;
00952                     if (n < bestCP)
00953                     {
00954                         p1Index = l;
00955                         p2Index = k;
00956                         bestCP  = n;
00957                     }
00958                 }
00959             }
00960         }
00961     }
00962 
00963 
00964     leftIndex.erase(p2Index);
00965 
00966 
00967 
00968     // start from the given triplet, and complete the poly until we reach the first point
00969     pCurr = p2Index;
00970     pPrev = pIndex;
00971 
00972     curr = Vertices[pCurr];
00973     prev = Vertices[pPrev];
00974 
00975     // create the first triplet vertices
00976     dest.Vertices.push_back(Vertices[p1Index]);
00977     dest.Vertices.push_back(prev);
00978     dest.Vertices.push_back(curr);
00979 
00980     uint step = 0;
00981 
00982     for(;;)
00983     {
00984         bestCP = 1.1f;
00985         CVector2f seg2 = (prev - curr).normed();
00986         TIndexSet::iterator bestIt = leftIndex.end();
00987         for (TIndexSet::iterator it =  leftIndex.begin(); it != leftIndex.end(); ++it)
00988         {
00989             if (step == 0 && *it == p1Index) continue;
00990             CVector2f seg1 = (Vertices[*it] - curr).normed();
00991             float n = seg1 * seg2;
00992             if (n < bestCP)
00993             {
00994                 bestCP = n;
00995                 bestIt = it;
00996             }
00997         }
00998 
00999         nlassert(bestIt != leftIndex.end());
01000         if (*bestIt == p1Index)
01001         {
01002             return; // if we reach the start point we have finished
01003         }
01004         prev = curr;
01005         curr = Vertices[*bestIt];
01006         pPrev = pCurr;
01007         pCurr = *bestIt;
01008         // add new point to the destination
01009         dest.Vertices.push_back(curr);
01010         ++step;
01011         leftIndex.erase(bestIt);
01012     }
01013 }
01014 
01015 // ***************************************************************************
01016 
01017 
01018 void CPolygon2D::serial(NLMISC::IStream &f) throw(NLMISC::EStream)
01019 {
01020     (void)f.serialVersion(0);
01021     f.serialCont(Vertices);
01022 }
01023 
01024 // ***************************************************************************
01026 void        CPolygon2D::getBestTriplet(uint &index0, uint &index1, uint &index2)
01027 {
01028     nlassert(Vertices.size() >= 3);
01029     uint i, j, k;
01030     float bestArea = 0.f;
01031     const uint numVerts = Vertices.size();
01032     for (i = 0; i < numVerts; ++i)
01033     {
01034         for (j = 0; j < numVerts; ++j)
01035         {
01036             if (i != j)
01037             {
01038                 for (k = 0; k < numVerts; ++k)
01039                 {
01040                     if (k != i && k != j)
01041                     {
01042                         CVector2f v0 = Vertices[j] - Vertices[i];
01043                         CVector2f v1 = Vertices[k] - Vertices[i];
01044                         float area = fabsf((CVector(v0.x, v0.y, 0) ^ CVector(v1.x, v1.y, 0)).norm());
01045                         if (area > bestArea)
01046                         {
01047                             bestArea = area;
01048                             index0 = i;
01049                             index1 = j;
01050                             index2 = k;
01051                         }
01052                     }
01053                 }
01054             }
01055         }
01056     }
01057 }
01058 
01059 
01061 // scan a an edge of a poly and write it into a table
01062 static void ScanEdge(CPolygon2D::TRasterVect &outputVect, sint topY, const CVector2f &v1, const CVector2f &v2, bool rightEdge = true)
01063 {
01064      const uint rol16 = 65536;
01065      sint ceilY1 = (sint) ceilf(v1.y);
01066      sint height;
01067      float deltaX, deltaY;
01068      float fInverseSlope;
01069      sint  iInverseSlope, iPosX;
01070 
01071      // check whether this segment gives a contribution to the final poly
01072      height = (sint) (ceilf(v2.y) - ceilY1);
01073      if (height <= 0) return;
01074 
01075      // compute slope
01076      deltaY = v2.y - v1.y;
01077      deltaX = v2.x - v1.x;
01078      fInverseSlope = deltaX / deltaY;
01079 
01080 
01081      CPolygon2D::TRasterVect::iterator  outputIt = outputVect.begin() + (ceilY1 - topY);
01082 
01083      // slope with ints
01084      iInverseSlope = (sint) (rol16 * fInverseSlope);
01085 
01086      // sub-pixel accuracy
01087      iPosX = (int) (rol16 * (v1.x + fInverseSlope * (ceilY1 - v1.y)));
01088 
01089      const CPolygon2D::TRasterVect::iterator endIt = outputIt + height;
01090      if (rightEdge)
01091      {
01092          do
01093          {
01094            outputIt->second =  iPosX >> 16;
01095            iPosX += iInverseSlope;
01096            ++outputIt;
01097          }
01098          while (outputIt != endIt);
01099      }
01100      else
01101      {
01102          iPosX += (rol16 - 1);
01103          do
01104          {
01105            outputIt->first =  iPosX >> 16;
01106            iPosX += iInverseSlope;
01107            ++outputIt;
01108          }
01109          while (outputIt != endIt);
01110      }
01111 }
01112 
01113 
01114 // *******************************************************************************
01115 // This function alow to cycle forward through a vertex vector like if it was a circular list
01116 static inline CPolygon2D::TVec2fVect::const_iterator Next(const CPolygon2D::TVec2fVect::const_iterator &it, const CPolygon2D::TVec2fVect &cont)
01117 {
01118     nlassert(cont.size() != 0);
01119     if ((it + 1) == cont.end()) return cont.begin();
01120     return (it + 1);
01121 }
01122 
01123 
01124 // *******************************************************************************
01125 // This function alow to cycle backward through a (non null) vertex vector like if it was a circular list
01126 static inline CPolygon2D::TVec2fVect::const_iterator Prev(const CPolygon2D::TVec2fVect::const_iterator &it, const CPolygon2D::TVec2fVect &cont)
01127 {
01128     nlassert(cont.size() != 0);
01129     if (it == cont.begin()) return cont.end() - 1;
01130     return (it - 1);
01131 }
01132 
01133 
01134 // *******************************************************************************
01135 bool CPolygon2D::isCCWOriented() const
01136 {
01137     const TVec2fVect &V = Vertices;
01138     nlassert(Vertices.size() >= 3);
01139     // compute highest and lowest pos of the poly
01140     float fHighest = V[0].y;
01141     float fLowest = fHighest;
01142     // iterators to the highest and lowest vertex
01143     TVec2fVect::const_iterator it = V.begin() ;
01144     const TVec2fVect::const_iterator endIt = V.end();
01145     TVec2fVect::const_iterator pHighest = V.begin();
01146     do
01147     {
01148         if (it->y < fHighest)
01149         {
01150             fHighest = it->y;
01151             pHighest = it;
01152         }
01153         fLowest = std::max(fLowest, it->y);
01154         ++it;
01155     }
01156     while (it != endIt);
01157     // we seek this vertex
01158     TVec2fVect::const_iterator pHighestRight = pHighest;
01159     if (fLowest == fHighest)
01160     {
01161         // special case : degenerate poly
01162         while (pHighestRight->x == pHighest->x)
01163         {
01164             pHighestRight = Next(pHighestRight, V);
01165             if (pHighestRight == pHighest) return false; // the poly is reduced to a point, returns an abritrary value
01166         }
01167         return pHighest->x <= pHighestRight->x;
01168     }
01169     // iterator to the first vertex that has an y different from the top vertex
01170     while (Next(pHighestRight, V)->y == fHighest)
01171     {
01172         pHighestRight = Next(pHighestRight, V);
01173     }
01174 
01175     // iterator to the first vertex after pHighestRight, that has the same y than the highest vertex
01176     TVec2fVect::const_iterator pHighestLeft = Next(pHighestRight, V);
01177     // seek the vertex
01178     while (pHighestLeft->y != fHighest)
01179     {
01180         pHighestLeft = Next(pHighestLeft, V);
01181     }
01182     TVec2fVect::const_iterator pPrevHighestLeft = Prev(pHighestLeft, V);
01183     // we need to get the orientation of the polygon
01184     // There are 2 case : flat, and non-flat top
01185     // check for flat top
01186     if (pHighestLeft->x != pHighestRight->x)
01187     {
01188         // compare right and left side
01189         return pHighestLeft->x <= pHighestRight->x;
01190     }
01191     // The top of the poly is sharp
01192     // We perform a cross product of the 2 highest vect to get its orientation
01193      float deltaXN = Next(pHighestRight, V)->x - pHighestRight->x;
01194      float deltaYN = Next(pHighestRight, V)->y - pHighestRight->y;
01195      float deltaXP = pPrevHighestLeft->x - pHighestLeft->x;
01196      float deltaYP = pPrevHighestLeft->y - pHighestLeft->y;
01197      return (deltaXN * deltaYP - deltaYN * deltaXP) >= 0;
01198 }
01199 
01200 // *******************************************************************************
01201 void    CPolygon2D::computeBorders(TRasterVect &borders, sint &highestY) const
01202 {
01203     #ifdef NL_DEBUG
01204         checkValidBorders();
01205     #endif
01206     // an 'alias' to the vertices
01207     const TVec2fVect &V = Vertices;
01208     if (Vertices.size() < 3)
01209     {
01210         borders.clear();
01211         return;
01212     }
01213     bool    ccw;  // set to true when it has a counter clock wise orientation
01214 
01215     // compute highest and lowest pos of the poly
01216     float fHighest = V[0].y;
01217     float fLowest  = fHighest;
01218 
01219     // iterators to the thighest and lowest vertex
01220     TVec2fVect::const_iterator pLowest = V.begin(), pHighest = V.begin();
01221     TVec2fVect::const_iterator it = V.begin() ;
01222     const TVec2fVect::const_iterator endIt = V.end();
01223     do
01224     {
01225         if (it->y > fLowest)
01226         {
01227             fLowest = it->y;
01228             pLowest = it;
01229         }
01230         else
01231         if (it->y < fHighest)
01232         {
01233             fHighest = it->y;
01234             pHighest = it;
01235         }
01236         ++it;
01237     }
01238     while (it != endIt);
01239 
01240 
01241     sint iHighest = (sint) ceilf(fHighest) ;
01242     sint iLowest  = (sint) ceilf(fLowest) ;
01243 
01244     highestY = iHighest;
01245 
01246 
01248     uint polyHeight = iLowest - iHighest;
01249     if (polyHeight <= 0)
01250     {
01251         borders.clear();
01252         return;
01253     }
01254 
01255     borders.resize(polyHeight);
01256 
01257     // iterator to the first vertex that has an y different from the top vertex
01258     TVec2fVect::const_iterator pHighestRight = pHighest;
01259     // we seek this vertex
01260     while (Next(pHighestRight, V)->y == fHighest)
01261     {
01262         pHighestRight = Next(pHighestRight, V);
01263     }
01264 
01265     // iterator to the first vertex after pHighestRight, that has the same y than the highest vertex
01266     TVec2fVect::const_iterator pHighestLeft = Next(pHighestRight, V);
01267     // seek the vertex
01268     while (pHighestLeft->y != fHighest)
01269     {
01270         pHighestLeft = Next(pHighestLeft, V);
01271     }
01272 
01273     TVec2fVect::const_iterator pPrevHighestLeft = Prev(pHighestLeft, V);
01274 
01275     // we need to get the orientation of the polygon
01276     // There are 2 case : flat, and non-flat top
01277 
01278     // check for flat top
01279     if (pHighestLeft->x != pHighestRight->x)
01280     {
01281         // compare right and left side
01282         if (pHighestLeft->x > pHighestRight->x)
01283         {
01284             ccw = true;  // the list is CCW oriented
01285             std::swap(pHighestLeft, pHighestRight);
01286         }
01287         else
01288         {
01289             ccw = false; // the list is CW oriented
01290         }
01291     }
01292     else
01293     {
01294         // The top of the poly is sharp
01295         // We perform a cross product of the 2 highest vect to get its orientation
01296 
01297          const float deltaXN = Next(pHighestRight, V)->x - pHighestRight->x;
01298          const float deltaYN = Next(pHighestRight, V)->y - pHighestRight->y;
01299          const float deltaXP = pPrevHighestLeft->x - pHighestLeft->x;
01300          const float deltaYP = pPrevHighestLeft->y - pHighestLeft->y;
01301          if ((deltaXN * deltaYP - deltaYN * deltaXP) < 0)
01302          {
01303             ccw = true;  // the list is CCW oriented
01304             std::swap(pHighestLeft, pHighestRight);
01305          }
01306          else
01307          {
01308             ccw = false; // the list is CW oriented
01309          }
01310     }
01311 
01312 
01313     // compute borders
01314     TVec2fVect::const_iterator currV, nextV; // current and next vertex
01315     if (!ccw) // clock wise order ?
01316     {
01317         currV = pHighestRight ;
01318         // compute right edge from top to bottom
01319         do
01320         {
01321             nextV = Next(currV, V);
01322             ScanEdge(borders, iHighest, *currV, *nextV, true);
01323             currV = nextV;
01324         }
01325         while (currV != pLowest); // repeat until we reach the bottom vertex
01326 
01327         // compute left edge from bottom to top
01328         do
01329         {
01330             nextV = Next(currV, V);
01331             ScanEdge(borders, iHighest, *nextV, *currV, false);
01332             currV = nextV;
01333         }
01334         while (currV != pHighestLeft);
01335     }
01336     else // ccw order
01337     {
01338         currV = pHighestLeft;
01339         // compute left edge from top to bottom
01340         do
01341         {
01342             nextV = Next(currV, V);
01343             ScanEdge(borders, iHighest, *currV, *nextV, false) ;
01344             currV = nextV;
01345         }
01346         while (currV != pLowest) ;
01347 
01348         // compute right edge from bottom to top
01349         do
01350         {
01351             nextV = Next(currV, V);
01352             ScanEdge(borders, iHighest, *nextV, *currV, true);
01353             currV = nextV;
01354         }
01355         while (currV != pHighestRight)  ;
01356     }
01357 }
01358 
01359 //=========================================================================
01360 // scan outer right edge of a poly
01361 static void ScanOuterEdgeRight(CPolygon2D::TRaster *r, float x1, float y1, float x2, float y2, sint minY)
01362 {
01363     CPolygon2D::TRaster *currRaster;
01364     float deltaX, deltaY;
01365     float inverseSlope;
01366     sint32  iInverseSlope, iposx;
01367     sint  height;
01368     deltaX = x2 - x1;
01369     height = (sint) (ceilf(y2) - floorf(y1)) ;
01370     if (height <= 0) return;
01371     if (deltaX >= 0.f)
01372     {
01373         if (height == 1)
01374         {
01375             currRaster = r + ((sint) floorf(y1) - minY);
01376             currRaster->second = std::max((sint) floorf(x2), currRaster->second);
01377         }
01378         else
01379         {
01380             deltaY = y2 - y1;
01381             if(deltaY)
01382                 inverseSlope = deltaX / deltaY;
01383             else
01384                 inverseSlope = 0;
01385             iInverseSlope = (sint32) (65536.0 * inverseSlope);
01386             currRaster = r + ((sint) floorf(y1) - minY);
01387             iposx = (sint32) (65536.0 * (x1 + inverseSlope * (ceilf(y1) - y1))); // sub-pixel accuracy
01388             if (ceilf(y1) == y1)
01389             {
01390                 iposx += iInverseSlope;
01391             }
01392             do
01393             {
01394                 currRaster->second = std::max((sint) (iposx >> 16), currRaster->second);
01395                 iposx += iInverseSlope;
01396                 ++ currRaster;
01397                 -- height;
01398             }
01399             while (height != 1);
01400             // correction for last line
01401             currRaster->second = std::max((sint) floorf(x2), currRaster->second);
01402         }
01403     }
01404     else
01405     {
01406         deltaY = y2 - y1;
01407         if(deltaY)
01408             inverseSlope = deltaX / deltaY;
01409         else
01410             inverseSlope = 0;
01411         iInverseSlope = (sint32) (65536.0 * inverseSlope);
01412         currRaster = r + ((sint) floorf(y1) - minY);
01413         currRaster->second = std::max((sint) floorf(x1), currRaster->second);
01414         ++ currRaster;
01415         iposx = (sint32) (65536.0 * (x1 + inverseSlope * (ceilf(y1) - y1))); // sub-pixel accuracy
01416         if (ceilf(y1) == y1)
01417         {
01418             iposx += iInverseSlope;
01419         }
01420         while (--height)
01421         {
01422             currRaster->second = std::max((sint) (iposx >> 16), currRaster->second);
01423             iposx += iInverseSlope;
01424             ++ currRaster;
01425         }
01426     }
01427 }
01428 
01429 //=========================================================================
01430 // scan outer left edge of a poly
01431 static void ScanOuterEdgeLeft(CPolygon2D::TRaster *r, float x1, float y1, float x2, float y2, sint minY)
01432 {
01433     CPolygon2D::TRaster *currRaster;
01434     float deltaX, deltaY;
01435     float inverseSlope;
01436     sint32   iInverseSlope, iposx;
01437     sint  height;
01438     deltaX = x2 - x1;
01439     height = (sint) (ceilf(y2) - floorf(y1)) ;
01440     if (height <= 0) return;
01441     if (deltaX < 0.f)
01442     {
01443         if (height == 1)
01444         {
01445             currRaster = r + ((sint) floorf(y1) - minY);
01446             currRaster->first = std::min((sint) floorf(x2), currRaster->first);
01447         }
01448         else
01449         {
01450             deltaY = y2 - y1;
01451             if(deltaY)
01452                 inverseSlope = deltaX / deltaY;
01453             else
01454                 inverseSlope = 0;
01455             iInverseSlope = (sint32) (65536.0 * inverseSlope);
01456             currRaster = r + ((sint) floorf(y1) - minY);
01457             iposx = (sint32) (65536.0 * (x1 + inverseSlope * (ceilf(y1) - y1))); // sub-pixel accuracy
01458             if (ceilf(y1) == y1)
01459             {
01460                 iposx += iInverseSlope;
01461             }
01462             do
01463             {
01464                 currRaster->first = std::min((sint) (iposx >> 16), currRaster->first);
01465                 iposx += iInverseSlope;
01466                 ++ currRaster;
01467                 -- height;
01468             }
01469             while (height != 1);
01470             // correction for last line
01471             currRaster->first = std::min((sint) floorf(x2), currRaster->first);
01472         }
01473     }
01474     else
01475     {
01476         deltaY = y2 - y1;
01477         if(deltaY)
01478             inverseSlope = deltaX / deltaY;
01479         else
01480             inverseSlope = 0;
01481         iInverseSlope = (sint32) (65536.0 * inverseSlope);
01482         currRaster = r + ((sint) floorf(y1) - minY);
01483         currRaster->first = std::min((sint) floorf(x1), currRaster->first);
01484         ++ currRaster;
01485         iposx = (sint32) (65536.0 * (x1 + inverseSlope * (ceilf(y1) - y1))); // sub-pixel accuracy
01486         if (ceilf(y1) == y1)
01487         {
01488             iposx += iInverseSlope;
01489         }
01490         while (--height)
01491         {
01492             currRaster->first = std::min((sint) (iposx >> 16), currRaster->first);
01493             iposx += iInverseSlope;
01494             ++ currRaster;
01495         }
01496     }
01497 }
01498 
01499 
01500 // *******************************************************************************
01501 void CPolygon2D::computeOuterBorders(TRasterVect &borders, sint &minimumY) const
01502 {
01503     #ifdef NL_DEBUG
01504         checkValidBorders();
01505     #endif
01506     borders.clear();
01507     // NB : this version is not much optimized, because of the min/max test
01508     // during rasterization.
01509     // TODO : optimize if needed ...
01510 
01511     if (Vertices.empty())
01512     {
01513         minimumY = -1;
01514         return;
01515     }
01516     const CVector2f *first = &Vertices[0];
01517     const CVector2f *last  = first + Vertices.size();
01518 
01519     const CVector2f *curr = first, *next, *plowest ,*phighest;
01520     const CVector2f *pHighestRight, *pHighestRightNext, *pHighestLeft;
01521     const CVector2f *pPrevHighestLeft;
01522     double          deltaXN, deltaYN, deltaXP, deltaYP;
01523     bool            ccw;  // true if CCW oriented
01524     sint            polyHeight;
01525     sint            highest, lowest;
01526 
01527     float fright   = curr->x;
01528     float fleft    = curr->x;
01529     float fhighest = curr->y;
01530     float flowest  = curr->y;
01531     plowest = phighest = curr;
01532 
01533     // compute highest and lowest pos of the poly
01534     do
01535     {
01536         fright = std::max(fright, curr->x);
01537         fleft  = std::min(fleft, curr->x);
01538         if (curr->y > flowest)
01539         {
01540             flowest = curr->y;
01541             plowest = curr;
01542         }
01543         if (curr->y < fhighest)
01544         {
01545             fhighest = curr->y;
01546             phighest = curr;
01547         }
01548         ++curr;
01549     }
01550     while (curr != last);
01551 
01552 
01553     highest = (sint) floorf(fhighest);
01554     lowest = (sint) floorf(flowest);
01555 
01556     polyHeight = lowest - highest + 1;
01557     nlassert(polyHeight > 0);
01558 
01559     // make room for rasters
01560     borders.resize(polyHeight);
01561     // fill with xmin / xman
01562     sint ileft = (sint) floorf(fleft);
01563     sint iright = (sint) ceilf(fright);
01564     minimumY = highest;
01565     if (flowest == fhighest) // special case : degenerate poly
01566     {
01567 
01568         borders.resize(1);
01569         borders.front().first =  ileft;
01570         borders.front().second =  ileft;
01571         return;
01572     }
01573     //
01574     for(TRasterVect::iterator it = borders.begin(); it != borders.end(); ++it)
01575     {
01576         it->second = ileft;
01577         it->first = iright;
01578     }
01579 
01580 
01581 
01582     pHighestRight = phighest;
01583     for (;;)
01584     {
01585         pHighestRightNext  = pHighestRight + 1;
01586         if (pHighestRightNext == last) pHighestRightNext = first;
01587         if (pHighestRightNext->y != pHighestRight->y) break;
01588         pHighestRight = pHighestRightNext;
01589     }
01590 
01591     pPrevHighestLeft = pHighestRight;
01592     pHighestLeft = pHighestRight;
01593     ++pHighestLeft;
01594     if (pHighestLeft == last) pHighestLeft = first;
01595 
01596     while (pHighestLeft->y != fhighest)
01597     {
01598         pPrevHighestLeft = pHighestLeft;
01599         ++pHighestLeft;
01600         if (pHighestLeft == last) pHighestLeft = first;
01601     }
01602 
01603 
01604     // we need to get the orientation of the polygon
01605     // There are 2 case : flat, and non-flat top
01606 
01607     // check for flat top
01608     if (pHighestLeft->x != pHighestRight->x)
01609     {
01610         // compare right and left side
01611         if (pHighestLeft->x > pHighestRight->x)
01612         {
01613             ccw = true;  // the list is CCW oriented
01614             std::swap(pHighestLeft, pHighestRight);
01615         }
01616         else
01617         {
01618             ccw = false; // the list is CW oriented
01619         }
01620     }
01621     else
01622     {
01623         pHighestRightNext = pHighestRight + 1;
01624         if (pHighestRightNext == last) pHighestRightNext = first;
01625          deltaXN = pHighestRightNext->x - pHighestRight->x;
01626          deltaYN = pHighestRightNext->y - pHighestRight->y;
01627          deltaXP = pPrevHighestLeft->x - pHighestLeft->x;
01628          deltaYP = pPrevHighestLeft->y - pHighestLeft->y;
01629          if ((deltaXN * deltaYP - deltaYN * deltaXP) < 0)
01630          {
01631             ccw = true;
01632             std::swap(pHighestLeft, pHighestRight);
01633          }
01634          else
01635          {
01636             ccw = false;
01637          }
01638     }
01639 
01640     if (!ccw)
01641     {
01642         // clock wise oriented list
01643         curr = pHighestRight;
01644         do
01645         {
01646             next = curr + 1;
01647             if (next == last) next = first;
01648             ScanOuterEdgeRight(&borders[0], curr->x, curr->y, next->x, next->y, minimumY);
01649             curr = next;
01650         }
01651         while (curr != plowest);
01652         do
01653         {
01654             next = curr + 1;
01655             if (next == last) next = first;
01656             ScanOuterEdgeLeft(&borders[0], next->x, next->y, curr->x, curr->y, minimumY);
01657             curr = next;
01658         }
01659         while (curr != pHighestLeft);
01660     }
01661     else
01662     {
01663         // ccw oriented
01664         curr = pHighestLeft;
01665         do
01666         {
01667             next = curr + 1;
01668             if (next == last) next = first;
01669             ScanOuterEdgeLeft(&borders[0], curr->x, curr->y, next->x, next->y, minimumY);
01670             curr = next;
01671         }
01672         while (curr != plowest);
01673         do
01674         {
01675             next = curr + 1;
01676             if (next == last) next = first;
01677             ScanOuterEdgeRight(&borders[0], next->x, next->y, curr->x, curr->y, minimumY);
01678             curr = next;
01679         }
01680         while (curr != pHighestRight);
01681     }
01682 }
01683 
01684 
01685 //=========================================================================
01686 // scan inner right edge of a poly
01687 static void ScanInnerEdge(CPolygon2D::TRaster *r, float x1, float y1, float x2, float y2, sint minY, bool rightEdge)
01688 {
01689     const uint rol16 = 65536;
01690     CPolygon2D::TRaster *currRaster;
01691     float deltaX, deltaY;
01692     float inverseSlope;
01693     sint32  iInverseSlope, iposx;
01694     sint  height;
01695     deltaX = x2 - x1;
01696     height = (sint) (ceilf(y2) - floorf(y1));
01697     if (height <= 0) return;
01698     deltaY = y2 - y1;
01699     if(deltaY)
01700         inverseSlope = deltaX / deltaY;
01701     else
01702         inverseSlope = 0;
01703     iInverseSlope = (sint32) (rol16 * inverseSlope);
01704     currRaster = r + ((sint) floorf(y1) - minY);
01705     //
01706     iposx = (sint32) (rol16 * (x1 + inverseSlope * (ceilf(y1) - y1))); // sub-pixel accuracy
01707     if (rightEdge)
01708     {
01709         iposx -= rol16 - 1;
01710         if (deltaX >= 0.f)
01711         {
01712             // start of segment
01713             if (floorf(y1) != y1)
01714             {
01715                 currRaster->second = std::min((sint) floorf(x1) - 1, currRaster->second);
01716                 ++ currRaster;
01717                 -- height;
01718                 if (height == 0) return;
01719             }
01720             do
01721             {
01722                 currRaster->second = std::min((sint) (iposx >> 16), currRaster->second);
01723                 iposx += iInverseSlope;
01724                 ++ currRaster;
01725             }
01726             while (--height);
01727         }
01728         else
01729         {
01730             // start of segment
01731             if (floorf(y1) != y1)
01732             {
01733                 currRaster->second = std::min((sint) (iposx >> 16), currRaster->second);
01734                 ++ currRaster;
01735                 -- height;
01736                 if (height == 0) return;
01737             }
01738             while (--height)
01739             {
01740                 iposx += iInverseSlope;
01741                 currRaster->second = std::min((sint) (iposx >> 16), currRaster->second);
01742                 ++ currRaster;
01743             }
01744             // fill bottom of segment
01745             currRaster->second = std::min((sint) floorf(x2) - 1, currRaster->second);
01746         }
01747     }
01748     else
01749     {
01750         iposx += rol16 - 1;
01751         if (deltaX < 0.f)
01752         {
01753             // start of segment
01754             if (floorf(y1) != y1)
01755             {
01756                 currRaster->first = std::max((sint) ceilf(x1), currRaster->first);
01757                 ++ currRaster;
01758                 -- height;
01759                 if (height == 0) return;
01760             }
01761             do
01762             {
01763                 currRaster->first = std::max((sint) (iposx >> 16), currRaster->first);
01764                 iposx += iInverseSlope;
01765                 ++ currRaster;
01766             }
01767             while (--height);
01768         }
01769         else
01770         {
01771             // start of segment
01772             if (floorf(y1) != y1)
01773             {
01774                 currRaster->first = std::max((sint) (iposx >> 16), currRaster->first);
01775                 ++ currRaster;
01776                 -- height;
01777                 if (height == 0) return;
01778             }
01779             while (--height)
01780             {
01781                 iposx += iInverseSlope;
01782                 currRaster->first = std::max((sint) (iposx >> 16), currRaster->first);
01783                 ++ currRaster;
01784             }
01785             // fill bottom of segment
01786             currRaster->first = std::max((sint) ceilf(x2), currRaster->first);
01787         }
01788     }
01789 }
01790 
01791 // *******************************************************************************
01792 void CPolygon2D::computeInnerBorders(TRasterVect &borders, sint &minimumY) const
01793 {
01794     #ifdef NL_DEBUG
01795         checkValidBorders();
01796     #endif
01797     borders.clear();
01798     if (Vertices.empty())
01799     {
01800         minimumY = -1;
01801         return;
01802     }
01803     const CVector2f *first = &Vertices[0];
01804     const CVector2f *last  = first + Vertices.size();
01805 
01806     const CVector2f *curr = first, *next, *plowest ,*phighest;
01807     const CVector2f *pHighestRight, *pHighestRightNext, *pHighestLeft;
01808     const CVector2f *pPrevHighestLeft;
01809     double          deltaXN, deltaYN, deltaXP, deltaYP;
01810     bool            ccw;  // true if CCW oriented
01811     sint            polyHeight;
01812     sint            highest, lowest;
01813 
01814     float fright   = curr->x;
01815     float fleft    = curr->x;
01816     float fhighest = curr->y;
01817     float flowest  = curr->y;
01818     plowest = phighest = curr;
01819 
01820     // compute highest (with lowest y) and lowest (with highest y) points of the poly
01821     do
01822     {
01823         fright = std::max(fright, curr->x);
01824         fleft  = std::min(fleft, curr->x);
01825         if (curr->y > flowest)
01826         {
01827             flowest = curr->y;
01828             plowest = curr;
01829         }
01830         if (curr->y < fhighest)
01831         {
01832             fhighest = curr->y;
01833             phighest = curr;
01834         }
01835         ++curr;
01836     }
01837     while (curr != last);
01838     if (flowest == fhighest)
01839     {
01840         minimumY = -1;
01841         return;
01842     }
01843     highest = (sint) floorf(fhighest);
01844     lowest = (sint) ceilf(flowest);
01845 
01846     polyHeight = lowest - highest;
01847     minimumY = highest;
01848     if (polyHeight == 0)
01849     {
01850         minimumY = -1;
01851         return;
01852     }
01853     // make room for rasters
01854     borders.resize(polyHeight);
01855     // fill with xmin / xman
01856     sint ileft = (sint) floorf(fleft) - 1;
01857     sint iright = (sint) ceilf(fright);
01858     for(TRasterVect::iterator it = borders.begin(); it != borders.end(); ++it)
01859     {
01860         it->second = iright;
01861         it->first = ileft;
01862     }
01863     pHighestRight = phighest;
01864     for (;;)
01865     {
01866         pHighestRightNext  = pHighestRight + 1;
01867         if (pHighestRightNext == last) pHighestRightNext = first;
01868         if (pHighestRightNext->y != pHighestRight->y) break;
01869         pHighestRight = pHighestRightNext;
01870     }
01871 
01872     pPrevHighestLeft = pHighestRight;
01873     pHighestLeft = pHighestRight;
01874     ++pHighestLeft;
01875     if (pHighestLeft == last) pHighestLeft = first;
01876 
01877     while (pHighestLeft->y != fhighest)
01878     {
01879         pPrevHighestLeft = pHighestLeft;
01880         ++pHighestLeft;
01881         if (pHighestLeft == last) pHighestLeft = first;
01882     }
01883 
01884 
01885     // we need to get the orientation of the polygon
01886     // There are 2 case : flat, and non-flat top
01887 
01888     // check for flat top
01889     if (pHighestLeft->x != pHighestRight->x)
01890     {
01891         // compare right and left side
01892         if (pHighestLeft->x > pHighestRight->x)
01893         {
01894             ccw = true;  // the list is CCW oriented
01895             std::swap(pHighestLeft, pHighestRight);
01896         }
01897         else
01898         {
01899             ccw = false; // the list is CW oriented
01900         }
01901     }
01902     else
01903     {
01904         pHighestRightNext = pHighestRight + 1;
01905         if (pHighestRightNext == last) pHighestRightNext = first;
01906          deltaXN = pHighestRightNext->x - pHighestRight->x;
01907          deltaYN = pHighestRightNext->y - pHighestRight->y;
01908          deltaXP = pPrevHighestLeft->x - pHighestLeft->x;
01909          deltaYP = pPrevHighestLeft->y - pHighestLeft->y;
01910          if ((deltaXN * deltaYP - deltaYN * deltaXP) < 0)
01911          {
01912             ccw = true;
01913             std::swap(pHighestLeft, pHighestRight);
01914          }
01915          else
01916          {
01917             ccw = false;
01918          }
01919     }
01920 
01921     if (!ccw)
01922     {
01923         // cw oriented
01924         curr = pHighestRight;
01925         do
01926         {
01927             next = curr + 1;
01928             if (next == last) next = first;
01929             ScanInnerEdge(&borders[0], curr->x, curr->y, next->x, next->y, minimumY, true);
01930             curr = next;
01931         }
01932         while (curr != plowest);
01933         do
01934         {
01935             next = curr + 1;
01936             if (next == last) next = first;
01937             ScanInnerEdge(&borders[0], next->x, next->y, curr->x, curr->y, minimumY, false);
01938             curr = next;
01939         }
01940         while (curr != pHighestLeft);
01941     }
01942     else
01943     {
01944         // ccw oriented
01945         curr = pHighestLeft;
01946         do
01947         {
01948             next = curr + 1;
01949             if (next == last) next = first;
01950             ScanInnerEdge(&borders[0], curr->x, curr->y, next->x, next->y, minimumY, false);
01951             curr = next;
01952         }
01953         while (curr != plowest);
01954         do
01955         {
01956             next = curr + 1;
01957             if (next == last) next = first;
01958             ScanInnerEdge(&borders[0], next->x, next->y, curr->x, curr->y, minimumY, true);
01959             curr = next;
01960         }
01961         while (curr != pHighestRight);
01962     }
01963     // fix for top
01964     if (floorf(fhighest) != fhighest)
01965     {
01966         borders[0].first = 1;
01967         borders[0].second = 0;
01968     }
01969     // fix for bottom
01970     if (floorf(flowest) != flowest)
01971     {
01972         borders.back().first = 1;
01973         borders.back().second = 0;
01974     }
01975 }
01976 
01977 // *******************************************************************************
01978 void CPolygon2D::checkValidBorders() const
01979 {
01980     for (uint k = 0; k < Vertices.size(); ++k)
01981     {
01982         nlassert(Vertices[k].x >= -32000.f); // coordinate too big !
01983         nlassert(Vertices[k].x < 32000.f);   // coordinate too big !
01984         nlassert(Vertices[k].y >= -32000.f); // coordinate too big !
01985         nlassert(Vertices[k].y < 32000.f);   // coordinate too big !
01986     }
01987 }
01988 
01989 // *******************************************************************************
01991 float       CPolygon2D::sumDPAgainstLine(float a, float b, float c) const
01992 {
01993     float sum = 0.f;
01994     for (uint k = 0; k < Vertices.size(); ++k)
01995     {
01996         const CVector2f &p = Vertices[k];
01997         sum += a * p.x + b * p.y + c;
01998     }
01999     return sum;
02000 }
02001 
02002 
02003 // *******************************************************************************
02004 bool  CPolygon2D::getNonNullSeg(uint &index) const
02005 {
02006     nlassert(Vertices.size() > 0);
02007     float bestLength = 0.f;
02008     sint  bestIndex = -1;
02009     for (uint k = 0; k < Vertices.size() - 1; ++k)
02010     {
02011         float norm2 = (Vertices[k + 1] - Vertices[k]).sqrnorm();
02012         if ( norm2 > bestLength)
02013         {
02014             bestLength = norm2;
02015             bestIndex = (int) k;
02016         }
02017     }
02018     float norm2 = (Vertices[Vertices.size() - 1] - Vertices[0]).sqrnorm();
02019     if ( norm2 > bestLength)
02020     {
02021         index = Vertices.size() - 1;
02022         return true;
02023     }
02024 
02025     if (bestIndex != -1)
02026     {
02027         index = bestIndex;
02028         return true;
02029     }
02030     else
02031     {
02032         return false;
02033     }
02034 }
02035 
02036 
02037 // *******************************************************************************
02038 void  CPolygon2D::getLineEquation(uint index, float &a, float &b, float &c) const
02039 {
02040     nlassert(index < Vertices.size());
02041     const CVector2f &v0 = getSegRef0(index);
02042     const CVector2f &v1 = getSegRef1(index);
02043 
02044     NLMISC::CVector2f seg = v0 - v1;
02045     a = seg.y;
02046     b = - seg.x;
02047     c = - v0.x * a - v0.y * b;
02048 }
02049 
02050 // *******************************************************************************
02051 bool        CPolygon2D::intersect(const CPolygon2D &other) const
02052 {
02053     nlassert(other.Vertices.size() > 0);
02054     uint nonNullSegIndex;
02056     if (getNonNullSeg(nonNullSegIndex))
02057     {
02058         float a0, b0, c0; 
02059         getLineEquation(nonNullSegIndex, a0, b0, c0);
02060         float orient = sumDPAgainstLine(a0, b0, c0);
02061 
02062         for (uint k = 0; k < Vertices.size(); ++k)
02063         {
02065             if ( (getSegRef0(k) - getSegRef1(k)).sqrnorm() == 0.f) continue;
02066 
02068             float a, b, c; 
02069             getLineEquation(k, a, b, c);
02070             uint l;
02071             for (l = 0; l < other.Vertices.size(); ++l)
02072             {
02073                 const CVector2f &ov = other.Vertices[l];
02074                 if ( orient * (ov.x * a + ov.y * b +c) > 0.f) break;
02075             }
02076             if (l == other.Vertices.size()) // all point on the outside
02077             {
02078                 return false; // outside
02079             }
02080         }
02081         return true;
02082     }
02083     else // this poly is just a point
02084     {
02085         return other.contains(Vertices[0]);
02086     }
02087 }
02088 
02089 // *******************************************************************************
02090 bool        CPolygon2D::contains(const CVector2f &p, bool hintIsConvex /*= true*/) const
02091 {
02092     if (hintIsConvex)
02093     {
02094         uint numVerts = Vertices.size();
02095         nlassert(numVerts >= 0.f);
02096         for (uint k = 0; k < numVerts; ++k)
02097         {
02098             if (getSegRef0(k) != getSegRef1(k))
02099             {
02100                 float a, b, c; 
02101                 getLineEquation(k, a, b, c);
02102                 float orient = a * p.x + b * p.y + c;
02103                 for(uint l = k + 1; l < numVerts; ++l)
02104                 {
02105                     getLineEquation(l, a, b, c);
02106                     float newOrient = a * p.x + b * p.y + c;
02107                     if (newOrient * orient < 0.f) return false;
02108                 }
02109                 return true;
02110             }
02111         }
02112         // the poly reduces to a point
02113         return p == Vertices[0];
02114     }
02115     else
02116     {
02117         // concave case
02118         static std::vector<float> xInter;
02119         xInter.clear();
02120         for(uint k = 0; k < Vertices.size(); ++k)
02121         {
02122             const CVector2f &p0 = getSegRef0(k);
02123             const CVector2f &p1 = getSegRef1(k);
02124             if (p0.y == p1.y)
02125             {
02126                 if (p.y == p0.y)
02127                 {
02128                     if ((p.x >= p0.x && p.x <= p1.x)
02129                         || (p.x >= p1.x && p.x <= p0.x))
02130                     {
02131                         return true;
02132                     }
02133                 }
02134             }
02135             if ((p.y >= p0.y && p.y < p1.y) ||
02136                 (p.y >= p1.y && p.y < p0.y)
02137                )
02138             {
02139 
02140                 float inter = p0.x + (p.y - p0.y) * (p1.x - p0.x) / (p1.y- p0.y);
02141                 xInter.push_back(inter);
02142             }
02143         }
02144         if (xInter.size() < 2) return false;
02145         std::sort(xInter.begin(), xInter.end());
02146         for(uint k = 0; k < xInter.size() - 1; ++k)
02147         {
02148             if (p.x >= xInter[k] && p.x <= xInter[k + 1])
02149             {
02150                 return (k & 1) == 0;
02151             }
02152         }
02153         return false;
02154     }
02155 }
02156 
02157 
02158 // *******************************************************************************
02159 CPolygon2D::CPolygon2D(const CTriangle &tri, const CMatrix &projMat)
02160 {
02161     Vertices.resize(3);
02162     NLMISC::CVector proj[3] = { projMat * tri.V0, projMat * tri.V1, projMat * tri.V2 };
02163     Vertices[0].set(proj[0].x, proj[0].y);
02164     Vertices[1].set(proj[1].x, proj[1].y);
02165     Vertices[2].set(proj[2].x, proj[2].y);
02166 }
02167 
02168 // *******************************************************************************
02169 void CPolygon2D::getBoundingRect(CVector2f &minCorner, CVector2f &maxCorner) const
02170 {
02171     nlassert(!Vertices.empty())
02172     minCorner = maxCorner = Vertices[0];
02173     uint numVertices = Vertices.size();
02174     for(uint k = 0; k < numVertices; ++k)
02175     {
02176         minCorner.minof(minCorner, Vertices[k]);
02177         maxCorner.maxof(minCorner, Vertices[k]);
02178     }
02179 }
02180 
02181 // *******************************************************************************
02182 bool operator ==(const CPolygon2D &lhs,const CPolygon2D &rhs)
02183 {
02184     if (lhs.Vertices.size() != rhs.Vertices.size()) return false;
02185     return std::equal(lhs.Vertices.begin(), lhs.Vertices.end(), rhs.Vertices.begin());
02186 }
02187 
02188 // *******************************************************************************
02189 bool operator < (const CPolygon2D &lhs, const CPolygon2D &rhs)
02190 {
02191     if (lhs.Vertices.size() != rhs.Vertices.size()) return lhs.Vertices.size() < rhs.Vertices.size();
02192     for(uint k = 0; k < lhs.Vertices.size(); ++k)
02193     {
02194         if (lhs.Vertices[k] != rhs.Vertices[k]) return lhs.Vertices[k] < rhs.Vertices[k];
02195     }
02196     return false;
02197 }
02198 
02199 
02200 // *******************************************************************************
02201 static inline bool testSegmentIntersection(const CVector2f &a, const CVector2f &b,
02202                                            const CVector2f &c, const CVector2f &d)
02203 {
02204     double denom = a.x * double(d.y - c.y) +
02205             b.x * double(c.y - d.y) +
02206             d.x * double(b.y - a.y) +
02207             c.x * double(a.y - b.y);
02208 
02209     if (denom == 0) return false;
02210     //
02211     double num = a.x * double(d.y - c.y) +
02212                  c.x * double(a.y - d.y) +
02213                  d.x * double(c.y - a.y);
02214 
02215     if (num == 0 || (num == denom)) return false;
02216     double lambda = num / denom;
02217     if (lambda <= 0 || lambda >= 1) return false;
02218     //
02219     num = - (a.x * double(c.y - b.y) +
02220           b.x * double(a.y - c.y) +
02221           c.x * double(b.y - a.y));
02222 
02223     if (num == 0 || (num == denom)) return false;
02224     lambda = num / denom;
02225     if (lambda <= 0 || lambda >= 1) return false;
02226     return true;
02227 }
02228 
02229 
02230 // *******************************************************************************
02231 bool CPolygon2D::selfIntersect() const
02232 {
02233     if (Vertices.size() < 3) return false;
02234     uint numEdges = Vertices.size();
02235     for(uint k = 0; k < numEdges; ++k)
02236     {
02237         // test intersection with all other edges that don't share a vertex with this one
02238         const CVector2f &p0 = getSegRef0(k);
02239         const CVector2f &p1 = getSegRef1(k);
02240         for(uint l = 0; l < k; ++l)
02241         {
02242             const CVector2f &v0 = getSegRef0(l);
02243             const CVector2f &v1 = getSegRef1(l);
02244             if (v0 == p0 || v0 == p1 || v1 == p0 || v1 == p1) continue;
02245             //
02246             if (testSegmentIntersection(p0, p1, v0, v1)) return true;
02247         }
02248     }
02249     return false;
02250 }
02251 
02252 
02253 
02254 } // NLMISC
02255 
02256 
02257 
02258 
02259 
02260 
02261 
02262 
02263 
02264 
02265 
02266 
02267 
02268 
02269 
02270 
02271 
02272 
02273 
02274 
02275 

Generated on Thu Jan 7 08:26:34 2010 for NeL by  doxygen 1.6.1