00001
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
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
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
00083
00084 static vector<CVector> tab0, tab1;
00085 tab0.resize(getNumVertices()+nPlanes);
00086 tab1.resize(getNumVertices()+nPlanes);
00087
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
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
00189 float Length;
00190
00191
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
00201 if( a0.x-a1.x==0 && b0.x-b1.x==0 )
00202 return false;
00203
00204
00205 CVector2f intersection;
00206
00207
00208 if(a0.x - a1.x==0)
00209 {
00210 float Ab = (b0.y - b1.y) / (b0.x - b1.x);
00211
00212
00213 intersection.x = a0.x;
00214 intersection.y = b0.y + (a0.x-b0.x) * Ab;
00215 }
00216
00217 else if(b0.x - b1.x==0)
00218 {
00219 float Aa = (a0.y - a1.y) / (a0.x - a1.x);
00220
00221
00222 intersection.x = b0.x;
00223 intersection.y = a0.y + (b0.x-a0.x) * Aa;
00224 }
00225
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
00234 if(Aa==Ab)
00235 return false;
00236
00237
00238 intersection.x = (Bb - Ba) / (Aa - Ab);
00239 intersection.y = Aa * intersection.x + Ba;
00240 }
00241
00242
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
00275 bool p0Front = (Plane * node->P0) > 0;
00276 bool p1Front = (Plane * node->P1) > 0;
00277 if (p0Front && p1Front)
00278 {
00279
00280 if (Front)
00281 Front->insert (node);
00282 else
00283 {
00284
00285 Front = node;
00286 node->Parent = this;
00287 }
00288 }
00289 else if ((!p0Front) && (!p1Front))
00290 {
00291
00292 if (Back)
00293 Back->insert (node);
00294 else
00295 {
00296
00297 Back = node;
00298 node->Parent = this;
00299 }
00300 }
00301 else
00302 {
00303
00304 CVector newVertex = Plane.intersect (node->P0, node->P1);
00305
00306
00307 CBSPNode2v *newNode = new CBSPNode2v (node->Plane, node->P0, newVertex, node->V0, node->V1);
00308
00309
00310 node->P0 = newVertex;
00311
00312
00313 CBSPNode2v **p0Parent;
00314 CBSPNode2v **p1Parent;
00315
00316
00317 if (p0Front)
00318 {
00319 p0Parent = &Front;
00320 p1Parent = &Back;
00321 }
00322 else
00323 {
00324 p0Parent = &Back;
00325 p1Parent = &Front;
00326 }
00327
00328
00329 if (*p0Parent)
00330 {
00331 (*p0Parent)->insert (newNode);
00332 }
00333 else
00334 {
00335 *p0Parent = newNode;
00336 newNode->Parent = this;
00337 }
00338
00339
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
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
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
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
00435 if (toConvexPolygonsInCone (vertex, a, b) && toConvexPolygonsInCone (vertex, b, a))
00436 {
00437
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
00448 CMatrix invert = basis;
00449 invert.invert ();
00450
00451
00452 uint vertexCount = Vertices.size();
00453 TCConcavePolygonsVertexMap vertexMap;
00454 localVertices.resize (vertexCount);
00455 uint i, j;
00456
00457
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
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
00473 root = CBSPNode2v (clipPlane, localVertices[i], localVertices[j], i, j);
00474
00475
00476 j=i++;
00477 for (; i<Vertices.size(); i++)
00478 {
00479
00480 normal = localVertices[i] - localVertices[j];
00481 normal = normal ^ CVector::K;
00482 clipPlane.make(normal, localVertices[i]);
00483
00484
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
00496 if (Vertices.size()>2)
00497 {
00498
00499 std::vector<CVector> localVertices;
00500
00501
00502 CBSPNode2v root;
00503
00504
00505 toConvexPolygonsLocalAndBSP (localVertices, root, basis);
00506
00507
00508 std::list<uint> vertexList;
00509 uint i;
00510 for (i=0; i<Vertices.size(); i++)
00511 vertexList.push_back (i);
00512
00513
00514 std::list<uint>::iterator current=vertexList.begin();
00515 std::list<uint>::iterator begin=vertexList.begin();
00516 do
00517 {
00518 again:;
00519
00520 bool found = false;
00521
00522
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
00537 if (
00538 (toConvexPolygonsDiagonal (localVertices, root, *lastPreviousPrevious, *last)) &&
00539 (toConvexPolygonsDiagonal (localVertices, root, *currentNext, *last)) &&
00540 (toConvexPolygonsDiagonal (localVertices, root, *last, *current))
00541 )
00542 {
00543
00544 found = true;
00545 }
00546 else
00547 {
00548
00549 last = lastPrevious;
00550 lastPrevious = lastPreviousPrevious;
00551 break;
00552 }
00553
00554
00555 lastPreviousPrevious = lastPrevious;
00556 lastPrevious = last++;
00557 if (last==vertexList.end())
00558 last = vertexList.begin();
00559 }
00560
00561
00562 if (last==current)
00563 {
00564
00565 outputPolygons.push_back (CPolygon());
00566 CPolygon &back = outputPolygons.back ();
00567 back.Vertices.reserve (vertexList.size());
00568
00569
00570 current=vertexList.begin();
00571 while (current!=vertexList.end())
00572 {
00573 back.Vertices.push_back (Vertices[*current]);
00574 current++;
00575 }
00576
00577
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
00595 if (
00596 (toConvexPolygonsDiagonal (localVertices, root, *firstNextNext, *first)) &&
00597 (toConvexPolygonsDiagonal (localVertices, root, *lastPrevious, *first)) &&
00598 (toConvexPolygonsDiagonal (localVertices, root, *last, *first))
00599 )
00600 {
00601
00602 found = true;
00603 }
00604 else
00605 {
00606
00607 first = firstNext;
00608 break;
00609 }
00610
00611
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
00625 if (found)
00626 {
00627
00628 outputPolygons.push_back (CPolygon());
00629 CPolygon &back = outputPolygons.back ();
00630
00631
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
00643 back.Vertices.reserve (vertexCount);
00644
00645
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
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
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
00680 std::vector<CVector> localVertices;
00681
00682
00683 CBSPNode2v root;
00684
00685
00686 toConvexPolygonsLocalAndBSP (localVertices, root, basis);
00687
00688
00689 std::vector<std::vector<CVector> > localVerticesOther (other.size());
00690
00691
00692 std::vector<CBSPNode2v> rootOther (other.size());
00693
00694
00695 std::vector<CPolygon> copy = other;
00696
00697
00698 CPolygon mainCopy = *this;
00699
00700
00701 uint o;
00702 for (o=0; o<other.size(); o++)
00703 {
00704
00705 other[o].toConvexPolygonsLocalAndBSP (localVerticesOther[o], rootOther[o], basis);
00706 }
00707
00708
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
00716 for (i=0; i<thisCount; i++)
00717 {
00718 for (j=0; j<otherCount; j++)
00719 {
00720
00721 if (!root.intersect (localVertices[i], localVerticesOther[o][j], i, 0xffffffff))
00722 {
00723
00724 uint otherO;
00725 for (otherO=0; otherO<other.size(); otherO++)
00726 {
00727
00728 if (rootOther[otherO].intersect (localVertices[i], localVerticesOther[o][j], 0xffffffff, (otherO == o)?j:0xffffffff))
00729 break;
00730 }
00731
00732
00733 if (otherO==other.size())
00734 {
00735
00736 mainCopy.Vertices.insert (mainCopy.Vertices.begin()+i, 2+otherCount, CVector());
00737
00738
00739 mainCopy.Vertices[i] = mainCopy.Vertices[i+otherCount+2];
00740
00741
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
00752 mainCopy.Vertices[i+otherCount+1] = copy[o].Vertices[j];
00753 break;
00754 }
00755 }
00756 }
00757 if (j!=otherCount)
00758 break;
00759 }
00760
00761
00762 if (i==thisCount)
00763 {
00764
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
00774 if (!rootOther[otherToCheck].intersect (localVerticesOther[otherToCheck][i], localVerticesOther[o][j], i, 0xffffffff))
00775 {
00776
00777 uint otherO;
00778 for (otherO=0; otherO<other.size(); otherO++)
00779 {
00780
00781 if (rootOther[otherO].intersect (localVerticesOther[otherToCheck][i], localVerticesOther[o][j], (otherToCheck == otherO)?i:0xffffffff, (otherO == o)?j:0xffffffff))
00782 break;
00783 }
00784
00785
00786 if (otherO==other.size())
00787 {
00788
00789 copy[otherToCheck].Vertices.insert (copy[otherToCheck].Vertices.begin()+i, 2+otherCount, CVector());
00790
00791
00792 copy[otherToCheck].Vertices[i] = copy[otherToCheck].Vertices[i+otherCount+2];
00793
00794
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
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
00819 return false;
00820 }
00821 }
00822 }
00823
00824
00825 *this = mainCopy;
00826 return true;
00827 }
00828
00829
00830
00831
00832
00833
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 )
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
00861
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);
00869 segEnd.set((it + 1)->x, (it + 1)->y, 0);
00870 float n = (segStart - segEnd).norm();
00871 if (n != 0)
00872 {
00873 clipPlane.make(segStart, segEnd, (n > 10 ? n : 10) * CVector::K + segStart);
00874
00875 for (TVec2fVect::const_iterator it2 = Vertices.begin(); it2 != Vertices.end(); ++it2)
00876 {
00877 if (it2 != it && it2 != (it + 1))
00878 {
00879
00880 float dist = clipPlane * CVector(it2->x, it2-> y, 0);
00881 if (dist != 0)
00882 {
00883 if (dist > 0) Front = true; else Back = true;
00884 if (Front && Back) return false;
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)
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
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
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
00950
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
00969 pCurr = p2Index;
00970 pPrev = pIndex;
00971
00972 curr = Vertices[pCurr];
00973 prev = Vertices[pPrev];
00974
00975
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;
01003 }
01004 prev = curr;
01005 curr = Vertices[*bestIt];
01006 pPrev = pCurr;
01007 pCurr = *bestIt;
01008
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
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
01072 height = (sint) (ceilf(v2.y) - ceilY1);
01073 if (height <= 0) return;
01074
01075
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
01084 iInverseSlope = (sint) (rol16 * fInverseSlope);
01085
01086
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
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
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
01140 float fHighest = V[0].y;
01141 float fLowest = fHighest;
01142
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
01158 TVec2fVect::const_iterator pHighestRight = pHighest;
01159 if (fLowest == fHighest)
01160 {
01161
01162 while (pHighestRight->x == pHighest->x)
01163 {
01164 pHighestRight = Next(pHighestRight, V);
01165 if (pHighestRight == pHighest) return false;
01166 }
01167 return pHighest->x <= pHighestRight->x;
01168 }
01169
01170 while (Next(pHighestRight, V)->y == fHighest)
01171 {
01172 pHighestRight = Next(pHighestRight, V);
01173 }
01174
01175
01176 TVec2fVect::const_iterator pHighestLeft = Next(pHighestRight, V);
01177
01178 while (pHighestLeft->y != fHighest)
01179 {
01180 pHighestLeft = Next(pHighestLeft, V);
01181 }
01182 TVec2fVect::const_iterator pPrevHighestLeft = Prev(pHighestLeft, V);
01183
01184
01185
01186 if (pHighestLeft->x != pHighestRight->x)
01187 {
01188
01189 return pHighestLeft->x <= pHighestRight->x;
01190 }
01191
01192
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
01207 const TVec2fVect &V = Vertices;
01208 if (Vertices.size() < 3)
01209 {
01210 borders.clear();
01211 return;
01212 }
01213 bool ccw;
01214
01215
01216 float fHighest = V[0].y;
01217 float fLowest = fHighest;
01218
01219
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
01258 TVec2fVect::const_iterator pHighestRight = pHighest;
01259
01260 while (Next(pHighestRight, V)->y == fHighest)
01261 {
01262 pHighestRight = Next(pHighestRight, V);
01263 }
01264
01265
01266 TVec2fVect::const_iterator pHighestLeft = Next(pHighestRight, V);
01267
01268 while (pHighestLeft->y != fHighest)
01269 {
01270 pHighestLeft = Next(pHighestLeft, V);
01271 }
01272
01273 TVec2fVect::const_iterator pPrevHighestLeft = Prev(pHighestLeft, V);
01274
01275
01276
01277
01278
01279 if (pHighestLeft->x != pHighestRight->x)
01280 {
01281
01282 if (pHighestLeft->x > pHighestRight->x)
01283 {
01284 ccw = true;
01285 std::swap(pHighestLeft, pHighestRight);
01286 }
01287 else
01288 {
01289 ccw = false;
01290 }
01291 }
01292 else
01293 {
01294
01295
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;
01304 std::swap(pHighestLeft, pHighestRight);
01305 }
01306 else
01307 {
01308 ccw = false;
01309 }
01310 }
01311
01312
01313
01314 TVec2fVect::const_iterator currV, nextV;
01315 if (!ccw)
01316 {
01317 currV = pHighestRight ;
01318
01319 do
01320 {
01321 nextV = Next(currV, V);
01322 ScanEdge(borders, iHighest, *currV, *nextV, true);
01323 currV = nextV;
01324 }
01325 while (currV != pLowest);
01326
01327
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
01337 {
01338 currV = pHighestLeft;
01339
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
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
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)));
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
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)));
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
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)));
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
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)));
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
01508
01509
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;
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
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
01560 borders.resize(polyHeight);
01561
01562 sint ileft = (sint) floorf(fleft);
01563 sint iright = (sint) ceilf(fright);
01564 minimumY = highest;
01565 if (flowest == fhighest)
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
01605
01606
01607
01608 if (pHighestLeft->x != pHighestRight->x)
01609 {
01610
01611 if (pHighestLeft->x > pHighestRight->x)
01612 {
01613 ccw = true;
01614 std::swap(pHighestLeft, pHighestRight);
01615 }
01616 else
01617 {
01618 ccw = false;
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
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
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
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)));
01707 if (rightEdge)
01708 {
01709 iposx -= rol16 - 1;
01710 if (deltaX >= 0.f)
01711 {
01712
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
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
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
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
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
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;
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
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
01854 borders.resize(polyHeight);
01855
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
01886
01887
01888
01889 if (pHighestLeft->x != pHighestRight->x)
01890 {
01891
01892 if (pHighestLeft->x > pHighestRight->x)
01893 {
01894 ccw = true;
01895 std::swap(pHighestLeft, pHighestRight);
01896 }
01897 else
01898 {
01899 ccw = false;
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
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
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
01964 if (floorf(fhighest) != fhighest)
01965 {
01966 borders[0].first = 1;
01967 borders[0].second = 0;
01968 }
01969
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);
01983 nlassert(Vertices[k].x < 32000.f);
01984 nlassert(Vertices[k].y >= -32000.f);
01985 nlassert(Vertices[k].y < 32000.f);
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())
02077 {
02078 return false;
02079 }
02080 }
02081 return true;
02082 }
02083 else
02084 {
02085 return other.contains(Vertices[0]);
02086 }
02087 }
02088
02089
02090 bool CPolygon2D::contains(const CVector2f &p, bool hintIsConvex ) 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
02113 return p == Vertices[0];
02114 }
02115 else
02116 {
02117
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
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 }
02255
02256
02257
02258
02259
02260
02261
02262
02263
02264
02265
02266
02267
02268
02269
02270
02271
02272
02273
02274
02275