1 // NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>
2 // Copyright (C) 2010 Winch Gate Property Limited
4 // This program is free software: you can redistribute it and/or modify
5 // it under the terms of the GNU Affero General Public License as
6 // published by the Free Software Foundation, either version 3 of the
7 // License, or (at your option) any later version.
9 // This program is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 // GNU Affero General Public License for more details.
14 // You should have received a copy of the GNU Affero General Public License
15 // along with this program. If not, see <http://www.gnu.org/licenses/>.
19 #include "nel/misc/polygon.h"
20 #include "nel/misc/plane.h"
21 #include "nel/misc/triangle.h"
25 using namespace NLMISC
;
35 //==================================//
36 // CPolygon implementation //
37 //==================================//
39 // ***************************************************************************
40 CPolygon::CPolygon(const CVector
&a
, const CVector
&b
, const CVector
&c
)
43 Vertices
.push_back(a
);
44 Vertices
.push_back(b
);
45 Vertices
.push_back(c
);
48 // ***************************************************************************
49 void CPolygon::toTriFan(std::vector
<NLMISC::CTriangle
> &dest
) const
51 sint count
= (sint
) Vertices
.size() - 2;
52 for(sint k
= 0; k
< count
; ++k
)
54 dest
.push_back(CTriangle(Vertices
[0], Vertices
[k
+ 1], Vertices
[k
+ 2]));
58 // ***************************************************************************
59 float CPolygon::computeArea() const
62 sint numVerts
= (sint
) Vertices
.size();
63 for(sint k
= 0; k
< numVerts
- 2; ++k
)
65 CVector v0
= Vertices
[k
+ 1] - Vertices
[0];
66 CVector v1
= Vertices
[k
+ 2] - Vertices
[0];
67 area
+= (v0
^ v1
).norm();
69 return 0.5f
* fabsf(area
);
72 // ***************************************************************************
73 void CPolygon::clip(const CPlane
*planes
, uint nPlanes
)
75 if(nPlanes
==0 || getNumVertices()==0)
78 // The final polygon has at maximum currentVertices+number of clipping planes.
79 // For performance, the vectors are static, so reallocation rarely occurs.
80 static vector
<CVector
> tab0
, tab1
;
81 tab0
.resize(getNumVertices()+nPlanes
);
82 tab1
.resize(getNumVertices()+nPlanes
);
83 // Init tab0 with Vertices.
84 copy(Vertices
.begin(), Vertices
.end(), tab0
.begin());
85 CVector
*in
=&(*tab0
.begin()), *out
= &(*tab1
.begin());
86 sint nin
= getNumVertices(), nout
;
87 for(sint i
=0;i
<(sint
)nPlanes
;i
++)
89 nout
= planes
[i
].clipPolygonBack(in
, out
, nin
);
96 // Final result in "in".
100 memcpy(&(*Vertices
.begin()), in
, nin
*sizeof(CVector
));
105 // ***************************************************************************
106 void CPolygon::clip(const std::vector
<CPlane
> &planes
)
110 clip(&(*planes
.begin()), (uint
)planes
.size());
115 // ***************************************************************************
116 void CPolygon::serial(NLMISC::IStream
&f
)
119 f
.serialCont(Vertices
);
122 // ***************************************************************************
123 void CPolygon::getBestTriplet(uint
&index0
,uint
&index1
,uint
&index2
)
125 nlassert(Vertices
.size() >= 3);
127 float bestArea
= 0.f
;
128 const uint numVerts
= (uint
)Vertices
.size();
129 for (i
= 0; i
< numVerts
; ++i
)
131 for (j
= 0; j
< numVerts
; ++j
)
135 for (k
= 0; k
< numVerts
; ++k
)
137 if (k
!= i
&& k
!= j
)
139 CVector v0
= Vertices
[j
] - Vertices
[i
];
140 CVector v1
= Vertices
[k
] - Vertices
[i
];
141 float area
= (v0
^ v1
).norm();
157 // ***************************************************************************
158 void CPolygon::buildBasis(CMatrix
&dest
)
160 nlassert(Vertices
.size() > 3);
162 getBestTriplet(i1
, i2
, i3
);
163 CVector v1
= (Vertices
[i2
] - Vertices
[i1
]).normed();
164 CVector v2
= (Vertices
[i3
] - Vertices
[i1
]).normed();
166 CVector I
= v1
- (v1
* K
) * v1
;
168 dest
.setRot(I
, J
, K
);
169 dest
.setPos(Vertices
[i1
]);
172 // ***************************************************************************
174 class CConcavePolygonsVertexDesc
178 CConcavePolygonsVertexDesc (float length
, uint index
)
187 // First vertex index
190 typedef std::map
<float, CConcavePolygonsVertexDesc
> TCConcavePolygonsVertexMap
;
193 // ***************************************************************************
194 bool CPolygon::toConvexPolygonsEdgeIntersect (const CVector2f
& a0
, const CVector2f
& a1
, const CVector2f
& b0
, const CVector2f
& b1
)
197 if( a0
.x
-a1
.x
==0 && b0
.x
-b1
.x
==0 )
200 // compute intersection of both lines
201 CVector2f intersection
;
203 // first edge vertical?
206 float Ab
= (b0
.y
- b1
.y
) / (b0
.x
- b1
.x
);
209 intersection
.x
= a0
.x
;
210 intersection
.y
= b0
.y
+ (a0
.x
-b0
.x
) * Ab
;
212 // second edge vertical?
213 else if(b0
.x
- b1
.x
==0)
215 float Aa
= (a0
.y
- a1
.y
) / (a0
.x
- a1
.x
);
218 intersection
.x
= b0
.x
;
219 intersection
.y
= a0
.y
+ (b0
.x
-a0
.x
) * Aa
;
224 float Aa
= (a0
.y
- a1
.y
) / (a0
.x
- a1
.x
);
225 float Ba
= a0
.y
- a0
.x
* Aa
;
226 float Ab
= (b0
.y
- b1
.y
) / (b0
.x
- b1
.x
);
227 float Bb
= b0
.y
- b0
.x
* Ab
;
234 intersection
.x
= (Bb
- Ba
) / (Aa
- Ab
);
235 intersection
.y
= Aa
* intersection
.x
+ Ba
;
239 return ( ( (a0
-intersection
)*(a1
-intersection
) < 0 ) && ( (b0
-intersection
)*(b1
-intersection
) < 0 ) );
242 // ***************************************************************************
252 CBSPNode2v ( const CPlane
&plane
, CVector p0
, CVector p1
, uint v0
, uint v1
) : Plane (plane
), P0 (p0
), P1 (p1
)
268 void insert (CBSPNode2v
*node
)
271 bool p0Front
= (Plane
* node
->P0
) > 0;
272 bool p1Front
= (Plane
* node
->P1
) > 0;
273 if (p0Front
&& p1Front
)
277 Front
->insert (node
);
285 else if ((!p0Front
) && (!p1Front
))
300 CVector newVertex
= Plane
.intersect (node
->P0
, node
->P1
);
303 CBSPNode2v
*newNode
= new CBSPNode2v (node
->Plane
, node
->P0
, newVertex
, node
->V0
, node
->V1
);
306 node
->P0
= newVertex
;
309 CBSPNode2v
**p0Parent
;
310 CBSPNode2v
**p1Parent
;
312 // Get insertion pointer
327 (*p0Parent
)->insert (newNode
);
332 newNode
->Parent
= this;
338 (*p1Parent
)->insert (node
);
348 bool intersect (const CVector
&p0
, const CVector
&p1
, uint v0
, uint v1
) const
351 bool p0Front
= (Plane
* p0
) > 0;
352 bool p1Front
= (Plane
* p1
) > 0;
354 if (p0Front
!= p1Front
)
355 if ( (v0
!= V0
) && (v0
!= V1
) && (v1
!= V0
) && (v1
!= V1
) )
356 if (CPolygon::toConvexPolygonsEdgeIntersect ((CVector2f
) P0
, (CVector2f
) P1
, (CVector2f
) p0
, (CVector2f
) p1
))
359 if (p0Front
|| p1Front
)
362 if (Front
->intersect (p0
, p1
, v0
, v1
))
366 if ((!p0Front
) || (!p1Front
))
369 if (Back
->intersect (p0
, p1
, v0
, v1
))
376 CBSPNode2v
*Back
, *Front
, *Parent
;
384 // ***************************************************************************
386 bool CPolygon::toConvexPolygonsLeft (const std::vector
<CVector
> &vertex
, uint a
, uint b
, uint c
)
388 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;
391 // ***************************************************************************
393 bool CPolygon::toConvexPolygonsLeftOn (const std::vector
<CVector
> &vertex
, uint a
, uint b
, uint c
)
395 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;
398 // ***************************************************************************
400 bool CPolygon::toConvexPolygonsInCone (const std::vector
<CVector
> &vertex
, uint a
, uint b
)
404 if (a0
==vertex
.size())
408 a1
= (uint
)vertex
.size()-1;
412 if (toConvexPolygonsLeftOn (vertex
, a
, a1
, a0
) )
414 return toConvexPolygonsLeft ( vertex
, a
, b
, a0
) && toConvexPolygonsLeft ( vertex
, b
, a
, a1
);
418 return !( toConvexPolygonsLeft ( vertex
, a
, b
, a1
) && toConvexPolygonsLeft ( vertex
, b
, a
, a0
) );
422 // ***************************************************************************
424 bool CPolygon::toConvexPolygonsDiagonal (const std::vector
<CVector
> &vertex
, const CBSPNode2v
&bsp
, uint a
, uint b
)
426 // Check it is a border
427 if ( ( (b
- a
) == 1) || ( (a
- b
) == 1) || ( (a
==0) && (b
==(vertex
.size()-1))) || ( (b
==0) && (a
==(vertex
.size()-1))) )
431 if (toConvexPolygonsInCone (vertex
, a
, b
) && toConvexPolygonsInCone (vertex
, b
, a
))
434 return !bsp
.intersect (vertex
[a
], vertex
[b
], a
, b
);
439 // ***************************************************************************
441 void CPolygon::toConvexPolygonsLocalAndBSP (std::vector
<CVector
> &localVertices
, CBSPNode2v
&root
, const CMatrix
&basis
) const
444 CMatrix invert
= basis
;
447 // Insert vertices in an ordered table
448 uint vertexCount
= (uint
)Vertices
.size();
449 TCConcavePolygonsVertexMap vertexMap
;
450 localVertices
.resize (vertexCount
);
453 // Transform the vertex
454 for (i
=0; i
<vertexCount
; i
++)
456 CVector local
= invert
*Vertices
[i
];
457 localVertices
[i
] = CVector (local
.x
, local
.y
, 0);
462 j
=(uint
)Vertices
.size()-1;
463 CVector normal
= localVertices
[i
] - localVertices
[j
];
464 normal
= normal
^ CVector::K
;
466 clipPlane
.make(normal
, localVertices
[i
]);
468 // Build the BSP root
469 root
= CBSPNode2v (clipPlane
, localVertices
[i
], localVertices
[j
], i
, j
);
471 // Insert all others edges
473 for (; i
<Vertices
.size(); i
++)
476 normal
= localVertices
[i
] - localVertices
[j
];
477 normal
= normal
^ CVector::K
;
478 clipPlane
.make(normal
, localVertices
[i
]);
480 // Build the BSP root
481 root
.insert ( new CBSPNode2v (clipPlane
, localVertices
[i
], localVertices
[j
], i
, j
) );
488 // ***************************************************************************
489 bool CPolygon::toConvexPolygons (std::list
<CPolygon
>& outputPolygons
, const CMatrix
& basis
) const
492 if (Vertices
.size()>2)
495 std::vector
<CVector
> localVertices
;
497 // Build the BSP root
500 // Build the local array and the BSP
501 toConvexPolygonsLocalAndBSP (localVertices
, root
, basis
);
503 // Build a vertex list
504 std::list
<uint
> vertexList
;
506 for (i
=0; i
<Vertices
.size(); i
++)
507 vertexList
.push_back (i
);
509 // Clip ears while there is some polygons
510 std::list
<uint
>::iterator current
=vertexList
.begin();
511 std::list
<uint
>::iterator begin
=vertexList
.begin();
515 // Search for a diagonal
519 std::list
<uint
>::iterator first
= current
;
520 std::list
<uint
>::iterator lastPreviousPrevious
=current
;
521 std::list
<uint
>::iterator lastPrevious
=current
;
523 if (lastPrevious
==vertexList
.end())
524 lastPrevious
= vertexList
.begin();
525 std::list
<uint
>::iterator currentNext
= lastPrevious
;
526 std::list
<uint
>::iterator last
= lastPrevious
;
528 if (last
==vertexList
.end())
529 last
= vertexList
.begin();
530 while (last
!= current
)
534 (toConvexPolygonsDiagonal (localVertices
, root
, *lastPreviousPrevious
, *last
)) &&
535 (toConvexPolygonsDiagonal (localVertices
, root
, *currentNext
, *last
)) &&
536 (toConvexPolygonsDiagonal (localVertices
, root
, *last
, *current
))
546 lastPrevious
= lastPreviousPrevious
;
551 lastPreviousPrevious
= lastPrevious
;
552 lastPrevious
= last
++;
553 if (last
==vertexList
.end())
554 last
= vertexList
.begin();
561 outputPolygons
.push_back (CPolygon());
562 CPolygon
&back
= outputPolygons
.back ();
563 back
.Vertices
.reserve (vertexList
.size());
565 // Add each vertex in the new polygon
566 current
=vertexList
.begin();
567 while (current
!=vertexList
.end())
569 back
.Vertices
.push_back (Vertices
[*current
]);
578 std::list
<uint
>::iterator firstNext
= current
;
579 std::list
<uint
>::iterator firstNextNext
= currentNext
;
580 if (first
!= vertexList
.begin())
584 first
= vertexList
.end();
588 while (current
!= first
)
592 (toConvexPolygonsDiagonal (localVertices
, root
, *firstNextNext
, *first
)) &&
593 (toConvexPolygonsDiagonal (localVertices
, root
, *lastPrevious
, *first
)) &&
594 (toConvexPolygonsDiagonal (localVertices
, root
, *last
, *first
))
608 firstNextNext
= firstNext
;
610 if (first
==vertexList
.begin())
612 first
= vertexList
.end();
624 outputPolygons
.push_back (CPolygon());
625 CPolygon
&back
= outputPolygons
.back ();
628 uint vertexCount
= 1;
630 while (current
!= last
)
634 if (current
== vertexList
.end())
635 current
= vertexList
.begin();
639 back
.Vertices
.reserve (vertexCount
);
641 // Copy and remove vertices
642 back
.Vertices
.push_back (Vertices
[*first
]);
644 if (first
== vertexList
.end())
645 first
= vertexList
.begin();
646 while (first
!= last
)
648 back
.Vertices
.push_back (Vertices
[*first
]);
651 first
= vertexList
.erase (first
);
652 if (first
== vertexList
.end())
653 first
= vertexList
.begin();
654 nlassert (first
!= vertexList
.end());
656 back
.Vertices
.push_back (Vertices
[*first
]);
657 current
= begin
= last
;
663 if (current
== vertexList
.end())
664 current
= vertexList
.begin ();
666 while (current
!= begin
);
671 // ***************************************************************************
673 bool CPolygon::chain (const std::vector
<CPolygon
> &other
, const CMatrix
& basis
)
676 std::vector
<CVector
> localVertices
;
678 // Build the BSP root
681 // Build the local array and the BSP
682 toConvexPolygonsLocalAndBSP (localVertices
, root
, basis
);
685 std::vector
<std::vector
<CVector
> > localVerticesOther (other
.size());
687 // Build the BSP root
688 std::vector
<CBSPNode2v
> rootOther (other
.size());
690 // Build a copy of the polygons
691 std::vector
<CPolygon
> copy
= other
;
694 CPolygon mainCopy
= *this;
696 // For each other polygons
698 for (o
=0; o
<other
.size(); o
++)
700 // Build the local array and the BSP
701 other
[o
].toConvexPolygonsLocalAndBSP (localVerticesOther
[o
], rootOther
[o
], basis
);
704 // Look for a couple..
705 uint thisCount
= (uint
)Vertices
.size();
707 for (o
=0; o
<other
.size(); o
++)
709 uint otherCount
= (uint
)other
[o
].Vertices
.size();
711 // Try to link in the main polygon
712 for (i
=0; i
<thisCount
; i
++)
714 for (j
=0; j
<otherCount
; j
++)
716 // Test this segement
717 if (!root
.intersect (localVertices
[i
], localVerticesOther
[o
][j
], i
, 0xffffffff))
719 // Test each other polygons
721 for (otherO
=0; otherO
<other
.size(); otherO
++)
724 if (rootOther
[otherO
].intersect (localVertices
[i
], localVerticesOther
[o
][j
], 0xffffffff, (otherO
== o
)?j
:0xffffffff))
729 if (otherO
==other
.size())
731 // Insert new vertices
732 mainCopy
.Vertices
.insert (mainCopy
.Vertices
.begin()+i
, 2+otherCount
, CVector());
734 // Copy the first vertex
735 mainCopy
.Vertices
[i
] = mainCopy
.Vertices
[i
+otherCount
+2];
737 // Copy the new vertices
739 for (k
=0; k
<otherCount
; k
++)
742 if (index
>=otherCount
)
744 mainCopy
.Vertices
[i
+k
+1] = copy
[o
].Vertices
[index
];
748 mainCopy
.Vertices
[i
+otherCount
+1] = copy
[o
].Vertices
[j
];
760 // Try to link in the sub polygons
762 for (otherToCheck
=o
+1; otherToCheck
<other
.size(); otherToCheck
++)
764 uint otherToCheckCount
= (uint
)other
[otherToCheck
].Vertices
.size();
765 for (i
=0; i
<otherToCheckCount
; i
++)
767 for (j
=0; j
<otherCount
; j
++)
769 // Test this segement
770 if (!rootOther
[otherToCheck
].intersect (localVerticesOther
[otherToCheck
][i
], localVerticesOther
[o
][j
], i
, 0xffffffff))
772 // Test each other polygons
774 for (otherO
=0; otherO
<other
.size(); otherO
++)
777 if (rootOther
[otherO
].intersect (localVerticesOther
[otherToCheck
][i
], localVerticesOther
[o
][j
], (otherToCheck
== otherO
)?i
:0xffffffff, (otherO
== o
)?j
:0xffffffff))
782 if (otherO
==other
.size())
784 // Insert new vertices
785 copy
[otherToCheck
].Vertices
.insert (copy
[otherToCheck
].Vertices
.begin()+i
, 2+otherCount
, CVector());
787 // Copy the first vertex
788 copy
[otherToCheck
].Vertices
[i
] = copy
[otherToCheck
].Vertices
[i
+otherCount
+2];
790 // Copy the new vertices
792 for (k
=0; k
<otherCount
; k
++)
795 if (index
>=otherCount
)
797 copy
[otherToCheck
].Vertices
[i
+k
+1] = copy
[otherO
].Vertices
[index
];
801 copy
[otherToCheck
].Vertices
[i
+otherCount
+1] = copy
[otherO
].Vertices
[j
];
809 if (i
!=otherToCheckCount
)
812 if (otherToCheck
==other
.size())
825 // ***************************************************************************
828 //====================================//
829 // CPolygon2d implementation //
830 //====================================//
834 // ***************************************************************************
835 CPolygon2D::CPolygon2D(const CPolygon
&src
, const CMatrix
&projMat
)
837 fromPolygon(src
, projMat
);
840 // ***************************************************************************
841 void CPolygon2D::fromPolygon(const CPolygon
&src
, const CMatrix
&projMat
/*=CMatrix::Identity*/)
843 uint size
= (uint
)src
.Vertices
.size();
844 Vertices
.resize(size
);
845 for (uint k
= 0; k
< size
; ++k
)
847 CVector proj
= projMat
* src
.Vertices
[k
];
848 Vertices
[k
].set(proj
.x
, proj
.y
);
852 // ***************************************************************************
853 bool CPolygon2D::isConvex()
855 bool Front
= true, Back
= false;
856 // we apply a dummy algo for now : check whether every vertex is in the same side
857 // of every plane defined by a segment of this poly
858 uint numVerts
= (uint
)Vertices
.size();
859 if (numVerts
< 3) return true;
860 CVector segStart
, segEnd
;
862 for (TVec2fVect::const_iterator it
= Vertices
.begin(); it
!= Vertices
.end(); ++it
)
864 segStart
.set(it
->x
, it
->y
, 0); // segment start
865 segEnd
.set((it
+ 1)->x
, (it
+ 1)->y
, 0); // segment end
866 float n
= (segStart
- segEnd
).norm(); // segment norm
869 clipPlane
.make(segStart
, segEnd
, (n
> 10 ? n
: 10) * CVector::K
+ segStart
); // make a plane, with this segment and the poly normal
870 // check each other vertices against this plane
871 for (TVec2fVect::const_iterator it2
= Vertices
.begin(); it2
!= Vertices
.end(); ++it2
)
873 if (it2
!= it
&& it2
!= (it
+ 1)) // the vertices must not be part of the test plane (because of imprecision)
876 float dist
= clipPlane
* CVector(it2
->x
, it2
-> y
, 0);
877 if (dist
!= 0) // midlle pos
879 if (dist
> 0) Front
= true; else Back
= true;
880 if (Front
&& Back
) return false; // there are both front end back vertices -> failure
889 // ***************************************************************************
891 void CPolygon2D::buildConvexHull(CPolygon2D
&dest
) const
893 nlassert(&dest
!= this);
895 if (this->Vertices
.size() == 3) // with 3 points it is always convex
901 uint numVerts
= (uint
)Vertices
.size();
902 CVector2f p
, curr
, prev
;
903 uint pIndex
, p1Index
, p2Index
, pCurr
, pPrev
;
904 // this is not optimized, but not used in realtime.. =)
905 nlassert(numVerts
>= 3);
906 dest
.Vertices
.clear();
908 typedef std::set
<uint
> TIndexSet
;
910 for (k
= 0; k
< Vertices
.size(); ++k
)
916 // 1) find the highest point p of the set. We are sure it belongs to the hull
919 for (k
= 1; k
< numVerts
; ++k
)
921 if (Vertices
[k
].y
< p
.y
)
928 leftIndex
.erase(pIndex
);
932 p1Index
= p2Index
= pIndex
;
934 for (k
= 0; k
< numVerts
; ++k
)
938 for (l
= 0; l
< numVerts
; ++l
)
940 if (l
!= pIndex
&& l
!= k
)
942 CVector2f seg1
= (Vertices
[l
] - p
).normed();
943 CVector2f seg2
= (Vertices
[k
] - p
).normed();
945 //CVector cp = CVector(seg1.x, seg1.y, 0) ^ CVector(seg2.x, seg2.y, 0);
946 //float n = fabsf(cp.z);
947 float n
= seg1
* seg2
;
960 leftIndex
.erase(p2Index
);
964 // start from the given triplet, and complete the poly until we reach the first point
968 curr
= Vertices
[pCurr
];
969 prev
= Vertices
[pPrev
];
971 // create the first triplet vertices
972 dest
.Vertices
.push_back(Vertices
[p1Index
]);
973 dest
.Vertices
.push_back(prev
);
974 dest
.Vertices
.push_back(curr
);
981 CVector2f seg2
= (prev
- curr
).normed();
982 TIndexSet::iterator bestIt
= leftIndex
.end();
983 for (TIndexSet::iterator it
= leftIndex
.begin(); it
!= leftIndex
.end(); ++it
)
985 if (step
== 0 && *it
== p1Index
) continue;
986 CVector2f seg1
= (Vertices
[*it
] - curr
).normed();
987 float n
= seg1
* seg2
;
995 nlassert(bestIt
!= leftIndex
.end());
996 if (*bestIt
== p1Index
)
998 return; // if we reach the start point we have finished
1001 curr
= Vertices
[*bestIt
];
1004 // add new point to the destination
1005 dest
.Vertices
.push_back(curr
);
1007 leftIndex
.erase(bestIt
);
1011 // ***************************************************************************
1014 void CPolygon2D::serial(NLMISC::IStream
&f
)
1016 (void)f
.serialVersion(0);
1017 f
.serialCont(Vertices
);
1020 // ***************************************************************************
1021 /// get the best triplet of vector. e.g the triplet that has the best surface
1022 void CPolygon2D::getBestTriplet(uint
&index0
, uint
&index1
, uint
&index2
)
1024 nlassert(Vertices
.size() >= 3);
1026 float bestArea
= 0.f
;
1027 const uint numVerts
= (uint
)Vertices
.size();
1028 for (i
= 0; i
< numVerts
; ++i
)
1030 for (j
= 0; j
< numVerts
; ++j
)
1034 for (k
= 0; k
< numVerts
; ++k
)
1036 if (k
!= i
&& k
!= j
)
1038 CVector2f v0
= Vertices
[j
] - Vertices
[i
];
1039 CVector2f v1
= Vertices
[k
] - Vertices
[i
];
1040 float area
= fabsf((CVector(v0
.x
, v0
.y
, 0) ^ CVector(v1
.x
, v1
.y
, 0)).norm());
1041 if (area
> bestArea
)
1056 /// ***************************************************************************************
1057 // scan a an edge of a poly and write it into a table
1058 static void ScanEdge(CPolygon2D::TRasterVect
&outputVect
, sint topY
, const CVector2f
&v1
, const CVector2f
&v2
, bool rightEdge
= true)
1060 const uint rol16
= 65536;
1061 sint ceilY1
= (sint
) ceilf(v1
.y
);
1063 float deltaX
, deltaY
;
1064 float fInverseSlope
;
1065 sint iInverseSlope
, iPosX
;
1067 // check whether this segment gives a contribution to the final poly
1068 height
= (sint
) (ceilf(v2
.y
) - ceilY1
);
1069 if (height
<= 0) return;
1072 deltaY
= v2
.y
- v1
.y
;
1073 deltaX
= v2
.x
- v1
.x
;
1074 fInverseSlope
= deltaX
/ deltaY
;
1077 CPolygon2D::TRasterVect::iterator outputIt
= outputVect
.begin() + (ceilY1
- topY
);
1080 iInverseSlope
= (sint
) (rol16
* fInverseSlope
);
1082 // sub-pixel accuracy
1083 iPosX
= (int) (rol16
* (v1
.x
+ fInverseSlope
* (ceilY1
- v1
.y
)));
1085 const CPolygon2D::TRasterVect::iterator endIt
= outputIt
+ height
;
1090 outputIt
->second
= iPosX
>> 16;
1091 iPosX
+= iInverseSlope
;
1094 while (outputIt
!= endIt
);
1098 iPosX
+= (rol16
- 1);
1101 outputIt
->first
= iPosX
>> 16;
1102 iPosX
+= iInverseSlope
;
1105 while (outputIt
!= endIt
);
1110 // *******************************************************************************
1111 // This function alow to cycle forward through a vertex vector like if it was a circular list
1112 static inline CPolygon2D::TVec2fVect::const_iterator
Next(const CPolygon2D::TVec2fVect::const_iterator
&it
, const CPolygon2D::TVec2fVect
&cont
)
1114 nlassert(cont
.size() != 0);
1115 if ((it
+ 1) == cont
.end()) return cont
.begin();
1120 // *******************************************************************************
1121 // This function alow to cycle backward through a (non null) vertex vector like if it was a circular list
1122 static inline CPolygon2D::TVec2fVect::const_iterator
Prev(const CPolygon2D::TVec2fVect::const_iterator
&it
, const CPolygon2D::TVec2fVect
&cont
)
1124 nlassert(cont
.size() != 0);
1125 if (it
== cont
.begin()) return cont
.end() - 1;
1130 // *******************************************************************************
1131 bool CPolygon2D::isCCWOriented() const
1133 const TVec2fVect
&V
= Vertices
;
1134 nlassert(Vertices
.size() >= 3);
1135 // compute highest and lowest pos of the poly
1136 float fHighest
= V
[0].y
;
1137 float fLowest
= fHighest
;
1138 // iterators to the highest and lowest vertex
1139 TVec2fVect::const_iterator it
= V
.begin() ;
1140 const TVec2fVect::const_iterator endIt
= V
.end();
1141 TVec2fVect::const_iterator pHighest
= V
.begin();
1144 if (it
->y
< fHighest
)
1149 fLowest
= std::max(fLowest
, it
->y
);
1152 while (it
!= endIt
);
1153 // we seek this vertex
1154 TVec2fVect::const_iterator pHighestRight
= pHighest
;
1155 if (fLowest
== fHighest
)
1157 // special case : degenerate poly
1158 while (pHighestRight
->x
== pHighest
->x
)
1160 pHighestRight
= Next(pHighestRight
, V
);
1161 if (pHighestRight
== pHighest
) return false; // the poly is reduced to a point, returns an abritrary value
1163 return pHighest
->x
<= pHighestRight
->x
;
1165 // iterator to the first vertex that has an y different from the top vertex
1166 while (Next(pHighestRight
, V
)->y
== fHighest
)
1168 pHighestRight
= Next(pHighestRight
, V
);
1171 // iterator to the first vertex after pHighestRight, that has the same y than the highest vertex
1172 TVec2fVect::const_iterator pHighestLeft
= Next(pHighestRight
, V
);
1174 while (pHighestLeft
->y
!= fHighest
)
1176 pHighestLeft
= Next(pHighestLeft
, V
);
1178 TVec2fVect::const_iterator pPrevHighestLeft
= Prev(pHighestLeft
, V
);
1179 // we need to get the orientation of the polygon
1180 // There are 2 case : flat, and non-flat top
1181 // check for flat top
1182 if (pHighestLeft
->x
!= pHighestRight
->x
)
1184 // compare right and left side
1185 return pHighestLeft
->x
<= pHighestRight
->x
;
1187 // The top of the poly is sharp
1188 // We perform a cross product of the 2 highest vect to get its orientation
1189 float deltaXN
= Next(pHighestRight
, V
)->x
- pHighestRight
->x
;
1190 float deltaYN
= Next(pHighestRight
, V
)->y
- pHighestRight
->y
;
1191 float deltaXP
= pPrevHighestLeft
->x
- pHighestLeft
->x
;
1192 float deltaYP
= pPrevHighestLeft
->y
- pHighestLeft
->y
;
1193 return (deltaXN
* deltaYP
- deltaYN
* deltaXP
) >= 0;
1196 // *******************************************************************************
1197 void CPolygon2D::computeBorders(TRasterVect
&borders
, sint
&highestY
) const
1200 checkValidBorders();
1202 // an 'alias' to the vertices
1203 const TVec2fVect
&V
= Vertices
;
1204 if (Vertices
.size() < 3)
1209 bool ccw
; // set to true when it has a counter clock wise orientation
1211 // compute highest and lowest pos of the poly
1212 float fHighest
= V
[0].y
;
1213 float fLowest
= fHighest
;
1215 // iterators to the thighest and lowest vertex
1216 TVec2fVect::const_iterator pLowest
= V
.begin(), pHighest
= V
.begin();
1217 TVec2fVect::const_iterator it
= V
.begin() ;
1218 const TVec2fVect::const_iterator endIt
= V
.end();
1221 if (it
->y
> fLowest
)
1227 if (it
->y
< fHighest
)
1234 while (it
!= endIt
);
1237 sint iHighest
= (sint
) ceilf(fHighest
) ;
1238 sint iLowest
= (sint
) ceilf(fLowest
) ;
1240 highestY
= iHighest
;
1243 /// check poly height, and discard null height
1244 uint polyHeight
= iLowest
- iHighest
;
1245 if (polyHeight
<= 0)
1251 borders
.resize(polyHeight
);
1253 // iterator to the first vertex that has an y different from the top vertex
1254 TVec2fVect::const_iterator pHighestRight
= pHighest
;
1255 // we seek this vertex
1256 while (Next(pHighestRight
, V
)->y
== fHighest
)
1258 pHighestRight
= Next(pHighestRight
, V
);
1261 // iterator to the first vertex after pHighestRight, that has the same y than the highest vertex
1262 TVec2fVect::const_iterator pHighestLeft
= Next(pHighestRight
, V
);
1264 while (pHighestLeft
->y
!= fHighest
)
1266 pHighestLeft
= Next(pHighestLeft
, V
);
1269 TVec2fVect::const_iterator pPrevHighestLeft
= Prev(pHighestLeft
, V
);
1271 // we need to get the orientation of the polygon
1272 // There are 2 case : flat, and non-flat top
1274 // check for flat top
1275 if (pHighestLeft
->x
!= pHighestRight
->x
)
1277 // compare right and left side
1278 if (pHighestLeft
->x
> pHighestRight
->x
)
1280 ccw
= true; // the list is CCW oriented
1281 std::swap(pHighestLeft
, pHighestRight
);
1285 ccw
= false; // the list is CW oriented
1290 // The top of the poly is sharp
1291 // We perform a cross product of the 2 highest vect to get its orientation
1293 const float deltaXN
= Next(pHighestRight
, V
)->x
- pHighestRight
->x
;
1294 const float deltaYN
= Next(pHighestRight
, V
)->y
- pHighestRight
->y
;
1295 const float deltaXP
= pPrevHighestLeft
->x
- pHighestLeft
->x
;
1296 const float deltaYP
= pPrevHighestLeft
->y
- pHighestLeft
->y
;
1297 if ((deltaXN
* deltaYP
- deltaYN
* deltaXP
) < 0)
1299 ccw
= true; // the list is CCW oriented
1300 std::swap(pHighestLeft
, pHighestRight
);
1304 ccw
= false; // the list is CW oriented
1310 TVec2fVect::const_iterator currV
, nextV
; // current and next vertex
1311 if (!ccw
) // clock wise order ?
1313 currV
= pHighestRight
;
1314 // compute right edge from top to bottom
1317 nextV
= Next(currV
, V
);
1318 ScanEdge(borders
, iHighest
, *currV
, *nextV
, true);
1321 while (currV
!= pLowest
); // repeat until we reach the bottom vertex
1323 // compute left edge from bottom to top
1326 nextV
= Next(currV
, V
);
1327 ScanEdge(borders
, iHighest
, *nextV
, *currV
, false);
1330 while (currV
!= pHighestLeft
);
1334 currV
= pHighestLeft
;
1335 // compute left edge from top to bottom
1338 nextV
= Next(currV
, V
);
1339 ScanEdge(borders
, iHighest
, *currV
, *nextV
, false) ;
1342 while (currV
!= pLowest
) ;
1344 // compute right edge from bottom to top
1347 nextV
= Next(currV
, V
);
1348 ScanEdge(borders
, iHighest
, *nextV
, *currV
, true);
1351 while (currV
!= pHighestRight
) ;
1355 //=========================================================================
1356 // scan outer right edge of a poly
1357 static void ScanOuterEdgeRight(CPolygon2D::TRaster
*r
, float x1
, float y1
, float x2
, float y2
, sint minY
)
1359 CPolygon2D::TRaster
*currRaster
;
1360 float deltaX
, deltaY
;
1362 sint32 iInverseSlope
, iposx
;
1365 height
= (sint
) (ceilf(y2
) - floorf(y1
)) ;
1366 if (height
<= 0) return;
1371 currRaster
= r
+ ((sint
) floorf(y1
) - minY
);
1372 currRaster
->second
= std::max((sint
) floorf(x2
), currRaster
->second
);
1378 inverseSlope
= deltaX
/ deltaY
;
1381 iInverseSlope
= (sint32
) (65536.0 * inverseSlope
);
1382 currRaster
= r
+ ((sint
) floorf(y1
) - minY
);
1383 iposx
= (sint32
) (65536.0 * (x1
+ inverseSlope
* (ceilf(y1
) - y1
))); // sub-pixel accuracy
1384 if (ceilf(y1
) == y1
)
1386 iposx
+= iInverseSlope
;
1390 currRaster
->second
= std::max((sint
) (iposx
>> 16), currRaster
->second
);
1391 iposx
+= iInverseSlope
;
1395 while (height
!= 1);
1396 // correction for last line
1397 currRaster
->second
= std::max((sint
) floorf(x2
), currRaster
->second
);
1404 inverseSlope
= deltaX
/ deltaY
;
1407 iInverseSlope
= (sint32
) (65536.0 * inverseSlope
);
1408 currRaster
= r
+ ((sint
) floorf(y1
) - minY
);
1409 currRaster
->second
= std::max((sint
) floorf(x1
), currRaster
->second
);
1411 iposx
= (sint32
) (65536.0 * (x1
+ inverseSlope
* (ceilf(y1
) - y1
))); // sub-pixel accuracy
1412 if (ceilf(y1
) == y1
)
1414 iposx
+= iInverseSlope
;
1418 currRaster
->second
= std::max((sint
) (iposx
>> 16), currRaster
->second
);
1419 iposx
+= iInverseSlope
;
1425 //=========================================================================
1426 // scan outer left edge of a poly
1427 static void ScanOuterEdgeLeft(CPolygon2D::TRaster
*r
, float x1
, float y1
, float x2
, float y2
, sint minY
)
1429 CPolygon2D::TRaster
*currRaster
;
1430 float deltaX
, deltaY
;
1432 sint32 iInverseSlope
, iposx
;
1435 height
= (sint
) (ceilf(y2
) - floorf(y1
)) ;
1436 if (height
<= 0) return;
1441 currRaster
= r
+ ((sint
) floorf(y1
) - minY
);
1442 currRaster
->first
= std::min((sint
) floorf(x2
), currRaster
->first
);
1448 inverseSlope
= deltaX
/ deltaY
;
1451 iInverseSlope
= (sint32
) (65536.0 * inverseSlope
);
1452 currRaster
= r
+ ((sint
) floorf(y1
) - minY
);
1453 iposx
= (sint32
) (65536.0 * (x1
+ inverseSlope
* (ceilf(y1
) - y1
))); // sub-pixel accuracy
1454 if (ceilf(y1
) == y1
)
1456 iposx
+= iInverseSlope
;
1460 currRaster
->first
= std::min((sint
) (iposx
>> 16), currRaster
->first
);
1461 iposx
+= iInverseSlope
;
1465 while (height
!= 1);
1466 // correction for last line
1467 currRaster
->first
= std::min((sint
) floorf(x2
), currRaster
->first
);
1474 inverseSlope
= deltaX
/ deltaY
;
1477 iInverseSlope
= (sint32
) (65536.0 * inverseSlope
);
1478 currRaster
= r
+ ((sint
) floorf(y1
) - minY
);
1479 currRaster
->first
= std::min((sint
) floorf(x1
), currRaster
->first
);
1481 iposx
= (sint32
) (65536.0 * (x1
+ inverseSlope
* (ceilf(y1
) - y1
))); // sub-pixel accuracy
1482 if (ceilf(y1
) == y1
)
1484 iposx
+= iInverseSlope
;
1488 currRaster
->first
= std::min((sint
) (iposx
>> 16), currRaster
->first
);
1489 iposx
+= iInverseSlope
;
1496 // *******************************************************************************
1497 void CPolygon2D::computeOuterBorders(TRasterVect
&borders
, sint
&minimumY
) const
1500 checkValidBorders();
1503 // NB : this version is not much optimized, because of the min/max test
1504 // during rasterization.
1505 // TODO : optimize if needed ...
1507 if (Vertices
.empty())
1512 const CVector2f
*first
= &Vertices
[0];
1513 const CVector2f
*last
= first
+ Vertices
.size();
1515 const CVector2f
*curr
= first
, *next
, *plowest
,*phighest
;
1516 const CVector2f
*pHighestRight
, *pHighestRightNext
, *pHighestLeft
;
1517 const CVector2f
*pPrevHighestLeft
;
1518 double deltaXN
, deltaYN
, deltaXP
, deltaYP
;
1519 bool ccw
; // true if CCW oriented
1521 sint highest
, lowest
;
1523 float fright
= curr
->x
;
1524 float fleft
= curr
->x
;
1525 float fhighest
= curr
->y
;
1526 float flowest
= curr
->y
;
1527 plowest
= phighest
= curr
;
1529 // compute highest and lowest pos of the poly
1532 fright
= std::max(fright
, curr
->x
);
1533 fleft
= std::min(fleft
, curr
->x
);
1534 if (curr
->y
> flowest
)
1539 if (curr
->y
< fhighest
)
1546 while (curr
!= last
);
1549 highest
= (sint
) floorf(fhighest
);
1550 lowest
= (sint
) floorf(flowest
);
1552 polyHeight
= lowest
- highest
+ 1;
1553 nlassert(polyHeight
> 0);
1555 // make room for rasters
1556 borders
.resize(polyHeight
);
1557 // fill with xmin / xman
1558 sint ileft
= (sint
) floorf(fleft
);
1559 sint iright
= (sint
) ceilf(fright
);
1561 if (flowest
== fhighest
) // special case : degenerate poly
1565 borders
.front().first
= ileft
;
1566 borders
.front().second
= ileft
;
1570 for(TRasterVect::iterator it
= borders
.begin(); it
!= borders
.end(); ++it
)
1578 pHighestRight
= phighest
;
1581 pHighestRightNext
= pHighestRight
+ 1;
1582 if (pHighestRightNext
== last
) pHighestRightNext
= first
;
1583 if (pHighestRightNext
->y
!= pHighestRight
->y
) break;
1584 pHighestRight
= pHighestRightNext
;
1587 pPrevHighestLeft
= pHighestRight
;
1588 pHighestLeft
= pHighestRight
;
1590 if (pHighestLeft
== last
) pHighestLeft
= first
;
1592 while (pHighestLeft
->y
!= fhighest
)
1594 pPrevHighestLeft
= pHighestLeft
;
1596 if (pHighestLeft
== last
) pHighestLeft
= first
;
1600 // we need to get the orientation of the polygon
1601 // There are 2 case : flat, and non-flat top
1603 // check for flat top
1604 if (pHighestLeft
->x
!= pHighestRight
->x
)
1606 // compare right and left side
1607 if (pHighestLeft
->x
> pHighestRight
->x
)
1609 ccw
= true; // the list is CCW oriented
1610 std::swap(pHighestLeft
, pHighestRight
);
1614 ccw
= false; // the list is CW oriented
1619 pHighestRightNext
= pHighestRight
+ 1;
1620 if (pHighestRightNext
== last
) pHighestRightNext
= first
;
1621 deltaXN
= pHighestRightNext
->x
- pHighestRight
->x
;
1622 deltaYN
= pHighestRightNext
->y
- pHighestRight
->y
;
1623 deltaXP
= pPrevHighestLeft
->x
- pHighestLeft
->x
;
1624 deltaYP
= pPrevHighestLeft
->y
- pHighestLeft
->y
;
1625 if ((deltaXN
* deltaYP
- deltaYN
* deltaXP
) < 0)
1628 std::swap(pHighestLeft
, pHighestRight
);
1638 // clock wise oriented list
1639 curr
= pHighestRight
;
1643 if (next
== last
) next
= first
;
1644 ScanOuterEdgeRight(&borders
[0], curr
->x
, curr
->y
, next
->x
, next
->y
, minimumY
);
1647 while (curr
!= plowest
);
1651 if (next
== last
) next
= first
;
1652 ScanOuterEdgeLeft(&borders
[0], next
->x
, next
->y
, curr
->x
, curr
->y
, minimumY
);
1655 while (curr
!= pHighestLeft
);
1660 curr
= pHighestLeft
;
1664 if (next
== last
) next
= first
;
1665 ScanOuterEdgeLeft(&borders
[0], curr
->x
, curr
->y
, next
->x
, next
->y
, minimumY
);
1668 while (curr
!= plowest
);
1672 if (next
== last
) next
= first
;
1673 ScanOuterEdgeRight(&borders
[0], next
->x
, next
->y
, curr
->x
, curr
->y
, minimumY
);
1676 while (curr
!= pHighestRight
);
1681 //=========================================================================
1682 // scan inner right edge of a poly
1683 static void ScanInnerEdge(CPolygon2D::TRaster
*r
, float x1
, float y1
, float x2
, float y2
, sint minY
, bool rightEdge
)
1685 const uint rol16
= 65536;
1686 CPolygon2D::TRaster
*currRaster
;
1687 float deltaX
, deltaY
;
1689 sint32 iInverseSlope
, iposx
;
1692 height
= (sint
) (ceilf(y2
) - floorf(y1
));
1693 if (height
<= 0) return;
1696 inverseSlope
= deltaX
/ deltaY
;
1699 iInverseSlope
= (sint32
) (rol16
* inverseSlope
);
1700 currRaster
= r
+ ((sint
) floorf(y1
) - minY
);
1702 iposx
= (sint32
) (rol16
* (x1
+ inverseSlope
* (ceilf(y1
) - y1
))); // sub-pixel accuracy
1709 if (floorf(y1
) != y1
)
1711 currRaster
->second
= std::min((sint
) floorf(x1
) - 1, currRaster
->second
);
1714 if (height
== 0) return;
1718 currRaster
->second
= std::min((sint
) (iposx
>> 16), currRaster
->second
);
1719 iposx
+= iInverseSlope
;
1727 if (floorf(y1
) != y1
)
1729 currRaster
->second
= std::min((sint
) (iposx
>> 16), currRaster
->second
);
1732 if (height
== 0) return;
1736 iposx
+= iInverseSlope
;
1737 currRaster
->second
= std::min((sint
) (iposx
>> 16), currRaster
->second
);
1740 // fill bottom of segment
1741 currRaster
->second
= std::min((sint
) floorf(x2
) - 1, currRaster
->second
);
1750 if (floorf(y1
) != y1
)
1752 currRaster
->first
= std::max((sint
) ceilf(x1
), currRaster
->first
);
1755 if (height
== 0) return;
1759 currRaster
->first
= std::max((sint
) (iposx
>> 16), currRaster
->first
);
1760 iposx
+= iInverseSlope
;
1768 if (floorf(y1
) != y1
)
1770 currRaster
->first
= std::max((sint
) (iposx
>> 16), currRaster
->first
);
1773 if (height
== 0) return;
1777 iposx
+= iInverseSlope
;
1778 currRaster
->first
= std::max((sint
) (iposx
>> 16), currRaster
->first
);
1781 // fill bottom of segment
1782 currRaster
->first
= std::max((sint
) ceilf(x2
), currRaster
->first
);
1787 // *******************************************************************************
1788 void CPolygon2D::computeInnerBorders(TRasterVect
&borders
, sint
&minimumY
) const
1791 checkValidBorders();
1794 if (Vertices
.empty())
1799 const CVector2f
*first
= &Vertices
[0];
1800 const CVector2f
*last
= first
+ Vertices
.size();
1802 const CVector2f
*curr
= first
, *next
, *plowest
,*phighest
;
1803 const CVector2f
*pHighestRight
, *pHighestRightNext
, *pHighestLeft
;
1804 const CVector2f
*pPrevHighestLeft
;
1805 double deltaXN
, deltaYN
, deltaXP
, deltaYP
;
1806 bool ccw
; // true if CCW oriented
1808 sint highest
, lowest
;
1810 float fright
= curr
->x
;
1811 float fleft
= curr
->x
;
1812 float fhighest
= curr
->y
;
1813 float flowest
= curr
->y
;
1814 plowest
= phighest
= curr
;
1816 // compute highest (with lowest y) and lowest (with highest y) points of the poly
1819 fright
= std::max(fright
, curr
->x
);
1820 fleft
= std::min(fleft
, curr
->x
);
1821 if (curr
->y
> flowest
)
1826 if (curr
->y
< fhighest
)
1833 while (curr
!= last
);
1834 if (flowest
== fhighest
)
1839 highest
= (sint
) floorf(fhighest
);
1840 lowest
= (sint
) ceilf(flowest
);
1842 polyHeight
= lowest
- highest
;
1844 if (polyHeight
== 0)
1849 // make room for rasters
1850 borders
.resize(polyHeight
);
1851 // fill with xmin / xman
1852 sint ileft
= (sint
) floorf(fleft
) - 1;
1853 sint iright
= (sint
) ceilf(fright
);
1854 for(TRasterVect::iterator it
= borders
.begin(); it
!= borders
.end(); ++it
)
1856 it
->second
= iright
;
1859 pHighestRight
= phighest
;
1862 pHighestRightNext
= pHighestRight
+ 1;
1863 if (pHighestRightNext
== last
) pHighestRightNext
= first
;
1864 if (pHighestRightNext
->y
!= pHighestRight
->y
) break;
1865 pHighestRight
= pHighestRightNext
;
1868 pPrevHighestLeft
= pHighestRight
;
1869 pHighestLeft
= pHighestRight
;
1871 if (pHighestLeft
== last
) pHighestLeft
= first
;
1873 while (pHighestLeft
->y
!= fhighest
)
1875 pPrevHighestLeft
= pHighestLeft
;
1877 if (pHighestLeft
== last
) pHighestLeft
= first
;
1881 // we need to get the orientation of the polygon
1882 // There are 2 case : flat, and non-flat top
1884 // check for flat top
1885 if (pHighestLeft
->x
!= pHighestRight
->x
)
1887 // compare right and left side
1888 if (pHighestLeft
->x
> pHighestRight
->x
)
1890 ccw
= true; // the list is CCW oriented
1891 std::swap(pHighestLeft
, pHighestRight
);
1895 ccw
= false; // the list is CW oriented
1900 pHighestRightNext
= pHighestRight
+ 1;
1901 if (pHighestRightNext
== last
) pHighestRightNext
= first
;
1902 deltaXN
= pHighestRightNext
->x
- pHighestRight
->x
;
1903 deltaYN
= pHighestRightNext
->y
- pHighestRight
->y
;
1904 deltaXP
= pPrevHighestLeft
->x
- pHighestLeft
->x
;
1905 deltaYP
= pPrevHighestLeft
->y
- pHighestLeft
->y
;
1906 if ((deltaXN
* deltaYP
- deltaYN
* deltaXP
) < 0)
1909 std::swap(pHighestLeft
, pHighestRight
);
1920 curr
= pHighestRight
;
1924 if (next
== last
) next
= first
;
1925 ScanInnerEdge(&borders
[0], curr
->x
, curr
->y
, next
->x
, next
->y
, minimumY
, true);
1928 while (curr
!= plowest
);
1932 if (next
== last
) next
= first
;
1933 ScanInnerEdge(&borders
[0], next
->x
, next
->y
, curr
->x
, curr
->y
, minimumY
, false);
1936 while (curr
!= pHighestLeft
);
1941 curr
= pHighestLeft
;
1945 if (next
== last
) next
= first
;
1946 ScanInnerEdge(&borders
[0], curr
->x
, curr
->y
, next
->x
, next
->y
, minimumY
, false);
1949 while (curr
!= plowest
);
1953 if (next
== last
) next
= first
;
1954 ScanInnerEdge(&borders
[0], next
->x
, next
->y
, curr
->x
, curr
->y
, minimumY
, true);
1957 while (curr
!= pHighestRight
);
1960 if (floorf(fhighest
) != fhighest
)
1962 borders
[0].first
= 1;
1963 borders
[0].second
= 0;
1966 if (floorf(flowest
) != flowest
)
1968 borders
.back().first
= 1;
1969 borders
.back().second
= 0;
1973 // *******************************************************************************
1974 void CPolygon2D::checkValidBorders() const
1976 for (uint k
= 0; k
< Vertices
.size(); ++k
)
1978 nlassert(Vertices
[k
].x
>= -32000.f
); // coordinate too big !
1979 nlassert(Vertices
[k
].x
< 32000.f
); // coordinate too big !
1980 nlassert(Vertices
[k
].y
>= -32000.f
); // coordinate too big !
1981 nlassert(Vertices
[k
].y
< 32000.f
); // coordinate too big !
1985 // *******************************************************************************
1986 /// Sum the dot product of this poly vertices against a plane
1987 float CPolygon2D::sumDPAgainstLine(float a
, float b
, float c
) const
1990 for (uint k
= 0; k
< Vertices
.size(); ++k
)
1992 const CVector2f
&p
= Vertices
[k
];
1993 sum
+= a
* p
.x
+ b
* p
.y
+ c
;
1999 // *******************************************************************************
2000 bool CPolygon2D::getNonNullSeg(uint
&index
) const
2002 nlassert(!Vertices
.empty());
2003 float bestLength
= 0.f
;
2004 sint bestIndex
= -1;
2005 for (uint k
= 0; k
< Vertices
.size() - 1; ++k
)
2007 float norm2
= (Vertices
[k
+ 1] - Vertices
[k
]).sqrnorm();
2008 if ( norm2
> bestLength
)
2011 bestIndex
= (int) k
;
2014 float norm2
= (Vertices
[Vertices
.size() - 1] - Vertices
[0]).sqrnorm();
2015 if ( norm2
> bestLength
)
2017 index
= (uint
)Vertices
.size() - 1;
2021 if (bestIndex
!= -1)
2033 // *******************************************************************************
2034 void CPolygon2D::getLineEquation(uint index
, float &a
, float &b
, float &c
) const
2036 nlassert(index
< Vertices
.size());
2037 const CVector2f
&v0
= getSegRef0(index
);
2038 const CVector2f
&v1
= getSegRef1(index
);
2040 NLMISC::CVector2f seg
= v0
- v1
;
2043 c
= - v0
.x
* a
- v0
.y
* b
;
2046 // *******************************************************************************
2047 bool CPolygon2D::intersect(const CPolygon2D
&other
) const
2049 nlassert(!other
.Vertices
.empty());
2050 uint nonNullSegIndex
;
2051 /// get the orientation of this poly
2052 if (getNonNullSeg(nonNullSegIndex
))
2054 float a0
, b0
, c0
; /// contains the seg 2d equation
2055 getLineEquation(nonNullSegIndex
, a0
, b0
, c0
);
2056 float orient
= sumDPAgainstLine(a0
, b0
, c0
);
2058 for (uint k
= 0; k
< Vertices
.size(); ++k
)
2060 /// don't check against a null segment
2061 if ( (getSegRef0(k
) - getSegRef1(k
)).sqrnorm() == 0.f
) continue;
2063 /// get the line equation of the current segment
2064 float a
, b
, c
; /// contains the seg 2d equation
2065 getLineEquation(k
, a
, b
, c
);
2067 for (l
= 0; l
< other
.Vertices
.size(); ++l
)
2069 const CVector2f
&ov
= other
.Vertices
[l
];
2070 if ( orient
* (ov
.x
* a
+ ov
.y
* b
+c
) > 0.f
) break;
2072 if (l
== other
.Vertices
.size()) // all point on the outside
2074 return false; // outside
2079 else // this poly is just a point
2081 return other
.contains(Vertices
[0]);
2085 // *******************************************************************************
2086 bool CPolygon2D::contains(const CVector2f
&p
, bool hintIsConvex
/*= true*/) const
2090 uint numVerts
= (uint
)Vertices
.size();
2091 nlassert(numVerts
>= 0.f
);
2092 for (uint k
= 0; k
< numVerts
; ++k
)
2094 if (getSegRef0(k
) != getSegRef1(k
))
2096 float a
, b
, c
; /// contains the seg 2d equation
2097 getLineEquation(k
, a
, b
, c
);
2098 float orient
= a
* p
.x
+ b
* p
.y
+ c
;
2099 for(uint l
= k
+ 1; l
< numVerts
; ++l
)
2101 getLineEquation(l
, a
, b
, c
);
2102 float newOrient
= a
* p
.x
+ b
* p
.y
+ c
;
2103 if (newOrient
* orient
< 0.f
) return false;
2108 // the poly reduces to a point
2109 return p
== Vertices
[0];
2114 static std::vector
<float> xInter
;
2116 for(uint k
= 0; k
< Vertices
.size(); ++k
)
2118 const CVector2f
&p0
= getSegRef0(k
);
2119 const CVector2f
&p1
= getSegRef1(k
);
2124 if ((p
.x
>= p0
.x
&& p
.x
<= p1
.x
)
2125 || (p
.x
>= p1
.x
&& p
.x
<= p0
.x
))
2131 if ((p
.y
>= p0
.y
&& p
.y
< p1
.y
) ||
2132 (p
.y
>= p1
.y
&& p
.y
< p0
.y
)
2136 float inter
= p0
.x
+ (p
.y
- p0
.y
) * (p1
.x
- p0
.x
) / (p1
.y
- p0
.y
);
2137 xInter
.push_back(inter
);
2140 if (xInter
.size() < 2) return false;
2141 std::sort(xInter
.begin(), xInter
.end());
2142 for(uint k
= 0; k
< xInter
.size() - 1; ++k
)
2144 if (p
.x
>= xInter
[k
] && p
.x
<= xInter
[k
+ 1])
2146 return (k
& 1) == 0;
2154 // *******************************************************************************
2155 CPolygon2D::CPolygon2D(const CTriangle
&tri
, const CMatrix
&projMat
)
2158 NLMISC::CVector proj
[3] = { projMat
* tri
.V0
, projMat
* tri
.V1
, projMat
* tri
.V2
};
2159 Vertices
[0].set(proj
[0].x
, proj
[0].y
);
2160 Vertices
[1].set(proj
[1].x
, proj
[1].y
);
2161 Vertices
[2].set(proj
[2].x
, proj
[2].y
);
2164 // *******************************************************************************
2165 void CPolygon2D::getBoundingRect(CVector2f
&minCorner
, CVector2f
&maxCorner
) const
2167 nlassert(!Vertices
.empty());
2168 minCorner
= maxCorner
= Vertices
[0];
2169 uint numVertices
= (uint
)Vertices
.size();
2170 for(uint k
= 0; k
< numVertices
; ++k
)
2172 minCorner
.minof(minCorner
, Vertices
[k
]);
2173 maxCorner
.maxof(minCorner
, Vertices
[k
]);
2177 // *******************************************************************************
2178 bool operator ==(const CPolygon2D
&lhs
,const CPolygon2D
&rhs
)
2180 if (lhs
.Vertices
.size() != rhs
.Vertices
.size()) return false;
2181 return std::equal(lhs
.Vertices
.begin(), lhs
.Vertices
.end(), rhs
.Vertices
.begin());
2184 // *******************************************************************************
2185 bool operator < (const CPolygon2D
&lhs
, const CPolygon2D
&rhs
)
2187 if (lhs
.Vertices
.size() != rhs
.Vertices
.size()) return lhs
.Vertices
.size() < rhs
.Vertices
.size();
2188 for(uint k
= 0; k
< lhs
.Vertices
.size(); ++k
)
2190 if (lhs
.Vertices
[k
] != rhs
.Vertices
[k
]) return lhs
.Vertices
[k
] < rhs
.Vertices
[k
];
2196 // *******************************************************************************
2197 static inline bool testSegmentIntersection(const CVector2f
&a
, const CVector2f
&b
,
2198 const CVector2f
&c
, const CVector2f
&d
)
2200 double denom
= a
.x
* double(d
.y
- c
.y
) +
2201 b
.x
* double(c
.y
- d
.y
) +
2202 d
.x
* double(b
.y
- a
.y
) +
2203 c
.x
* double(a
.y
- b
.y
);
2205 if (denom
== 0) return false;
2207 double num
= a
.x
* double(d
.y
- c
.y
) +
2208 c
.x
* double(a
.y
- d
.y
) +
2209 d
.x
* double(c
.y
- a
.y
);
2211 if (num
== 0 || (num
== denom
)) return false;
2212 double lambda
= num
/ denom
;
2213 if (lambda
<= 0 || lambda
>= 1) return false;
2215 num
= - (a
.x
* double(c
.y
- b
.y
) +
2216 b
.x
* double(a
.y
- c
.y
) +
2217 c
.x
* double(b
.y
- a
.y
));
2219 if (num
== 0 || (num
== denom
)) return false;
2220 lambda
= num
/ denom
;
2221 if (lambda
<= 0 || lambda
>= 1) return false;
2226 // *******************************************************************************
2227 bool CPolygon2D::selfIntersect() const
2229 if (Vertices
.size() < 3) return false;
2230 uint numEdges
= (uint
)Vertices
.size();
2231 for(uint k
= 0; k
< numEdges
; ++k
)
2233 // test intersection with all other edges that don't share a vertex with this one
2234 const CVector2f
&p0
= getSegRef0(k
);
2235 const CVector2f
&p1
= getSegRef1(k
);
2236 for(uint l
= 0; l
< k
; ++l
)
2238 const CVector2f
&v0
= getSegRef0(l
);
2239 const CVector2f
&v1
= getSegRef1(l
);
2240 if (v0
== p0
|| v0
== p1
|| v1
== p0
|| v1
== p1
) continue;
2242 if (testSegmentIntersection(p0
, p1
, v0
, v1
)) return true;