xref: /AOO41X/main/basegfx/source/polygon/b2dpolygontriangulator.cxx (revision cdf0e10c4e3984b49a9502b011690b615761d4a3)
1*cdf0e10cSrcweir /*************************************************************************
2*cdf0e10cSrcweir  *
3*cdf0e10cSrcweir  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4*cdf0e10cSrcweir  *
5*cdf0e10cSrcweir  * Copyright 2000, 2010 Oracle and/or its affiliates.
6*cdf0e10cSrcweir  *
7*cdf0e10cSrcweir  * OpenOffice.org - a multi-platform office productivity suite
8*cdf0e10cSrcweir  *
9*cdf0e10cSrcweir  * This file is part of OpenOffice.org.
10*cdf0e10cSrcweir  *
11*cdf0e10cSrcweir  * OpenOffice.org is free software: you can redistribute it and/or modify
12*cdf0e10cSrcweir  * it under the terms of the GNU Lesser General Public License version 3
13*cdf0e10cSrcweir  * only, as published by the Free Software Foundation.
14*cdf0e10cSrcweir  *
15*cdf0e10cSrcweir  * OpenOffice.org is distributed in the hope that it will be useful,
16*cdf0e10cSrcweir  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17*cdf0e10cSrcweir  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18*cdf0e10cSrcweir  * GNU Lesser General Public License version 3 for more details
19*cdf0e10cSrcweir  * (a copy is included in the LICENSE file that accompanied this code).
20*cdf0e10cSrcweir  *
21*cdf0e10cSrcweir  * You should have received a copy of the GNU Lesser General Public License
22*cdf0e10cSrcweir  * version 3 along with OpenOffice.org.  If not, see
23*cdf0e10cSrcweir  * <http://www.openoffice.org/license.html>
24*cdf0e10cSrcweir  * for a copy of the LGPLv3 License.
25*cdf0e10cSrcweir  *
26*cdf0e10cSrcweir  ************************************************************************/
27*cdf0e10cSrcweir 
28*cdf0e10cSrcweir // MARKER(update_precomp.py): autogen include statement, do not remove
29*cdf0e10cSrcweir #include "precompiled_basegfx.hxx"
30*cdf0e10cSrcweir #include <basegfx/polygon/b2dpolygontriangulator.hxx>
31*cdf0e10cSrcweir #include <osl/diagnose.h>
32*cdf0e10cSrcweir #include <basegfx/point/b2dpoint.hxx>
33*cdf0e10cSrcweir #include <basegfx/polygon/b2dpolygon.hxx>
34*cdf0e10cSrcweir #include <basegfx/vector/b2dvector.hxx>
35*cdf0e10cSrcweir #include <basegfx/polygon/b2dpolygontools.hxx>
36*cdf0e10cSrcweir #include <basegfx/polygon/b2dpolypolygontools.hxx>
37*cdf0e10cSrcweir #include <basegfx/range/b2drange.hxx>
38*cdf0e10cSrcweir #include <basegfx/numeric/ftools.hxx>
39*cdf0e10cSrcweir 
40*cdf0e10cSrcweir #include <algorithm>
41*cdf0e10cSrcweir 
42*cdf0e10cSrcweir //////////////////////////////////////////////////////////////////////////////
43*cdf0e10cSrcweir 
44*cdf0e10cSrcweir namespace basegfx
45*cdf0e10cSrcweir {
46*cdf0e10cSrcweir 	namespace
47*cdf0e10cSrcweir 	{
48*cdf0e10cSrcweir 		class EdgeEntry
49*cdf0e10cSrcweir 		{
50*cdf0e10cSrcweir 			EdgeEntry*								mpNext;
51*cdf0e10cSrcweir 			B2DPoint								maStart;
52*cdf0e10cSrcweir 			B2DPoint								maEnd;
53*cdf0e10cSrcweir 			double									mfAtan2;
54*cdf0e10cSrcweir 
55*cdf0e10cSrcweir 		public:
56*cdf0e10cSrcweir 			EdgeEntry(const B2DPoint& rStart, const B2DPoint& rEnd)
57*cdf0e10cSrcweir 			:	mpNext(0L),
58*cdf0e10cSrcweir 				maStart(rStart),
59*cdf0e10cSrcweir 				maEnd(rEnd),
60*cdf0e10cSrcweir 				mfAtan2(0.0)
61*cdf0e10cSrcweir 			{
62*cdf0e10cSrcweir 				// make sure edge goes down. If horizontal, let it go to the right (left-handed).
63*cdf0e10cSrcweir 				bool bSwap(false);
64*cdf0e10cSrcweir 
65*cdf0e10cSrcweir 				if(::basegfx::fTools::equal(maStart.getY(), maEnd.getY()))
66*cdf0e10cSrcweir 				{
67*cdf0e10cSrcweir 					if(maStart.getX() > maEnd.getX())
68*cdf0e10cSrcweir 					{
69*cdf0e10cSrcweir 						bSwap = true;
70*cdf0e10cSrcweir 					}
71*cdf0e10cSrcweir 				}
72*cdf0e10cSrcweir 				else if(maStart.getY() > maEnd.getY())
73*cdf0e10cSrcweir 				{
74*cdf0e10cSrcweir 					bSwap = true;
75*cdf0e10cSrcweir 				}
76*cdf0e10cSrcweir 
77*cdf0e10cSrcweir 				if(bSwap)
78*cdf0e10cSrcweir 				{
79*cdf0e10cSrcweir 					maStart = rEnd;
80*cdf0e10cSrcweir 					maEnd = rStart;
81*cdf0e10cSrcweir 				}
82*cdf0e10cSrcweir 
83*cdf0e10cSrcweir 				mfAtan2 = atan2(maEnd.getY() - maStart.getY(), maEnd.getX() - maStart.getX());
84*cdf0e10cSrcweir 			}
85*cdf0e10cSrcweir 
86*cdf0e10cSrcweir 			~EdgeEntry()
87*cdf0e10cSrcweir 			{
88*cdf0e10cSrcweir 			}
89*cdf0e10cSrcweir 
90*cdf0e10cSrcweir 			bool operator<(const EdgeEntry& rComp) const
91*cdf0e10cSrcweir 			{
92*cdf0e10cSrcweir 				if(::basegfx::fTools::equal(maStart.getY(), rComp.maStart.getY()))
93*cdf0e10cSrcweir 				{
94*cdf0e10cSrcweir 					if(::basegfx::fTools::equal(maStart.getX(), rComp.maStart.getX()))
95*cdf0e10cSrcweir 					{
96*cdf0e10cSrcweir 						// same in x and y -> same start point. Sort emitting vectors from left to right.
97*cdf0e10cSrcweir 						return (mfAtan2 > rComp.mfAtan2);
98*cdf0e10cSrcweir 					}
99*cdf0e10cSrcweir 
100*cdf0e10cSrcweir 					return (maStart.getX() < rComp.maStart.getX());
101*cdf0e10cSrcweir 				}
102*cdf0e10cSrcweir 
103*cdf0e10cSrcweir 				return (maStart.getY() < rComp.maStart.getY());
104*cdf0e10cSrcweir 			}
105*cdf0e10cSrcweir 
106*cdf0e10cSrcweir 			bool operator==(const EdgeEntry& rComp) const
107*cdf0e10cSrcweir 			{
108*cdf0e10cSrcweir 				return (maStart.equal(rComp.maStart) && maEnd.equal(rComp.maEnd));
109*cdf0e10cSrcweir 			}
110*cdf0e10cSrcweir 
111*cdf0e10cSrcweir 			bool operator!=(const EdgeEntry& rComp) const
112*cdf0e10cSrcweir 			{
113*cdf0e10cSrcweir 				return !(*this == rComp);
114*cdf0e10cSrcweir 			}
115*cdf0e10cSrcweir 
116*cdf0e10cSrcweir 			const B2DPoint& getStart() const { return maStart; }
117*cdf0e10cSrcweir 			const B2DPoint& getEnd() const { return maEnd; }
118*cdf0e10cSrcweir 
119*cdf0e10cSrcweir 			EdgeEntry* getNext() const { return mpNext; }
120*cdf0e10cSrcweir 			void setNext(EdgeEntry* pNext) { mpNext = pNext; }
121*cdf0e10cSrcweir 		};
122*cdf0e10cSrcweir 
123*cdf0e10cSrcweir 		//////////////////////////////////////////////////////////////////////////////
124*cdf0e10cSrcweir 
125*cdf0e10cSrcweir 		typedef ::std::vector< EdgeEntry > EdgeEntries;
126*cdf0e10cSrcweir 		typedef ::std::vector< EdgeEntry* > EdgeEntryPointers;
127*cdf0e10cSrcweir 
128*cdf0e10cSrcweir 		//////////////////////////////////////////////////////////////////////////////
129*cdf0e10cSrcweir 
130*cdf0e10cSrcweir 		class Triangulator
131*cdf0e10cSrcweir 		{
132*cdf0e10cSrcweir 			EdgeEntry*										mpList;
133*cdf0e10cSrcweir 			EdgeEntries										maStartEntries;
134*cdf0e10cSrcweir 			EdgeEntryPointers								maNewEdgeEntries;
135*cdf0e10cSrcweir 			B2DPolygon										maResult;
136*cdf0e10cSrcweir 
137*cdf0e10cSrcweir 			void handleClosingEdge(const B2DPoint& rStart, const B2DPoint& rEnd);
138*cdf0e10cSrcweir 			bool CheckPointInTriangle(EdgeEntry* pEdgeA, EdgeEntry* pEdgeB, const B2DPoint& rTestPoint);
139*cdf0e10cSrcweir 			void createTriangle(const B2DPoint& rA, const B2DPoint& rB, const B2DPoint& rC);
140*cdf0e10cSrcweir 
141*cdf0e10cSrcweir 		public:
142*cdf0e10cSrcweir 			Triangulator(const B2DPolyPolygon& rCandidate);
143*cdf0e10cSrcweir 			~Triangulator();
144*cdf0e10cSrcweir 
145*cdf0e10cSrcweir 			const B2DPolygon getResult() const { return maResult; }
146*cdf0e10cSrcweir 		};
147*cdf0e10cSrcweir 
148*cdf0e10cSrcweir 		void Triangulator::handleClosingEdge(const B2DPoint& rStart, const B2DPoint& rEnd)
149*cdf0e10cSrcweir 		{
150*cdf0e10cSrcweir 			// create an entry, else the comparison might use the wrong edges
151*cdf0e10cSrcweir 			EdgeEntry aNew(rStart, rEnd);
152*cdf0e10cSrcweir 			EdgeEntry* pCurr = mpList;
153*cdf0e10cSrcweir 			EdgeEntry* pPrev = 0L;
154*cdf0e10cSrcweir 
155*cdf0e10cSrcweir 			while(pCurr
156*cdf0e10cSrcweir 				&& pCurr->getStart().getY() <= aNew.getStart().getY()
157*cdf0e10cSrcweir 				&& *pCurr != aNew)
158*cdf0e10cSrcweir 			{
159*cdf0e10cSrcweir 				pPrev = pCurr;
160*cdf0e10cSrcweir 				pCurr = pCurr->getNext();
161*cdf0e10cSrcweir 			}
162*cdf0e10cSrcweir 
163*cdf0e10cSrcweir 			if(pCurr && *pCurr == aNew)
164*cdf0e10cSrcweir 			{
165*cdf0e10cSrcweir 				// found closing edge, remove
166*cdf0e10cSrcweir 				if(pPrev)
167*cdf0e10cSrcweir 				{
168*cdf0e10cSrcweir 					pPrev->setNext(pCurr->getNext());
169*cdf0e10cSrcweir 				}
170*cdf0e10cSrcweir 				else
171*cdf0e10cSrcweir 				{
172*cdf0e10cSrcweir 					mpList = pCurr->getNext();
173*cdf0e10cSrcweir 				}
174*cdf0e10cSrcweir 			}
175*cdf0e10cSrcweir 			else
176*cdf0e10cSrcweir 			{
177*cdf0e10cSrcweir 				// insert closing edge
178*cdf0e10cSrcweir 				EdgeEntry* pNew = new EdgeEntry(aNew);
179*cdf0e10cSrcweir 				maNewEdgeEntries.push_back(pNew);
180*cdf0e10cSrcweir 				pCurr = mpList;
181*cdf0e10cSrcweir 				pPrev = 0L;
182*cdf0e10cSrcweir 
183*cdf0e10cSrcweir 				while(pCurr && *pCurr < *pNew)
184*cdf0e10cSrcweir 				{
185*cdf0e10cSrcweir 					pPrev = pCurr;
186*cdf0e10cSrcweir 					pCurr = pCurr->getNext();
187*cdf0e10cSrcweir 				}
188*cdf0e10cSrcweir 
189*cdf0e10cSrcweir 				if(pPrev)
190*cdf0e10cSrcweir 				{
191*cdf0e10cSrcweir 					pNew->setNext(pPrev->getNext());
192*cdf0e10cSrcweir 					pPrev->setNext(pNew);
193*cdf0e10cSrcweir 				}
194*cdf0e10cSrcweir 				else
195*cdf0e10cSrcweir 				{
196*cdf0e10cSrcweir 					pNew->setNext(mpList);
197*cdf0e10cSrcweir 					mpList = pNew;
198*cdf0e10cSrcweir 				}
199*cdf0e10cSrcweir 			}
200*cdf0e10cSrcweir 		}
201*cdf0e10cSrcweir 
202*cdf0e10cSrcweir 		bool Triangulator::CheckPointInTriangle(EdgeEntry* pEdgeA, EdgeEntry* pEdgeB, const B2DPoint& rTestPoint)
203*cdf0e10cSrcweir 		{
204*cdf0e10cSrcweir 			// inside triangle or on edge?
205*cdf0e10cSrcweir 			if(tools::isPointInTriangle(pEdgeA->getStart(), pEdgeA->getEnd(), pEdgeB->getEnd(), rTestPoint, true))
206*cdf0e10cSrcweir 			{
207*cdf0e10cSrcweir 				// but not on point
208*cdf0e10cSrcweir 				if(!rTestPoint.equal(pEdgeA->getEnd()) && !rTestPoint.equal(pEdgeB->getEnd()))
209*cdf0e10cSrcweir 				{
210*cdf0e10cSrcweir 					// found point in triangle -> split triangle inserting two edges
211*cdf0e10cSrcweir 					EdgeEntry* pStart = new EdgeEntry(pEdgeA->getStart(), rTestPoint);
212*cdf0e10cSrcweir 					EdgeEntry* pEnd = new EdgeEntry(*pStart);
213*cdf0e10cSrcweir 					maNewEdgeEntries.push_back(pStart);
214*cdf0e10cSrcweir 					maNewEdgeEntries.push_back(pEnd);
215*cdf0e10cSrcweir 
216*cdf0e10cSrcweir 					pStart->setNext(pEnd);
217*cdf0e10cSrcweir 					pEnd->setNext(pEdgeA->getNext());
218*cdf0e10cSrcweir 					pEdgeA->setNext(pStart);
219*cdf0e10cSrcweir 
220*cdf0e10cSrcweir 					return false;
221*cdf0e10cSrcweir 				}
222*cdf0e10cSrcweir 			}
223*cdf0e10cSrcweir 
224*cdf0e10cSrcweir 			return true;
225*cdf0e10cSrcweir 		}
226*cdf0e10cSrcweir 
227*cdf0e10cSrcweir 		void Triangulator::createTriangle(const B2DPoint& rA, const B2DPoint& rB, const B2DPoint& rC)
228*cdf0e10cSrcweir 		{
229*cdf0e10cSrcweir 			maResult.append(rA);
230*cdf0e10cSrcweir 			maResult.append(rB);
231*cdf0e10cSrcweir 			maResult.append(rC);
232*cdf0e10cSrcweir 		}
233*cdf0e10cSrcweir 
234*cdf0e10cSrcweir 		// consume as long as there are edges
235*cdf0e10cSrcweir 		Triangulator::Triangulator(const B2DPolyPolygon& rCandidate)
236*cdf0e10cSrcweir 		:	mpList(0L)
237*cdf0e10cSrcweir 		{
238*cdf0e10cSrcweir 			// add all available edges to the single linked local list which will be sorted
239*cdf0e10cSrcweir 			// by Y,X,atan2 when adding nodes
240*cdf0e10cSrcweir 			if(rCandidate.count())
241*cdf0e10cSrcweir 			{
242*cdf0e10cSrcweir 				for(sal_uInt32 a(0L); a < rCandidate.count(); a++)
243*cdf0e10cSrcweir 				{
244*cdf0e10cSrcweir 					const B2DPolygon aPolygonCandidate(rCandidate.getB2DPolygon(a));
245*cdf0e10cSrcweir 					const sal_uInt32 nCount(aPolygonCandidate.count());
246*cdf0e10cSrcweir 
247*cdf0e10cSrcweir 					if(nCount > 2L)
248*cdf0e10cSrcweir 					{
249*cdf0e10cSrcweir 						B2DPoint aPrevPnt(aPolygonCandidate.getB2DPoint(nCount - 1L));
250*cdf0e10cSrcweir 
251*cdf0e10cSrcweir 						for(sal_uInt32 b(0L); b < nCount; b++)
252*cdf0e10cSrcweir 						{
253*cdf0e10cSrcweir 							B2DPoint aNextPnt(aPolygonCandidate.getB2DPoint(b));
254*cdf0e10cSrcweir 
255*cdf0e10cSrcweir 							if( !aPrevPnt.equal(aNextPnt) )
256*cdf0e10cSrcweir 							{
257*cdf0e10cSrcweir 								maStartEntries.push_back(EdgeEntry(aPrevPnt, aNextPnt));
258*cdf0e10cSrcweir 							}
259*cdf0e10cSrcweir 
260*cdf0e10cSrcweir 							aPrevPnt = aNextPnt;
261*cdf0e10cSrcweir 						}
262*cdf0e10cSrcweir 					}
263*cdf0e10cSrcweir 				}
264*cdf0e10cSrcweir 
265*cdf0e10cSrcweir 				if(maStartEntries.size())
266*cdf0e10cSrcweir 				{
267*cdf0e10cSrcweir 					// sort initial list
268*cdf0e10cSrcweir 					::std::sort(maStartEntries.begin(), maStartEntries.end());
269*cdf0e10cSrcweir 
270*cdf0e10cSrcweir 					// insert to own simply linked list
271*cdf0e10cSrcweir 					EdgeEntries::iterator aPos(maStartEntries.begin());
272*cdf0e10cSrcweir 					mpList = &(*aPos++);
273*cdf0e10cSrcweir 					EdgeEntry* pLast = mpList;
274*cdf0e10cSrcweir 
275*cdf0e10cSrcweir 					while(aPos != maStartEntries.end())
276*cdf0e10cSrcweir 					{
277*cdf0e10cSrcweir 						EdgeEntry* pEntry = &(*aPos++);
278*cdf0e10cSrcweir 						pLast->setNext(pEntry);
279*cdf0e10cSrcweir 						pLast = pEntry;
280*cdf0e10cSrcweir 					}
281*cdf0e10cSrcweir 				}
282*cdf0e10cSrcweir 			}
283*cdf0e10cSrcweir 
284*cdf0e10cSrcweir 			while(mpList)
285*cdf0e10cSrcweir 			{
286*cdf0e10cSrcweir 				if(mpList->getNext() && mpList->getNext()->getStart().equal(mpList->getStart()))
287*cdf0e10cSrcweir 				{
288*cdf0e10cSrcweir 					// next candidate. There are two edges and start point is equal.
289*cdf0e10cSrcweir 					// Length is not zero.
290*cdf0e10cSrcweir 					EdgeEntry* pEdgeA = mpList;
291*cdf0e10cSrcweir 					EdgeEntry* pEdgeB = pEdgeA->getNext();
292*cdf0e10cSrcweir 
293*cdf0e10cSrcweir 					if( pEdgeA->getEnd().equal(pEdgeB->getEnd()) )
294*cdf0e10cSrcweir 					{
295*cdf0e10cSrcweir 						// start and end equal -> neutral triangle, delete both
296*cdf0e10cSrcweir 						mpList = pEdgeB->getNext();
297*cdf0e10cSrcweir 					}
298*cdf0e10cSrcweir 					else
299*cdf0e10cSrcweir 					{
300*cdf0e10cSrcweir 						const B2DVector aLeft(pEdgeA->getEnd() - pEdgeA->getStart());
301*cdf0e10cSrcweir 						const B2DVector aRight(pEdgeB->getEnd() - pEdgeA->getStart());
302*cdf0e10cSrcweir 
303*cdf0e10cSrcweir 						if(ORIENTATION_NEUTRAL == getOrientation(aLeft, aRight))
304*cdf0e10cSrcweir 						{
305*cdf0e10cSrcweir 							// edges are parallel and have different length -> neutral triangle,
306*cdf0e10cSrcweir 							// delete both edges and handle closing edge
307*cdf0e10cSrcweir 							mpList = pEdgeB->getNext();
308*cdf0e10cSrcweir 							handleClosingEdge(pEdgeA->getEnd(), pEdgeB->getEnd());
309*cdf0e10cSrcweir 						}
310*cdf0e10cSrcweir 						else
311*cdf0e10cSrcweir 						{
312*cdf0e10cSrcweir 							// not parallel, look for points inside
313*cdf0e10cSrcweir 							B2DRange aRange(pEdgeA->getStart(), pEdgeA->getEnd());
314*cdf0e10cSrcweir 							aRange.expand(pEdgeB->getEnd());
315*cdf0e10cSrcweir 							EdgeEntry* pTestEdge = pEdgeB->getNext();
316*cdf0e10cSrcweir 							bool bNoPointInTriangle(true);
317*cdf0e10cSrcweir 
318*cdf0e10cSrcweir 							// look for start point in triangle
319*cdf0e10cSrcweir 							while(bNoPointInTriangle && pTestEdge)
320*cdf0e10cSrcweir 							{
321*cdf0e10cSrcweir 								if(aRange.getMaxY() < pTestEdge->getStart().getY())
322*cdf0e10cSrcweir 								{
323*cdf0e10cSrcweir 									// edge is below test range and edges are sorted -> stop looking
324*cdf0e10cSrcweir 									break;
325*cdf0e10cSrcweir 								}
326*cdf0e10cSrcweir 								else
327*cdf0e10cSrcweir 								{
328*cdf0e10cSrcweir 									// do not look for edges with same start point, they are sorted and cannot end inside.
329*cdf0e10cSrcweir 									if(!pTestEdge->getStart().equal(pEdgeA->getStart()))
330*cdf0e10cSrcweir 									{
331*cdf0e10cSrcweir 										if(aRange.isInside(pTestEdge->getStart()))
332*cdf0e10cSrcweir 										{
333*cdf0e10cSrcweir 											bNoPointInTriangle = CheckPointInTriangle(pEdgeA, pEdgeB, pTestEdge->getStart());
334*cdf0e10cSrcweir 										}
335*cdf0e10cSrcweir 									}
336*cdf0e10cSrcweir 								}
337*cdf0e10cSrcweir 
338*cdf0e10cSrcweir 								// next candidate
339*cdf0e10cSrcweir 								pTestEdge = pTestEdge->getNext();
340*cdf0e10cSrcweir 							}
341*cdf0e10cSrcweir 
342*cdf0e10cSrcweir 							if(bNoPointInTriangle)
343*cdf0e10cSrcweir 							{
344*cdf0e10cSrcweir 								// look for end point in triange
345*cdf0e10cSrcweir 								pTestEdge = pEdgeB->getNext();
346*cdf0e10cSrcweir 
347*cdf0e10cSrcweir 								while(bNoPointInTriangle && pTestEdge)
348*cdf0e10cSrcweir 								{
349*cdf0e10cSrcweir 									if(aRange.getMaxY() < pTestEdge->getStart().getY())
350*cdf0e10cSrcweir 									{
351*cdf0e10cSrcweir 										// edge is below test range and edges are sorted -> stop looking
352*cdf0e10cSrcweir 										break;
353*cdf0e10cSrcweir 									}
354*cdf0e10cSrcweir 									else
355*cdf0e10cSrcweir 									{
356*cdf0e10cSrcweir 										// do not look for edges with same end point, they are sorted and cannot end inside.
357*cdf0e10cSrcweir 										if(!pTestEdge->getEnd().equal(pEdgeA->getStart()))
358*cdf0e10cSrcweir 										{
359*cdf0e10cSrcweir 											if(aRange.isInside(pTestEdge->getEnd()))
360*cdf0e10cSrcweir 											{
361*cdf0e10cSrcweir 												bNoPointInTriangle = CheckPointInTriangle(pEdgeA, pEdgeB, pTestEdge->getEnd());
362*cdf0e10cSrcweir 											}
363*cdf0e10cSrcweir 										}
364*cdf0e10cSrcweir 									}
365*cdf0e10cSrcweir 
366*cdf0e10cSrcweir 									// next candidate
367*cdf0e10cSrcweir 									pTestEdge = pTestEdge->getNext();
368*cdf0e10cSrcweir 								}
369*cdf0e10cSrcweir 							}
370*cdf0e10cSrcweir 
371*cdf0e10cSrcweir 							if(bNoPointInTriangle)
372*cdf0e10cSrcweir 							{
373*cdf0e10cSrcweir 								// create triangle, remove edges, handle closing edge
374*cdf0e10cSrcweir 								mpList = pEdgeB->getNext();
375*cdf0e10cSrcweir 								createTriangle(pEdgeA->getStart(), pEdgeB->getEnd(), pEdgeA->getEnd());
376*cdf0e10cSrcweir 								handleClosingEdge(pEdgeA->getEnd(), pEdgeB->getEnd());
377*cdf0e10cSrcweir 							}
378*cdf0e10cSrcweir 						}
379*cdf0e10cSrcweir 					}
380*cdf0e10cSrcweir 				}
381*cdf0e10cSrcweir 				else
382*cdf0e10cSrcweir 				{
383*cdf0e10cSrcweir 					// only one entry at start point, delete it
384*cdf0e10cSrcweir 					mpList = mpList->getNext();
385*cdf0e10cSrcweir 				}
386*cdf0e10cSrcweir 			}
387*cdf0e10cSrcweir 		}
388*cdf0e10cSrcweir 
389*cdf0e10cSrcweir 		Triangulator::~Triangulator()
390*cdf0e10cSrcweir 		{
391*cdf0e10cSrcweir 			EdgeEntryPointers::iterator aIter(maNewEdgeEntries.begin());
392*cdf0e10cSrcweir 
393*cdf0e10cSrcweir 			while(aIter != maNewEdgeEntries.end())
394*cdf0e10cSrcweir 			{
395*cdf0e10cSrcweir 				delete (*aIter++);
396*cdf0e10cSrcweir 			}
397*cdf0e10cSrcweir 		}
398*cdf0e10cSrcweir 
399*cdf0e10cSrcweir 	} // end of anonymous namespace
400*cdf0e10cSrcweir } // end of namespace basegfx
401*cdf0e10cSrcweir 
402*cdf0e10cSrcweir //////////////////////////////////////////////////////////////////////////////
403*cdf0e10cSrcweir 
404*cdf0e10cSrcweir namespace basegfx
405*cdf0e10cSrcweir {
406*cdf0e10cSrcweir 	namespace triangulator
407*cdf0e10cSrcweir 	{
408*cdf0e10cSrcweir 		B2DPolygon triangulate(const B2DPolygon& rCandidate)
409*cdf0e10cSrcweir 		{
410*cdf0e10cSrcweir 			B2DPolygon aRetval;
411*cdf0e10cSrcweir 
412*cdf0e10cSrcweir 			// subdivide locally (triangulate does not work with beziers), remove double and neutral points
413*cdf0e10cSrcweir             B2DPolygon aCandidate(rCandidate.areControlPointsUsed() ? tools::adaptiveSubdivideByAngle(rCandidate) : rCandidate);
414*cdf0e10cSrcweir 			aCandidate.removeDoublePoints();
415*cdf0e10cSrcweir 			aCandidate = tools::removeNeutralPoints(aCandidate);
416*cdf0e10cSrcweir 
417*cdf0e10cSrcweir 			if(2L == aCandidate.count())
418*cdf0e10cSrcweir 			{
419*cdf0e10cSrcweir 				// candidate IS a triangle, just append
420*cdf0e10cSrcweir 				aRetval.append(aCandidate);
421*cdf0e10cSrcweir 			}
422*cdf0e10cSrcweir 			else if(aCandidate.count() > 2L)
423*cdf0e10cSrcweir 			{
424*cdf0e10cSrcweir 				if(tools::isConvex(aCandidate))
425*cdf0e10cSrcweir 				{
426*cdf0e10cSrcweir 					// polygon is convex, just use a triangle fan
427*cdf0e10cSrcweir 					tools::addTriangleFan(aCandidate, aRetval);
428*cdf0e10cSrcweir 				}
429*cdf0e10cSrcweir 				else
430*cdf0e10cSrcweir 				{
431*cdf0e10cSrcweir 					// polygon is concave.
432*cdf0e10cSrcweir                     const B2DPolyPolygon aCandPolyPoly(aCandidate);
433*cdf0e10cSrcweir 					Triangulator aTriangulator(aCandPolyPoly);
434*cdf0e10cSrcweir 					aRetval = aTriangulator.getResult();
435*cdf0e10cSrcweir 				}
436*cdf0e10cSrcweir 			}
437*cdf0e10cSrcweir 
438*cdf0e10cSrcweir 			return aRetval;
439*cdf0e10cSrcweir 		}
440*cdf0e10cSrcweir 
441*cdf0e10cSrcweir 		B2DPolygon triangulate(const B2DPolyPolygon& rCandidate)
442*cdf0e10cSrcweir 		{
443*cdf0e10cSrcweir 			B2DPolygon aRetval;
444*cdf0e10cSrcweir 
445*cdf0e10cSrcweir 			// subdivide locally (triangulate does not work with beziers)
446*cdf0e10cSrcweir             B2DPolyPolygon aCandidate(rCandidate.areControlPointsUsed() ? tools::adaptiveSubdivideByAngle(rCandidate) : rCandidate);
447*cdf0e10cSrcweir 
448*cdf0e10cSrcweir 			if(1L == aCandidate.count())
449*cdf0e10cSrcweir 			{
450*cdf0e10cSrcweir 				// single polygon -> single polygon triangulation
451*cdf0e10cSrcweir 				const B2DPolygon aSinglePolygon(aCandidate.getB2DPolygon(0L));
452*cdf0e10cSrcweir 				aRetval = triangulate(aSinglePolygon);
453*cdf0e10cSrcweir 			}
454*cdf0e10cSrcweir 			else
455*cdf0e10cSrcweir 			{
456*cdf0e10cSrcweir 				Triangulator aTriangulator(aCandidate);
457*cdf0e10cSrcweir 				aRetval = aTriangulator.getResult();
458*cdf0e10cSrcweir 			}
459*cdf0e10cSrcweir 
460*cdf0e10cSrcweir 			return aRetval;
461*cdf0e10cSrcweir 		}
462*cdf0e10cSrcweir 	} // end of namespace triangulator
463*cdf0e10cSrcweir } // end of namespace basegfx
464*cdf0e10cSrcweir 
465*cdf0e10cSrcweir //////////////////////////////////////////////////////////////////////////////
466*cdf0e10cSrcweir // eof
467