189b56da7SAndrew Rist /**************************************************************
2cdf0e10cSrcweir *
389b56da7SAndrew Rist * Licensed to the Apache Software Foundation (ASF) under one
489b56da7SAndrew Rist * or more contributor license agreements. See the NOTICE file
589b56da7SAndrew Rist * distributed with this work for additional information
689b56da7SAndrew Rist * regarding copyright ownership. The ASF licenses this file
789b56da7SAndrew Rist * to you under the Apache License, Version 2.0 (the
889b56da7SAndrew Rist * "License"); you may not use this file except in compliance
989b56da7SAndrew Rist * with the License. You may obtain a copy of the License at
1089b56da7SAndrew Rist *
1189b56da7SAndrew Rist * http://www.apache.org/licenses/LICENSE-2.0
1289b56da7SAndrew Rist *
1389b56da7SAndrew Rist * Unless required by applicable law or agreed to in writing,
1489b56da7SAndrew Rist * software distributed under the License is distributed on an
1589b56da7SAndrew Rist * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
1689b56da7SAndrew Rist * KIND, either express or implied. See the License for the
1789b56da7SAndrew Rist * specific language governing permissions and limitations
1889b56da7SAndrew Rist * under the License.
1989b56da7SAndrew Rist *
2089b56da7SAndrew Rist *************************************************************/
2189b56da7SAndrew Rist
2289b56da7SAndrew Rist
23cdf0e10cSrcweir
24cdf0e10cSrcweir // MARKER(update_precomp.py): autogen include statement, do not remove
25cdf0e10cSrcweir #include "precompiled_tools.hxx"
26cdf0e10cSrcweir
27cdf0e10cSrcweir #define _SV_POLY_CXX
28cdf0e10cSrcweir #include <osl/endian.h>
29cdf0e10cSrcweir #include <tools/bigint.hxx>
30cdf0e10cSrcweir #include <tools/debug.hxx>
31cdf0e10cSrcweir #include <tools/stream.hxx>
32cdf0e10cSrcweir #include <tools/vcompat.hxx>
33cdf0e10cSrcweir #include <poly.h>
34cdf0e10cSrcweir #include <tools/line.hxx>
35cdf0e10cSrcweir #ifndef _VECTOR2D_H
36cdf0e10cSrcweir #include <tools/vector2d.hxx>
37cdf0e10cSrcweir #endif
38cdf0e10cSrcweir #ifndef _POLY_HXX
39cdf0e10cSrcweir #include <tools/poly.hxx>
40cdf0e10cSrcweir #endif
41cdf0e10cSrcweir #include <basegfx/polygon/b2dpolygon.hxx>
42cdf0e10cSrcweir #include <basegfx/point/b2dpoint.hxx>
43cdf0e10cSrcweir #include <basegfx/vector/b2dvector.hxx>
44cdf0e10cSrcweir #include <basegfx/polygon/b2dpolygontools.hxx>
45cdf0e10cSrcweir #include <basegfx/curve/b2dcubicbezier.hxx>
46cdf0e10cSrcweir
47cdf0e10cSrcweir #include <vector>
48cdf0e10cSrcweir #include <iterator>
49cdf0e10cSrcweir #include <algorithm>
50cdf0e10cSrcweir #include <cstring>
51cdf0e10cSrcweir #include <limits.h>
52cdf0e10cSrcweir #include <cmath>
53cdf0e10cSrcweir
54cdf0e10cSrcweir
55cdf0e10cSrcweir // =======================================================================
56cdf0e10cSrcweir
57cdf0e10cSrcweir DBG_NAME( Polygon )
58cdf0e10cSrcweir
59cdf0e10cSrcweir // -----------------------------------------------------------------------
60cdf0e10cSrcweir
61cdf0e10cSrcweir #define EDGE_LEFT 1
62cdf0e10cSrcweir #define EDGE_TOP 2
63cdf0e10cSrcweir #define EDGE_RIGHT 4
64cdf0e10cSrcweir #define EDGE_BOTTOM 8
65cdf0e10cSrcweir #define EDGE_HORZ (EDGE_RIGHT | EDGE_LEFT)
66cdf0e10cSrcweir #define EDGE_VERT (EDGE_TOP | EDGE_BOTTOM)
67cdf0e10cSrcweir #define SMALL_DVALUE 0.0000001
68cdf0e10cSrcweir #define FSQRT2 1.4142135623730950488016887242097
69cdf0e10cSrcweir
70cdf0e10cSrcweir // -----------------------------------------------------------------------
71cdf0e10cSrcweir
72cdf0e10cSrcweir static ImplPolygonData aStaticImplPolygon =
73cdf0e10cSrcweir {
74cdf0e10cSrcweir NULL, NULL, 0, 0
75cdf0e10cSrcweir };
76cdf0e10cSrcweir
77cdf0e10cSrcweir // =======================================================================
78cdf0e10cSrcweir
ImplPolygon(sal_uInt16 nInitSize,sal_Bool bFlags)79cdf0e10cSrcweir ImplPolygon::ImplPolygon( sal_uInt16 nInitSize, sal_Bool bFlags )
80cdf0e10cSrcweir {
81cdf0e10cSrcweir if ( nInitSize )
82cdf0e10cSrcweir {
83cdf0e10cSrcweir mpPointAry = (Point*)new char[(sal_uIntPtr)nInitSize*sizeof(Point)];
84cdf0e10cSrcweir memset( mpPointAry, 0, (sal_uIntPtr)nInitSize*sizeof(Point) );
85cdf0e10cSrcweir }
86cdf0e10cSrcweir else
87cdf0e10cSrcweir mpPointAry = NULL;
88cdf0e10cSrcweir
89cdf0e10cSrcweir if( bFlags )
90cdf0e10cSrcweir {
91cdf0e10cSrcweir mpFlagAry = new sal_uInt8[ nInitSize ];
92cdf0e10cSrcweir memset( mpPointAry, 0, nInitSize );
93cdf0e10cSrcweir }
94cdf0e10cSrcweir else
95cdf0e10cSrcweir mpFlagAry = NULL;
96cdf0e10cSrcweir
97cdf0e10cSrcweir mnRefCount = 1;
98cdf0e10cSrcweir mnPoints = nInitSize;
99cdf0e10cSrcweir }
100cdf0e10cSrcweir
101cdf0e10cSrcweir // -----------------------------------------------------------------------
102cdf0e10cSrcweir
ImplPolygon(const ImplPolygon & rImpPoly)103cdf0e10cSrcweir ImplPolygon::ImplPolygon( const ImplPolygon& rImpPoly )
104cdf0e10cSrcweir {
105cdf0e10cSrcweir if ( rImpPoly.mnPoints )
106cdf0e10cSrcweir {
107cdf0e10cSrcweir mpPointAry = (Point*)new char[(sal_uIntPtr)rImpPoly.mnPoints*sizeof(Point)];
108cdf0e10cSrcweir memcpy( mpPointAry, rImpPoly.mpPointAry, (sal_uIntPtr)rImpPoly.mnPoints*sizeof(Point) );
109cdf0e10cSrcweir
110cdf0e10cSrcweir if( rImpPoly.mpFlagAry )
111cdf0e10cSrcweir {
112cdf0e10cSrcweir mpFlagAry = new sal_uInt8[ rImpPoly.mnPoints ];
113cdf0e10cSrcweir memcpy( mpFlagAry, rImpPoly.mpFlagAry, rImpPoly.mnPoints );
114cdf0e10cSrcweir }
115cdf0e10cSrcweir else
116cdf0e10cSrcweir mpFlagAry = NULL;
117cdf0e10cSrcweir }
118cdf0e10cSrcweir else
119cdf0e10cSrcweir {
120cdf0e10cSrcweir mpPointAry = NULL;
121cdf0e10cSrcweir mpFlagAry = NULL;
122cdf0e10cSrcweir }
123cdf0e10cSrcweir
124cdf0e10cSrcweir mnRefCount = 1;
125cdf0e10cSrcweir mnPoints = rImpPoly.mnPoints;
126cdf0e10cSrcweir }
127cdf0e10cSrcweir
128cdf0e10cSrcweir // -----------------------------------------------------------------------
129cdf0e10cSrcweir
ImplPolygon(sal_uInt16 nInitSize,const Point * pInitAry,const sal_uInt8 * pInitFlags)130cdf0e10cSrcweir ImplPolygon::ImplPolygon( sal_uInt16 nInitSize, const Point* pInitAry, const sal_uInt8* pInitFlags )
131cdf0e10cSrcweir {
132cdf0e10cSrcweir if ( nInitSize )
133cdf0e10cSrcweir {
134cdf0e10cSrcweir mpPointAry = (Point*)new char[(sal_uIntPtr)nInitSize*sizeof(Point)];
135cdf0e10cSrcweir memcpy( mpPointAry, pInitAry, (sal_uIntPtr)nInitSize*sizeof( Point ) );
136cdf0e10cSrcweir
137cdf0e10cSrcweir if( pInitFlags )
138cdf0e10cSrcweir {
139cdf0e10cSrcweir mpFlagAry = new sal_uInt8[ nInitSize ];
140cdf0e10cSrcweir memcpy( mpFlagAry, pInitFlags, nInitSize );
141cdf0e10cSrcweir }
142cdf0e10cSrcweir else
143cdf0e10cSrcweir mpFlagAry = NULL;
144cdf0e10cSrcweir }
145cdf0e10cSrcweir else
146cdf0e10cSrcweir {
147cdf0e10cSrcweir mpPointAry = NULL;
148cdf0e10cSrcweir mpFlagAry = NULL;
149cdf0e10cSrcweir }
150cdf0e10cSrcweir
151cdf0e10cSrcweir mnRefCount = 1;
152cdf0e10cSrcweir mnPoints = nInitSize;
153cdf0e10cSrcweir }
154cdf0e10cSrcweir
155cdf0e10cSrcweir // -----------------------------------------------------------------------
156cdf0e10cSrcweir
~ImplPolygon()157cdf0e10cSrcweir ImplPolygon::~ImplPolygon()
158cdf0e10cSrcweir {
159cdf0e10cSrcweir if ( mpPointAry )
160cdf0e10cSrcweir {
161cdf0e10cSrcweir delete[] (char*) mpPointAry;
162cdf0e10cSrcweir }
163cdf0e10cSrcweir
164cdf0e10cSrcweir if( mpFlagAry )
165cdf0e10cSrcweir delete[] mpFlagAry;
166cdf0e10cSrcweir }
167cdf0e10cSrcweir
168cdf0e10cSrcweir // -----------------------------------------------------------------------
169cdf0e10cSrcweir
ImplSetSize(sal_uInt16 nNewSize,sal_Bool bResize)170cdf0e10cSrcweir void ImplPolygon::ImplSetSize( sal_uInt16 nNewSize, sal_Bool bResize )
171cdf0e10cSrcweir {
172cdf0e10cSrcweir if( mnPoints == nNewSize )
173cdf0e10cSrcweir return;
174cdf0e10cSrcweir
175cdf0e10cSrcweir Point* pNewAry;
176cdf0e10cSrcweir
177cdf0e10cSrcweir if ( nNewSize )
178cdf0e10cSrcweir {
179cdf0e10cSrcweir pNewAry = (Point*)new char[(sal_uIntPtr)nNewSize*sizeof(Point)];
180cdf0e10cSrcweir
181cdf0e10cSrcweir if ( bResize )
182cdf0e10cSrcweir {
183cdf0e10cSrcweir // Alte Punkte kopieren
184cdf0e10cSrcweir if ( mnPoints < nNewSize )
185cdf0e10cSrcweir {
186cdf0e10cSrcweir // Neue Punkte mit 0 initialisieren
187cdf0e10cSrcweir memset( pNewAry+mnPoints, 0, (sal_uIntPtr)(nNewSize-mnPoints)*sizeof(Point) );
188cdf0e10cSrcweir if ( mpPointAry )
189cdf0e10cSrcweir memcpy( pNewAry, mpPointAry, mnPoints*sizeof(Point) );
190cdf0e10cSrcweir }
191cdf0e10cSrcweir else
192cdf0e10cSrcweir {
193cdf0e10cSrcweir if ( mpPointAry )
194cdf0e10cSrcweir memcpy( pNewAry, mpPointAry, (sal_uIntPtr)nNewSize*sizeof(Point) );
195cdf0e10cSrcweir }
196cdf0e10cSrcweir }
197cdf0e10cSrcweir }
198cdf0e10cSrcweir else
199cdf0e10cSrcweir pNewAry = NULL;
200cdf0e10cSrcweir
201cdf0e10cSrcweir if ( mpPointAry )
202cdf0e10cSrcweir delete[] (char*) mpPointAry;
203cdf0e10cSrcweir
204cdf0e10cSrcweir // ggf. FlagArray beruecksichtigen
205cdf0e10cSrcweir if( mpFlagAry )
206cdf0e10cSrcweir {
207cdf0e10cSrcweir sal_uInt8* pNewFlagAry;
208cdf0e10cSrcweir
209cdf0e10cSrcweir if( nNewSize )
210cdf0e10cSrcweir {
211cdf0e10cSrcweir pNewFlagAry = new sal_uInt8[ nNewSize ];
212cdf0e10cSrcweir
213cdf0e10cSrcweir if( bResize )
214cdf0e10cSrcweir {
215cdf0e10cSrcweir // Alte Flags kopieren
216cdf0e10cSrcweir if ( mnPoints < nNewSize )
217cdf0e10cSrcweir {
218cdf0e10cSrcweir // Neue Punkte mit 0 initialisieren
219cdf0e10cSrcweir memset( pNewFlagAry+mnPoints, 0, nNewSize-mnPoints );
220cdf0e10cSrcweir memcpy( pNewFlagAry, mpFlagAry, mnPoints );
221cdf0e10cSrcweir }
222cdf0e10cSrcweir else
223cdf0e10cSrcweir memcpy( pNewFlagAry, mpFlagAry, nNewSize );
224cdf0e10cSrcweir }
225cdf0e10cSrcweir }
226cdf0e10cSrcweir else
227cdf0e10cSrcweir pNewFlagAry = NULL;
228cdf0e10cSrcweir
229cdf0e10cSrcweir delete[] mpFlagAry;
230cdf0e10cSrcweir mpFlagAry = pNewFlagAry;
231cdf0e10cSrcweir }
232cdf0e10cSrcweir
233cdf0e10cSrcweir mpPointAry = pNewAry;
234cdf0e10cSrcweir mnPoints = nNewSize;
235cdf0e10cSrcweir }
236cdf0e10cSrcweir
237cdf0e10cSrcweir // -----------------------------------------------------------------------
238cdf0e10cSrcweir
ImplSplit(sal_uInt16 nPos,sal_uInt16 nSpace,ImplPolygon * pInitPoly)239cdf0e10cSrcweir void ImplPolygon::ImplSplit( sal_uInt16 nPos, sal_uInt16 nSpace, ImplPolygon* pInitPoly )
240cdf0e10cSrcweir {
241cdf0e10cSrcweir const sal_uIntPtr nSpaceSize = nSpace * sizeof( Point );
242cdf0e10cSrcweir
243cdf0e10cSrcweir //Can't fit this in :-(, throw ?
244cdf0e10cSrcweir if (mnPoints + nSpace > USHRT_MAX)
245cdf0e10cSrcweir return;
246cdf0e10cSrcweir
247cdf0e10cSrcweir const sal_uInt16 nNewSize = mnPoints + nSpace;
248cdf0e10cSrcweir
249cdf0e10cSrcweir if( nPos >= mnPoints )
250cdf0e10cSrcweir {
251cdf0e10cSrcweir // Hinten anhaengen
252cdf0e10cSrcweir nPos = mnPoints;
253cdf0e10cSrcweir ImplSetSize( nNewSize, sal_True );
254cdf0e10cSrcweir
255cdf0e10cSrcweir if( pInitPoly )
256cdf0e10cSrcweir {
257cdf0e10cSrcweir memcpy( mpPointAry + nPos, pInitPoly->mpPointAry, nSpaceSize );
258cdf0e10cSrcweir
259cdf0e10cSrcweir if( pInitPoly->mpFlagAry )
260cdf0e10cSrcweir memcpy( mpFlagAry + nPos, pInitPoly->mpFlagAry, nSpace );
261cdf0e10cSrcweir }
262cdf0e10cSrcweir }
263cdf0e10cSrcweir else
264cdf0e10cSrcweir {
265cdf0e10cSrcweir // PointArray ist in diesem Zweig immer vorhanden
266cdf0e10cSrcweir const sal_uInt16 nSecPos = nPos + nSpace;
267cdf0e10cSrcweir const sal_uInt16 nRest = mnPoints - nPos;
268cdf0e10cSrcweir
269cdf0e10cSrcweir Point* pNewAry = (Point*) new char[ (sal_uIntPtr) nNewSize * sizeof( Point ) ];
270cdf0e10cSrcweir
271cdf0e10cSrcweir memcpy( pNewAry, mpPointAry, nPos * sizeof( Point ) );
272cdf0e10cSrcweir
273cdf0e10cSrcweir if( pInitPoly )
274cdf0e10cSrcweir memcpy( pNewAry + nPos, pInitPoly->mpPointAry, nSpaceSize );
275cdf0e10cSrcweir else
276cdf0e10cSrcweir memset( pNewAry + nPos, 0, nSpaceSize );
277cdf0e10cSrcweir
278cdf0e10cSrcweir memcpy( pNewAry + nSecPos, mpPointAry + nPos, nRest * sizeof( Point ) );
279cdf0e10cSrcweir delete[] (char*) mpPointAry;
280cdf0e10cSrcweir
281cdf0e10cSrcweir // ggf. FlagArray beruecksichtigen
282cdf0e10cSrcweir if( mpFlagAry )
283cdf0e10cSrcweir {
284cdf0e10cSrcweir sal_uInt8* pNewFlagAry = new sal_uInt8[ nNewSize ];
285cdf0e10cSrcweir
286cdf0e10cSrcweir memcpy( pNewFlagAry, mpFlagAry, nPos );
287cdf0e10cSrcweir
288cdf0e10cSrcweir if( pInitPoly && pInitPoly->mpFlagAry )
289cdf0e10cSrcweir memcpy( pNewFlagAry + nPos, pInitPoly->mpFlagAry, nSpace );
290cdf0e10cSrcweir else
291cdf0e10cSrcweir memset( pNewFlagAry + nPos, 0, nSpace );
292cdf0e10cSrcweir
293cdf0e10cSrcweir memcpy( pNewFlagAry + nSecPos, mpFlagAry + nPos, nRest );
294cdf0e10cSrcweir delete[] mpFlagAry;
295cdf0e10cSrcweir mpFlagAry = pNewFlagAry;
296cdf0e10cSrcweir }
297cdf0e10cSrcweir
298cdf0e10cSrcweir mpPointAry = pNewAry;
299cdf0e10cSrcweir mnPoints = nNewSize;
300cdf0e10cSrcweir }
301cdf0e10cSrcweir }
302cdf0e10cSrcweir
303cdf0e10cSrcweir // -----------------------------------------------------------------------
304cdf0e10cSrcweir
ImplRemove(sal_uInt16 nPos,sal_uInt16 nCount)305cdf0e10cSrcweir void ImplPolygon::ImplRemove( sal_uInt16 nPos, sal_uInt16 nCount )
306cdf0e10cSrcweir {
307cdf0e10cSrcweir const sal_uInt16 nRemoveCount = Min( (sal_uInt16) ( mnPoints - nPos ), (sal_uInt16) nCount );
308cdf0e10cSrcweir
309cdf0e10cSrcweir if( nRemoveCount )
310cdf0e10cSrcweir {
311cdf0e10cSrcweir const sal_uInt16 nNewSize = mnPoints - nRemoveCount;
312cdf0e10cSrcweir const sal_uInt16 nSecPos = nPos + nRemoveCount;
313cdf0e10cSrcweir const sal_uInt16 nRest = mnPoints - nSecPos;
314cdf0e10cSrcweir
315cdf0e10cSrcweir Point* pNewAry = (Point*) new char[ (sal_uIntPtr) nNewSize * sizeof( Point ) ];
316cdf0e10cSrcweir
317cdf0e10cSrcweir memcpy( pNewAry, mpPointAry, nPos * sizeof( Point ) );
318cdf0e10cSrcweir memcpy( pNewAry + nPos, mpPointAry + nSecPos, nRest * sizeof( Point ) );
319cdf0e10cSrcweir
320cdf0e10cSrcweir delete[] (char*) mpPointAry;
321cdf0e10cSrcweir
322cdf0e10cSrcweir // ggf. FlagArray beruecksichtigen
323cdf0e10cSrcweir if( mpFlagAry )
324cdf0e10cSrcweir {
325cdf0e10cSrcweir sal_uInt8* pNewFlagAry = new sal_uInt8[ nNewSize ];
326cdf0e10cSrcweir
327cdf0e10cSrcweir memcpy( pNewFlagAry, mpFlagAry, nPos );
328cdf0e10cSrcweir memcpy( pNewFlagAry + nPos, mpFlagAry + nSecPos, nRest );
329cdf0e10cSrcweir delete[] mpFlagAry;
330cdf0e10cSrcweir mpFlagAry = pNewFlagAry;
331cdf0e10cSrcweir }
332cdf0e10cSrcweir
333cdf0e10cSrcweir mpPointAry = pNewAry;
334cdf0e10cSrcweir mnPoints = nNewSize;
335cdf0e10cSrcweir }
336cdf0e10cSrcweir }
337cdf0e10cSrcweir
338cdf0e10cSrcweir // -----------------------------------------------------------------------
339cdf0e10cSrcweir
ImplCreateFlagArray()340cdf0e10cSrcweir void ImplPolygon::ImplCreateFlagArray()
341cdf0e10cSrcweir {
342cdf0e10cSrcweir if( !mpFlagAry )
343cdf0e10cSrcweir {
344cdf0e10cSrcweir mpFlagAry = new sal_uInt8[ mnPoints ];
345cdf0e10cSrcweir memset( mpFlagAry, 0, mnPoints );
346cdf0e10cSrcweir }
347cdf0e10cSrcweir }
348cdf0e10cSrcweir
349cdf0e10cSrcweir // =======================================================================
350cdf0e10cSrcweir
ImplMakeUnique()351cdf0e10cSrcweir inline void Polygon::ImplMakeUnique()
352cdf0e10cSrcweir {
353cdf0e10cSrcweir // Falls noch andere Referenzen bestehen, dann kopieren
354cdf0e10cSrcweir if ( mpImplPolygon->mnRefCount != 1 )
355cdf0e10cSrcweir {
356cdf0e10cSrcweir if ( mpImplPolygon->mnRefCount )
357cdf0e10cSrcweir mpImplPolygon->mnRefCount--;
358cdf0e10cSrcweir mpImplPolygon = new ImplPolygon( *mpImplPolygon );
359cdf0e10cSrcweir }
360cdf0e10cSrcweir }
361cdf0e10cSrcweir
362cdf0e10cSrcweir // -----------------------------------------------------------------------
363cdf0e10cSrcweir
ImplGetAngle(const Point & rCenter,const Point & rPt)364cdf0e10cSrcweir inline double ImplGetAngle( const Point& rCenter, const Point& rPt )
365cdf0e10cSrcweir {
366cdf0e10cSrcweir const long nDX = rPt.X() - rCenter.X();
367cdf0e10cSrcweir return( atan2( -rPt.Y() + rCenter.Y(), ( ( nDX == 0L ) ? 0.000000001 : nDX ) ) );
368cdf0e10cSrcweir }
369cdf0e10cSrcweir
370cdf0e10cSrcweir // -----------------------------------------------------------------------
371cdf0e10cSrcweir
Polygon()372cdf0e10cSrcweir Polygon::Polygon()
373cdf0e10cSrcweir {
374cdf0e10cSrcweir DBG_CTOR( Polygon, NULL );
375cdf0e10cSrcweir mpImplPolygon = (ImplPolygon*)(&aStaticImplPolygon);
376cdf0e10cSrcweir }
377cdf0e10cSrcweir
378cdf0e10cSrcweir // -----------------------------------------------------------------------
379cdf0e10cSrcweir
Polygon(sal_uInt16 nSize)380cdf0e10cSrcweir Polygon::Polygon( sal_uInt16 nSize )
381cdf0e10cSrcweir {
382cdf0e10cSrcweir DBG_CTOR( Polygon, NULL );
383cdf0e10cSrcweir
384cdf0e10cSrcweir if ( nSize )
385cdf0e10cSrcweir mpImplPolygon = new ImplPolygon( nSize );
386cdf0e10cSrcweir else
387cdf0e10cSrcweir mpImplPolygon = (ImplPolygon*)(&aStaticImplPolygon);
388cdf0e10cSrcweir }
389cdf0e10cSrcweir
390cdf0e10cSrcweir // -----------------------------------------------------------------------
391cdf0e10cSrcweir
Polygon(sal_uInt16 nPoints,const Point * pPtAry,const sal_uInt8 * pFlagAry)392cdf0e10cSrcweir Polygon::Polygon( sal_uInt16 nPoints, const Point* pPtAry, const sal_uInt8* pFlagAry )
393cdf0e10cSrcweir {
394cdf0e10cSrcweir DBG_CTOR( Polygon, NULL );
395cdf0e10cSrcweir
396cdf0e10cSrcweir if( nPoints )
397cdf0e10cSrcweir mpImplPolygon = new ImplPolygon( nPoints, pPtAry, pFlagAry );
398cdf0e10cSrcweir else
399cdf0e10cSrcweir mpImplPolygon = (ImplPolygon*)(&aStaticImplPolygon);
400cdf0e10cSrcweir }
401cdf0e10cSrcweir
402cdf0e10cSrcweir // -----------------------------------------------------------------------
403cdf0e10cSrcweir
Polygon(const Polygon & rPoly)404cdf0e10cSrcweir Polygon::Polygon( const Polygon& rPoly )
405cdf0e10cSrcweir {
406cdf0e10cSrcweir DBG_CTOR( Polygon, NULL );
407cdf0e10cSrcweir DBG_CHKOBJ( &rPoly, Polygon, NULL );
408cdf0e10cSrcweir DBG_ASSERT( rPoly.mpImplPolygon->mnRefCount < 0xFFFFFFFE, "Polygon: RefCount overflow" );
409cdf0e10cSrcweir
410cdf0e10cSrcweir mpImplPolygon = rPoly.mpImplPolygon;
411cdf0e10cSrcweir if ( mpImplPolygon->mnRefCount )
412cdf0e10cSrcweir mpImplPolygon->mnRefCount++;
413cdf0e10cSrcweir }
414cdf0e10cSrcweir
415cdf0e10cSrcweir // -----------------------------------------------------------------------
416cdf0e10cSrcweir
Polygon(const Rectangle & rRect)417cdf0e10cSrcweir Polygon::Polygon( const Rectangle& rRect )
418cdf0e10cSrcweir {
419cdf0e10cSrcweir DBG_CTOR( Polygon, NULL );
420cdf0e10cSrcweir
421cdf0e10cSrcweir if ( rRect.IsEmpty() )
422cdf0e10cSrcweir mpImplPolygon = (ImplPolygon*)(&aStaticImplPolygon);
423cdf0e10cSrcweir else
424cdf0e10cSrcweir {
425cdf0e10cSrcweir mpImplPolygon = new ImplPolygon( 5 );
426cdf0e10cSrcweir mpImplPolygon->mpPointAry[0] = rRect.TopLeft();
427cdf0e10cSrcweir mpImplPolygon->mpPointAry[1] = rRect.TopRight();
428cdf0e10cSrcweir mpImplPolygon->mpPointAry[2] = rRect.BottomRight();
429cdf0e10cSrcweir mpImplPolygon->mpPointAry[3] = rRect.BottomLeft();
430cdf0e10cSrcweir mpImplPolygon->mpPointAry[4] = rRect.TopLeft();
431cdf0e10cSrcweir }
432cdf0e10cSrcweir }
433cdf0e10cSrcweir
434cdf0e10cSrcweir // -----------------------------------------------------------------------
435cdf0e10cSrcweir
Polygon(const Rectangle & rRect,sal_uIntPtr nHorzRound,sal_uIntPtr nVertRound)436cdf0e10cSrcweir Polygon::Polygon( const Rectangle& rRect, sal_uIntPtr nHorzRound, sal_uIntPtr nVertRound )
437cdf0e10cSrcweir {
438cdf0e10cSrcweir DBG_CTOR( Polygon, NULL );
439cdf0e10cSrcweir
440cdf0e10cSrcweir if ( rRect.IsEmpty() )
441cdf0e10cSrcweir mpImplPolygon = (ImplPolygon*)(&aStaticImplPolygon);
442cdf0e10cSrcweir else
443cdf0e10cSrcweir {
444cdf0e10cSrcweir Rectangle aRect( rRect );
445cdf0e10cSrcweir aRect.Justify(); // SJ: i9140
446cdf0e10cSrcweir
447cdf0e10cSrcweir nHorzRound = Min( nHorzRound, (sal_uIntPtr) labs( aRect.GetWidth() >> 1 ) );
448cdf0e10cSrcweir nVertRound = Min( nVertRound, (sal_uIntPtr) labs( aRect.GetHeight() >> 1 ) );
449cdf0e10cSrcweir
450cdf0e10cSrcweir if( !nHorzRound && !nVertRound )
451cdf0e10cSrcweir {
452cdf0e10cSrcweir mpImplPolygon = new ImplPolygon( 5 );
453cdf0e10cSrcweir mpImplPolygon->mpPointAry[0] = aRect.TopLeft();
454cdf0e10cSrcweir mpImplPolygon->mpPointAry[1] = aRect.TopRight();
455cdf0e10cSrcweir mpImplPolygon->mpPointAry[2] = aRect.BottomRight();
456cdf0e10cSrcweir mpImplPolygon->mpPointAry[3] = aRect.BottomLeft();
457cdf0e10cSrcweir mpImplPolygon->mpPointAry[4] = aRect.TopLeft();
458cdf0e10cSrcweir }
459cdf0e10cSrcweir else
460cdf0e10cSrcweir {
461cdf0e10cSrcweir const Point aTL( aRect.Left() + nHorzRound, aRect.Top() + nVertRound );
462cdf0e10cSrcweir const Point aTR( aRect.Right() - nHorzRound, aRect.Top() + nVertRound );
463cdf0e10cSrcweir const Point aBR( aRect.Right() - nHorzRound, aRect.Bottom() - nVertRound );
464cdf0e10cSrcweir const Point aBL( aRect.Left() + nHorzRound, aRect.Bottom() - nVertRound );
465cdf0e10cSrcweir Polygon* pEllipsePoly = new Polygon( Point(), nHorzRound, nVertRound );
466cdf0e10cSrcweir sal_uInt16 i, nEnd, nSize4 = pEllipsePoly->GetSize() >> 2;
467cdf0e10cSrcweir
468cdf0e10cSrcweir mpImplPolygon = new ImplPolygon( pEllipsePoly->GetSize() + 1 );
469cdf0e10cSrcweir
470cdf0e10cSrcweir const Point* pSrcAry = pEllipsePoly->GetConstPointAry();
471cdf0e10cSrcweir Point* pDstAry = mpImplPolygon->mpPointAry;
472cdf0e10cSrcweir
473cdf0e10cSrcweir for( i = 0, nEnd = nSize4; i < nEnd; i++ )
474cdf0e10cSrcweir ( pDstAry[ i ] = pSrcAry[ i ] ) += aTR;
475cdf0e10cSrcweir
476cdf0e10cSrcweir for( nEnd = nEnd + nSize4; i < nEnd; i++ )
477cdf0e10cSrcweir ( pDstAry[ i ] = pSrcAry[ i ] ) += aTL;
478cdf0e10cSrcweir
479cdf0e10cSrcweir for( nEnd = nEnd + nSize4; i < nEnd; i++ )
480cdf0e10cSrcweir ( pDstAry[ i ] = pSrcAry[ i ] ) += aBL;
481cdf0e10cSrcweir
482cdf0e10cSrcweir for( nEnd = nEnd + nSize4; i < nEnd; i++ )
483cdf0e10cSrcweir ( pDstAry[ i ] = pSrcAry[ i ] ) += aBR;
484cdf0e10cSrcweir
485cdf0e10cSrcweir pDstAry[ nEnd ] = pDstAry[ 0 ];
486cdf0e10cSrcweir delete pEllipsePoly;
487cdf0e10cSrcweir }
488cdf0e10cSrcweir }
489cdf0e10cSrcweir }
490cdf0e10cSrcweir
491cdf0e10cSrcweir // -----------------------------------------------------------------------
492cdf0e10cSrcweir
Polygon(const Point & rCenter,long nRadX,long nRadY,sal_uInt16 nPoints)493cdf0e10cSrcweir Polygon::Polygon( const Point& rCenter, long nRadX, long nRadY, sal_uInt16 nPoints )
494cdf0e10cSrcweir {
495cdf0e10cSrcweir DBG_CTOR( Polygon, NULL );
496cdf0e10cSrcweir
497cdf0e10cSrcweir if( nRadX && nRadY )
498cdf0e10cSrcweir {
499cdf0e10cSrcweir // Default berechnen (abhaengig von Groesse)
500cdf0e10cSrcweir if( !nPoints )
501cdf0e10cSrcweir {
502cdf0e10cSrcweir nPoints = (sal_uInt16) ( F_PI * ( 1.5 * ( nRadX + nRadY ) -
503cdf0e10cSrcweir sqrt( (double) labs( nRadX * nRadY ) ) ) );
504cdf0e10cSrcweir
505cdf0e10cSrcweir nPoints = (sal_uInt16) MinMax( nPoints, 32, 256 );
506cdf0e10cSrcweir
507cdf0e10cSrcweir if( ( nRadX > 32 ) && ( nRadY > 32 ) && ( nRadX + nRadY ) < 8192 )
508cdf0e10cSrcweir nPoints >>= 1;
509cdf0e10cSrcweir }
510cdf0e10cSrcweir
511cdf0e10cSrcweir // Anzahl der Punkte auf durch 4 teilbare Zahl aufrunden
512cdf0e10cSrcweir mpImplPolygon = new ImplPolygon( nPoints = (nPoints + 3) & ~3 );
513cdf0e10cSrcweir
514cdf0e10cSrcweir Point* pPt;
515cdf0e10cSrcweir sal_uInt16 i;
516cdf0e10cSrcweir sal_uInt16 nPoints2 = nPoints >> 1;
517cdf0e10cSrcweir sal_uInt16 nPoints4 = nPoints >> 2;
518cdf0e10cSrcweir double nAngle;
519cdf0e10cSrcweir double nAngleStep = F_PI2 / ( nPoints4 - 1 );
520cdf0e10cSrcweir
521cdf0e10cSrcweir for( i=0, nAngle = 0.0; i < nPoints4; i++, nAngle += nAngleStep )
522cdf0e10cSrcweir {
523cdf0e10cSrcweir long nX = FRound( nRadX * cos( nAngle ) );
524cdf0e10cSrcweir long nY = FRound( -nRadY * sin( nAngle ) );
525cdf0e10cSrcweir
526cdf0e10cSrcweir pPt = &(mpImplPolygon->mpPointAry[i]);
527cdf0e10cSrcweir pPt->X() = nX + rCenter.X();
528cdf0e10cSrcweir pPt->Y() = nY + rCenter.Y();
529cdf0e10cSrcweir pPt = &(mpImplPolygon->mpPointAry[nPoints2-i-1]);
530cdf0e10cSrcweir pPt->X() = -nX + rCenter.X();
531cdf0e10cSrcweir pPt->Y() = nY + rCenter.Y();
532cdf0e10cSrcweir pPt = &(mpImplPolygon->mpPointAry[i+nPoints2]);
533cdf0e10cSrcweir pPt->X() = -nX + rCenter.X();
534cdf0e10cSrcweir pPt->Y() = -nY + rCenter.Y();
535cdf0e10cSrcweir pPt = &(mpImplPolygon->mpPointAry[nPoints-i-1]);
536cdf0e10cSrcweir pPt->X() = nX + rCenter.X();
537cdf0e10cSrcweir pPt->Y() = -nY + rCenter.Y();
538cdf0e10cSrcweir }
539cdf0e10cSrcweir }
540cdf0e10cSrcweir else
541cdf0e10cSrcweir mpImplPolygon = (ImplPolygon*)(&aStaticImplPolygon);
542cdf0e10cSrcweir }
543cdf0e10cSrcweir
544cdf0e10cSrcweir // -----------------------------------------------------------------------
545cdf0e10cSrcweir
Polygon(const Rectangle & rBound,const Point & rStart,const Point & rEnd,PolyStyle eStyle)546cdf0e10cSrcweir Polygon::Polygon( const Rectangle& rBound,
547cdf0e10cSrcweir const Point& rStart, const Point& rEnd, PolyStyle eStyle )
548cdf0e10cSrcweir {
549cdf0e10cSrcweir DBG_CTOR( Polygon, NULL );
550cdf0e10cSrcweir
551cdf0e10cSrcweir const long nWidth = rBound.GetWidth();
552cdf0e10cSrcweir const long nHeight = rBound.GetHeight();
553cdf0e10cSrcweir
554cdf0e10cSrcweir if( ( nWidth > 1 ) && ( nHeight > 1 ) )
555cdf0e10cSrcweir {
556cdf0e10cSrcweir const Point aCenter( rBound.Center() );
557cdf0e10cSrcweir const long nRadX = aCenter.X() - rBound.Left();
558cdf0e10cSrcweir const long nRadY = aCenter.Y() - rBound.Top();
559cdf0e10cSrcweir sal_uInt16 nPoints;
560cdf0e10cSrcweir
561cdf0e10cSrcweir nPoints = (sal_uInt16) ( F_PI * ( 1.5 * ( nRadX + nRadY ) -
562cdf0e10cSrcweir sqrt( (double) labs( nRadX * nRadY ) ) ) );
563cdf0e10cSrcweir
564cdf0e10cSrcweir nPoints = (sal_uInt16) MinMax( nPoints, 32, 256 );
565cdf0e10cSrcweir
566cdf0e10cSrcweir if( ( nRadX > 32 ) && ( nRadY > 32 ) && ( nRadX + nRadY ) < 8192 )
567cdf0e10cSrcweir nPoints >>= 1;
568cdf0e10cSrcweir
569cdf0e10cSrcweir // Winkel berechnen
570cdf0e10cSrcweir const double fRadX = nRadX;
571cdf0e10cSrcweir const double fRadY = nRadY;
572cdf0e10cSrcweir const double fCenterX = aCenter.X();
573cdf0e10cSrcweir const double fCenterY = aCenter.Y();
574cdf0e10cSrcweir double fStart = ImplGetAngle( aCenter, rStart );
575cdf0e10cSrcweir double fEnd = ImplGetAngle( aCenter, rEnd );
576cdf0e10cSrcweir double fDiff = fEnd - fStart;
577cdf0e10cSrcweir double fStep;
578cdf0e10cSrcweir sal_uInt16 nStart;
579cdf0e10cSrcweir sal_uInt16 nEnd;
580cdf0e10cSrcweir
581cdf0e10cSrcweir if( fDiff < 0. )
582cdf0e10cSrcweir fDiff += F_2PI;
583cdf0e10cSrcweir
584cdf0e10cSrcweir // Punktanzahl proportional verkleinern ( fDiff / (2PI) );
585cdf0e10cSrcweir // ist eingentlich nur fuer einen Kreis richtig; wir
586cdf0e10cSrcweir // machen es hier aber trotzdem
587cdf0e10cSrcweir nPoints = Max( (sal_uInt16) ( ( fDiff * 0.1591549 ) * nPoints ), (sal_uInt16) 16 );
588cdf0e10cSrcweir fStep = fDiff / ( nPoints - 1 );
589cdf0e10cSrcweir
590cdf0e10cSrcweir if( POLY_PIE == eStyle )
591cdf0e10cSrcweir {
592cdf0e10cSrcweir const Point aCenter2( FRound( fCenterX ), FRound( fCenterY ) );
593cdf0e10cSrcweir
594cdf0e10cSrcweir nStart = 1;
595cdf0e10cSrcweir nEnd = nPoints + 1;
596cdf0e10cSrcweir mpImplPolygon = new ImplPolygon( nPoints + 2 );
597cdf0e10cSrcweir mpImplPolygon->mpPointAry[ 0 ] = aCenter2;
598cdf0e10cSrcweir mpImplPolygon->mpPointAry[ nEnd ] = aCenter2;
599cdf0e10cSrcweir }
600cdf0e10cSrcweir else
601cdf0e10cSrcweir {
602cdf0e10cSrcweir mpImplPolygon = new ImplPolygon( ( POLY_CHORD == eStyle ) ? ( nPoints + 1 ) : nPoints );
603cdf0e10cSrcweir nStart = 0;
604cdf0e10cSrcweir nEnd = nPoints;
605cdf0e10cSrcweir }
606cdf0e10cSrcweir
607cdf0e10cSrcweir for(; nStart < nEnd; nStart++, fStart += fStep )
608cdf0e10cSrcweir {
609cdf0e10cSrcweir Point& rPt = mpImplPolygon->mpPointAry[ nStart ];
610cdf0e10cSrcweir
611cdf0e10cSrcweir rPt.X() = FRound( fCenterX + fRadX * cos( fStart ) );
612cdf0e10cSrcweir rPt.Y() = FRound( fCenterY - fRadY * sin( fStart ) );
613cdf0e10cSrcweir }
614cdf0e10cSrcweir
615cdf0e10cSrcweir if( POLY_CHORD == eStyle )
616cdf0e10cSrcweir mpImplPolygon->mpPointAry[ nPoints ] = mpImplPolygon->mpPointAry[ 0 ];
617cdf0e10cSrcweir }
618cdf0e10cSrcweir else
619cdf0e10cSrcweir mpImplPolygon = (ImplPolygon*) &aStaticImplPolygon;
620cdf0e10cSrcweir }
621cdf0e10cSrcweir
622cdf0e10cSrcweir // -----------------------------------------------------------------------
623cdf0e10cSrcweir
Polygon(const Point & rBezPt1,const Point & rCtrlPt1,const Point & rBezPt2,const Point & rCtrlPt2,sal_uInt16 nPoints)624cdf0e10cSrcweir Polygon::Polygon( const Point& rBezPt1, const Point& rCtrlPt1,
625cdf0e10cSrcweir const Point& rBezPt2, const Point& rCtrlPt2,
626cdf0e10cSrcweir sal_uInt16 nPoints )
627cdf0e10cSrcweir {
628cdf0e10cSrcweir DBG_CTOR( Polygon, NULL );
629cdf0e10cSrcweir
630cdf0e10cSrcweir nPoints = ( 0 == nPoints ) ? 25 : ( ( nPoints < 2 ) ? 2 : nPoints );
631cdf0e10cSrcweir
632cdf0e10cSrcweir const double fInc = 1.0 / ( nPoints - 1 );
633cdf0e10cSrcweir double fK_1 = 0.0, fK1_1 = 1.0;
634cdf0e10cSrcweir double fK_2, fK_3, fK1_2, fK1_3, fK12, fK21;
635cdf0e10cSrcweir const double fX0 = rBezPt1.X();
636cdf0e10cSrcweir const double fY0 = rBezPt1.Y();
637cdf0e10cSrcweir const double fX1 = 3.0 * rCtrlPt1.X();
638cdf0e10cSrcweir const double fY1 = 3.0 * rCtrlPt1.Y();
639cdf0e10cSrcweir const double fX2 = 3.0 * rCtrlPt2.X();;
640cdf0e10cSrcweir const double fY2 = 3.0 * rCtrlPt2.Y();;
641cdf0e10cSrcweir const double fX3 = rBezPt2.X();
642cdf0e10cSrcweir const double fY3 = rBezPt2.Y();
643cdf0e10cSrcweir
644cdf0e10cSrcweir mpImplPolygon = new ImplPolygon( nPoints );
645cdf0e10cSrcweir
646cdf0e10cSrcweir for( sal_uInt16 i = 0; i < nPoints; i++, fK_1 += fInc, fK1_1 -= fInc )
647cdf0e10cSrcweir {
648cdf0e10cSrcweir Point& rPt = mpImplPolygon->mpPointAry[ i ];
649cdf0e10cSrcweir
650cdf0e10cSrcweir fK_2 = fK_1, fK_3 = ( fK_2 *= fK_1 ), fK_3 *= fK_1;
651cdf0e10cSrcweir fK1_2 = fK1_1, fK1_3 = ( fK1_2 *= fK1_1 ), fK1_3 *= fK1_1;
652cdf0e10cSrcweir fK12 = fK_1 * fK1_2, fK21 = fK_2 * fK1_1;
653cdf0e10cSrcweir
654cdf0e10cSrcweir rPt.X() = FRound( fK1_3 * fX0 + fK12 * fX1 + fK21 * fX2 + fK_3 * fX3 );
655cdf0e10cSrcweir rPt.Y() = FRound( fK1_3 * fY0 + fK12 * fY1 + fK21 * fY2 + fK_3 * fY3 );
656cdf0e10cSrcweir }
657cdf0e10cSrcweir }
658cdf0e10cSrcweir
659cdf0e10cSrcweir // -----------------------------------------------------------------------
660cdf0e10cSrcweir
~Polygon()661cdf0e10cSrcweir Polygon::~Polygon()
662cdf0e10cSrcweir {
663cdf0e10cSrcweir DBG_DTOR( Polygon, NULL );
664cdf0e10cSrcweir
665cdf0e10cSrcweir // Wenn es keine statischen ImpDaten sind, dann loeschen, wenn es
666cdf0e10cSrcweir // die letzte Referenz ist, sonst Referenzcounter decrementieren
667cdf0e10cSrcweir if ( mpImplPolygon->mnRefCount )
668cdf0e10cSrcweir {
669cdf0e10cSrcweir if ( mpImplPolygon->mnRefCount > 1 )
670cdf0e10cSrcweir mpImplPolygon->mnRefCount--;
671cdf0e10cSrcweir else
672cdf0e10cSrcweir delete mpImplPolygon;
673cdf0e10cSrcweir }
674cdf0e10cSrcweir }
675cdf0e10cSrcweir
676cdf0e10cSrcweir // -----------------------------------------------------------------------
677cdf0e10cSrcweir
ImplGetPointAry()678cdf0e10cSrcweir Point* Polygon::ImplGetPointAry()
679cdf0e10cSrcweir {
680cdf0e10cSrcweir DBG_CHKTHIS( Polygon, NULL );
681cdf0e10cSrcweir
682cdf0e10cSrcweir ImplMakeUnique();
683cdf0e10cSrcweir return (Point*)mpImplPolygon->mpPointAry;
684cdf0e10cSrcweir }
685cdf0e10cSrcweir
686cdf0e10cSrcweir // -----------------------------------------------------------------------
687cdf0e10cSrcweir
ImplGetFlagAry()688cdf0e10cSrcweir sal_uInt8* Polygon::ImplGetFlagAry()
689cdf0e10cSrcweir {
690cdf0e10cSrcweir DBG_CHKTHIS( Polygon, NULL );
691cdf0e10cSrcweir
692cdf0e10cSrcweir ImplMakeUnique();
693cdf0e10cSrcweir mpImplPolygon->ImplCreateFlagArray();
694cdf0e10cSrcweir return mpImplPolygon->mpFlagAry;
695cdf0e10cSrcweir }
696cdf0e10cSrcweir
697cdf0e10cSrcweir // -----------------------------------------------------------------------
698cdf0e10cSrcweir
GetConstPointAry() const699cdf0e10cSrcweir const Point* Polygon::GetConstPointAry() const
700cdf0e10cSrcweir {
701cdf0e10cSrcweir DBG_CHKTHIS( Polygon, NULL );
702cdf0e10cSrcweir return (Point*)mpImplPolygon->mpPointAry;
703cdf0e10cSrcweir }
704cdf0e10cSrcweir
705cdf0e10cSrcweir // -----------------------------------------------------------------------
706cdf0e10cSrcweir
GetConstFlagAry() const707cdf0e10cSrcweir const sal_uInt8* Polygon::GetConstFlagAry() const
708cdf0e10cSrcweir {
709cdf0e10cSrcweir DBG_CHKTHIS( Polygon, NULL );
710cdf0e10cSrcweir return mpImplPolygon->mpFlagAry;
711cdf0e10cSrcweir }
712cdf0e10cSrcweir
713cdf0e10cSrcweir // -----------------------------------------------------------------------
714cdf0e10cSrcweir
SetPoint(const Point & rPt,sal_uInt16 nPos)715cdf0e10cSrcweir void Polygon::SetPoint( const Point& rPt, sal_uInt16 nPos )
716cdf0e10cSrcweir {
717cdf0e10cSrcweir DBG_CHKTHIS( Polygon, NULL );
718cdf0e10cSrcweir DBG_ASSERT( nPos < mpImplPolygon->mnPoints,
719cdf0e10cSrcweir "Polygon::SetPoint(): nPos >= nPoints" );
720cdf0e10cSrcweir
721cdf0e10cSrcweir ImplMakeUnique();
722cdf0e10cSrcweir mpImplPolygon->mpPointAry[nPos] = rPt;
723cdf0e10cSrcweir }
724cdf0e10cSrcweir
725cdf0e10cSrcweir // -----------------------------------------------------------------------
726cdf0e10cSrcweir
SetFlags(sal_uInt16 nPos,PolyFlags eFlags)727cdf0e10cSrcweir void Polygon::SetFlags( sal_uInt16 nPos, PolyFlags eFlags )
728cdf0e10cSrcweir {
729cdf0e10cSrcweir DBG_CHKTHIS( Polygon, NULL );
730cdf0e10cSrcweir DBG_ASSERT( nPos < mpImplPolygon->mnPoints,
731cdf0e10cSrcweir "Polygon::SetFlags(): nPos >= nPoints" );
732cdf0e10cSrcweir
733cdf0e10cSrcweir // we do only want to create the flag array if there
734cdf0e10cSrcweir // is at least one flag different to POLY_NORMAL
735cdf0e10cSrcweir if ( mpImplPolygon || ( eFlags != POLY_NORMAL ) )
736cdf0e10cSrcweir {
737cdf0e10cSrcweir ImplMakeUnique();
738cdf0e10cSrcweir mpImplPolygon->ImplCreateFlagArray();
739cdf0e10cSrcweir mpImplPolygon->mpFlagAry[ nPos ] = (sal_uInt8) eFlags;
740cdf0e10cSrcweir }
741cdf0e10cSrcweir }
742cdf0e10cSrcweir
743cdf0e10cSrcweir // -----------------------------------------------------------------------
744cdf0e10cSrcweir
GetPoint(sal_uInt16 nPos) const745cdf0e10cSrcweir const Point& Polygon::GetPoint( sal_uInt16 nPos ) const
746cdf0e10cSrcweir {
747cdf0e10cSrcweir DBG_CHKTHIS( Polygon, NULL );
748cdf0e10cSrcweir DBG_ASSERT( nPos < mpImplPolygon->mnPoints,
749cdf0e10cSrcweir "Polygon::GetPoint(): nPos >= nPoints" );
750cdf0e10cSrcweir
751cdf0e10cSrcweir return mpImplPolygon->mpPointAry[nPos];
752cdf0e10cSrcweir }
753cdf0e10cSrcweir
754cdf0e10cSrcweir // -----------------------------------------------------------------------
755cdf0e10cSrcweir
GetFlags(sal_uInt16 nPos) const756cdf0e10cSrcweir PolyFlags Polygon::GetFlags( sal_uInt16 nPos ) const
757cdf0e10cSrcweir {
758cdf0e10cSrcweir DBG_CHKTHIS( Polygon, NULL );
759cdf0e10cSrcweir DBG_ASSERT( nPos < mpImplPolygon->mnPoints,
760cdf0e10cSrcweir "Polygon::GetFlags(): nPos >= nPoints" );
761cdf0e10cSrcweir return( mpImplPolygon->mpFlagAry ?
762cdf0e10cSrcweir (PolyFlags) mpImplPolygon->mpFlagAry[ nPos ] :
763cdf0e10cSrcweir POLY_NORMAL );
764cdf0e10cSrcweir }
765cdf0e10cSrcweir
766cdf0e10cSrcweir // -----------------------------------------------------------------------
767cdf0e10cSrcweir
HasFlags() const768cdf0e10cSrcweir sal_Bool Polygon::HasFlags() const
769cdf0e10cSrcweir {
770cdf0e10cSrcweir return mpImplPolygon->mpFlagAry != NULL;
771cdf0e10cSrcweir }
772cdf0e10cSrcweir
773cdf0e10cSrcweir // -----------------------------------------------------------------------
774cdf0e10cSrcweir
IsControl(sal_uInt16 nPos) const775cdf0e10cSrcweir sal_Bool Polygon::IsControl(sal_uInt16 nPos) const
776cdf0e10cSrcweir {
777cdf0e10cSrcweir DBG_CHKTHIS( Polygon, NULL );
778cdf0e10cSrcweir DBG_ASSERT( nPos < mpImplPolygon->mnPoints,
779cdf0e10cSrcweir "Polygon::GetFlags(): nPos >= nPoints" );
780cdf0e10cSrcweir PolyFlags eFlags = mpImplPolygon->mpFlagAry ?
781cdf0e10cSrcweir (PolyFlags) mpImplPolygon->mpFlagAry[ nPos ] : POLY_NORMAL;
782cdf0e10cSrcweir
783cdf0e10cSrcweir return( POLY_CONTROL == eFlags );
784cdf0e10cSrcweir }
785cdf0e10cSrcweir
786cdf0e10cSrcweir // -----------------------------------------------------------------------
787cdf0e10cSrcweir
IsSmooth(sal_uInt16 nPos) const788cdf0e10cSrcweir sal_Bool Polygon::IsSmooth(sal_uInt16 nPos) const
789cdf0e10cSrcweir {
790cdf0e10cSrcweir DBG_CHKTHIS( Polygon, NULL );
791cdf0e10cSrcweir DBG_ASSERT( nPos < mpImplPolygon->mnPoints,
792cdf0e10cSrcweir "Polygon::GetFlags(): nPos >= nPoints" );
793cdf0e10cSrcweir PolyFlags eFlags = mpImplPolygon->mpFlagAry ?
794cdf0e10cSrcweir (PolyFlags) mpImplPolygon->mpFlagAry[ nPos ] : POLY_NORMAL;
795cdf0e10cSrcweir
796cdf0e10cSrcweir return( ( POLY_SMOOTH == eFlags ) || ( POLY_SYMMTR == eFlags ) );
797cdf0e10cSrcweir }
798cdf0e10cSrcweir
799cdf0e10cSrcweir // -----------------------------------------------------------------------
800cdf0e10cSrcweir
IsRect() const801cdf0e10cSrcweir sal_Bool Polygon::IsRect() const
802cdf0e10cSrcweir {
803cdf0e10cSrcweir sal_Bool bIsRect = sal_False;
804cdf0e10cSrcweir if ( mpImplPolygon->mpFlagAry == NULL )
805cdf0e10cSrcweir {
806cdf0e10cSrcweir if ( ( ( mpImplPolygon->mnPoints == 5 ) && ( mpImplPolygon->mpPointAry[ 0 ] == mpImplPolygon->mpPointAry[ 4 ] ) ) ||
807cdf0e10cSrcweir ( mpImplPolygon->mnPoints == 4 ) )
808cdf0e10cSrcweir {
809cdf0e10cSrcweir if ( ( mpImplPolygon->mpPointAry[ 0 ].X() == mpImplPolygon->mpPointAry[ 3 ].X() ) &&
810cdf0e10cSrcweir ( mpImplPolygon->mpPointAry[ 0 ].Y() == mpImplPolygon->mpPointAry[ 1 ].Y() ) &&
811cdf0e10cSrcweir ( mpImplPolygon->mpPointAry[ 1 ].X() == mpImplPolygon->mpPointAry[ 2 ].X() ) &&
812cdf0e10cSrcweir ( mpImplPolygon->mpPointAry[ 2 ].Y() == mpImplPolygon->mpPointAry[ 3 ].Y() ) )
813cdf0e10cSrcweir bIsRect = sal_True;
814cdf0e10cSrcweir }
815cdf0e10cSrcweir }
816cdf0e10cSrcweir return bIsRect;
817cdf0e10cSrcweir }
818cdf0e10cSrcweir
819cdf0e10cSrcweir // -----------------------------------------------------------------------
820cdf0e10cSrcweir
SetSize(sal_uInt16 nNewSize)821cdf0e10cSrcweir void Polygon::SetSize( sal_uInt16 nNewSize )
822cdf0e10cSrcweir {
823cdf0e10cSrcweir DBG_CHKTHIS( Polygon, NULL );
824cdf0e10cSrcweir
825cdf0e10cSrcweir if( nNewSize != mpImplPolygon->mnPoints )
826cdf0e10cSrcweir {
827cdf0e10cSrcweir ImplMakeUnique();
828cdf0e10cSrcweir mpImplPolygon->ImplSetSize( nNewSize );
829cdf0e10cSrcweir }
830cdf0e10cSrcweir }
831cdf0e10cSrcweir
832cdf0e10cSrcweir // -----------------------------------------------------------------------
833cdf0e10cSrcweir
GetSize() const834cdf0e10cSrcweir sal_uInt16 Polygon::GetSize() const
835cdf0e10cSrcweir {
836cdf0e10cSrcweir DBG_CHKTHIS( Polygon, NULL );
837cdf0e10cSrcweir
838cdf0e10cSrcweir return mpImplPolygon->mnPoints;
839cdf0e10cSrcweir }
840cdf0e10cSrcweir
841cdf0e10cSrcweir // -----------------------------------------------------------------------
842cdf0e10cSrcweir
Clear()843cdf0e10cSrcweir void Polygon::Clear()
844cdf0e10cSrcweir {
845cdf0e10cSrcweir DBG_CHKTHIS( Polygon, NULL );
846cdf0e10cSrcweir
847cdf0e10cSrcweir if ( mpImplPolygon->mnRefCount )
848cdf0e10cSrcweir {
849cdf0e10cSrcweir if ( mpImplPolygon->mnRefCount > 1 )
850cdf0e10cSrcweir mpImplPolygon->mnRefCount--;
851cdf0e10cSrcweir else
852cdf0e10cSrcweir delete mpImplPolygon;
853cdf0e10cSrcweir }
854cdf0e10cSrcweir
855cdf0e10cSrcweir mpImplPolygon = (ImplPolygon*)(&aStaticImplPolygon);
856cdf0e10cSrcweir }
857cdf0e10cSrcweir
858cdf0e10cSrcweir // -----------------------------------------------------------------------
859cdf0e10cSrcweir
CalcDistance(sal_uInt16 nP1,sal_uInt16 nP2)860cdf0e10cSrcweir double Polygon::CalcDistance( sal_uInt16 nP1, sal_uInt16 nP2 )
861cdf0e10cSrcweir {
862cdf0e10cSrcweir DBG_ASSERT( nP1 < mpImplPolygon->mnPoints,
863cdf0e10cSrcweir "Polygon::CalcDistance(): nPos1 >= nPoints" );
864cdf0e10cSrcweir DBG_ASSERT( nP2 < mpImplPolygon->mnPoints,
865cdf0e10cSrcweir "Polygon::CalcDistance(): nPos2 >= nPoints" );
866cdf0e10cSrcweir
867cdf0e10cSrcweir const Point& rP1 = mpImplPolygon->mpPointAry[ nP1 ];
868cdf0e10cSrcweir const Point& rP2 = mpImplPolygon->mpPointAry[ nP2 ];
869cdf0e10cSrcweir const double fDx = rP2.X() - rP1.X();
870cdf0e10cSrcweir const double fDy = rP2.Y() - rP1.Y();
871cdf0e10cSrcweir
872cdf0e10cSrcweir return sqrt( fDx * fDx + fDy * fDy );
873cdf0e10cSrcweir }
874cdf0e10cSrcweir
875cdf0e10cSrcweir // -----------------------------------------------------------------------
876cdf0e10cSrcweir
Optimize(sal_uIntPtr nOptimizeFlags,const PolyOptimizeData * pData)877cdf0e10cSrcweir void Polygon::Optimize( sal_uIntPtr nOptimizeFlags, const PolyOptimizeData* pData )
878cdf0e10cSrcweir {
879cdf0e10cSrcweir DBG_CHKTHIS( Polygon, NULL );
880cdf0e10cSrcweir DBG_ASSERT( !mpImplPolygon->mpFlagAry, "Optimizing could fail with beziers!" );
881cdf0e10cSrcweir
882cdf0e10cSrcweir sal_uInt16 nSize = mpImplPolygon->mnPoints;
883cdf0e10cSrcweir
884cdf0e10cSrcweir if( nOptimizeFlags && nSize )
885cdf0e10cSrcweir {
886cdf0e10cSrcweir if( nOptimizeFlags & POLY_OPTIMIZE_EDGES )
887cdf0e10cSrcweir {
888cdf0e10cSrcweir const Rectangle aBound( GetBoundRect() );
889cdf0e10cSrcweir const double fArea = ( aBound.GetWidth() + aBound.GetHeight() ) * 0.5;
890cdf0e10cSrcweir const sal_uInt16 nPercent = pData ? pData->GetPercentValue() : 50;
891cdf0e10cSrcweir
892cdf0e10cSrcweir Optimize( POLY_OPTIMIZE_NO_SAME );
893cdf0e10cSrcweir ImplReduceEdges( *this, fArea, nPercent );
894cdf0e10cSrcweir }
895cdf0e10cSrcweir else if( nOptimizeFlags & ( POLY_OPTIMIZE_REDUCE | POLY_OPTIMIZE_NO_SAME ) )
896cdf0e10cSrcweir {
897cdf0e10cSrcweir Polygon aNewPoly;
898cdf0e10cSrcweir const Point& rFirst = mpImplPolygon->mpPointAry[ 0 ];
899cdf0e10cSrcweir sal_uIntPtr nReduce;
900cdf0e10cSrcweir
901cdf0e10cSrcweir if( nOptimizeFlags & ( POLY_OPTIMIZE_REDUCE ) )
902cdf0e10cSrcweir nReduce = pData ? pData->GetAbsValue() : 4UL;
903cdf0e10cSrcweir else
904cdf0e10cSrcweir nReduce = 0UL;
905cdf0e10cSrcweir
906cdf0e10cSrcweir while( nSize && ( mpImplPolygon->mpPointAry[ nSize - 1 ] == rFirst ) )
907cdf0e10cSrcweir nSize--;
908cdf0e10cSrcweir
909cdf0e10cSrcweir if( nSize > 1 )
910cdf0e10cSrcweir {
911cdf0e10cSrcweir sal_uInt16 nLast = 0, nNewCount = 1;
912cdf0e10cSrcweir
913cdf0e10cSrcweir aNewPoly.SetSize( nSize );
914cdf0e10cSrcweir aNewPoly[ 0 ] = rFirst;
915cdf0e10cSrcweir
916cdf0e10cSrcweir for( sal_uInt16 i = 1; i < nSize; i++ )
917cdf0e10cSrcweir {
918cdf0e10cSrcweir if( ( mpImplPolygon->mpPointAry[ i ] != mpImplPolygon->mpPointAry[ nLast ] ) &&
919cdf0e10cSrcweir ( !nReduce || ( nReduce < (sal_uIntPtr) FRound( CalcDistance( nLast, i ) ) ) ) )
920cdf0e10cSrcweir {
921cdf0e10cSrcweir aNewPoly[ nNewCount++ ] = mpImplPolygon->mpPointAry[ nLast = i ];
922cdf0e10cSrcweir }
923cdf0e10cSrcweir }
924cdf0e10cSrcweir
925cdf0e10cSrcweir if( nNewCount == 1 )
926cdf0e10cSrcweir aNewPoly.Clear();
927cdf0e10cSrcweir else
928cdf0e10cSrcweir aNewPoly.SetSize( nNewCount );
929cdf0e10cSrcweir }
930cdf0e10cSrcweir
931cdf0e10cSrcweir *this = aNewPoly;
932cdf0e10cSrcweir }
933cdf0e10cSrcweir
934cdf0e10cSrcweir nSize = mpImplPolygon->mnPoints;
935cdf0e10cSrcweir
936cdf0e10cSrcweir if( nSize > 1 )
937cdf0e10cSrcweir {
938cdf0e10cSrcweir if( ( nOptimizeFlags & POLY_OPTIMIZE_CLOSE ) &&
939cdf0e10cSrcweir ( mpImplPolygon->mpPointAry[ 0 ] != mpImplPolygon->mpPointAry[ nSize - 1 ] ) )
940cdf0e10cSrcweir {
941cdf0e10cSrcweir SetSize( mpImplPolygon->mnPoints + 1 );
942cdf0e10cSrcweir mpImplPolygon->mpPointAry[ mpImplPolygon->mnPoints - 1 ] = mpImplPolygon->mpPointAry[ 0 ];
943cdf0e10cSrcweir }
944cdf0e10cSrcweir else if( ( nOptimizeFlags & POLY_OPTIMIZE_OPEN ) &&
945cdf0e10cSrcweir ( mpImplPolygon->mpPointAry[ 0 ] == mpImplPolygon->mpPointAry[ nSize - 1 ] ) )
946cdf0e10cSrcweir {
947cdf0e10cSrcweir const Point& rFirst = mpImplPolygon->mpPointAry[ 0 ];
948cdf0e10cSrcweir
949cdf0e10cSrcweir while( nSize && ( mpImplPolygon->mpPointAry[ nSize - 1 ] == rFirst ) )
950cdf0e10cSrcweir nSize--;
951cdf0e10cSrcweir
952cdf0e10cSrcweir SetSize( nSize );
953cdf0e10cSrcweir }
954cdf0e10cSrcweir }
955cdf0e10cSrcweir }
956cdf0e10cSrcweir }
957cdf0e10cSrcweir
958cdf0e10cSrcweir // =======================================================================
959cdf0e10cSrcweir
960cdf0e10cSrcweir /* Recursively subdivide cubic bezier curve via deCasteljau.
961cdf0e10cSrcweir
962cdf0e10cSrcweir @param rPointIter
963cdf0e10cSrcweir Output iterator, where the subdivided polylines are written to.
964cdf0e10cSrcweir
965cdf0e10cSrcweir @param d
966cdf0e10cSrcweir Squared difference of curve to a straight line
967cdf0e10cSrcweir
968cdf0e10cSrcweir @param P*
969cdf0e10cSrcweir Exactly four points, interpreted as support and control points of
970cdf0e10cSrcweir a cubic bezier curve. Must be in device coordinates, since stop
971cdf0e10cSrcweir criterion is based on the following assumption: the device has a
972cdf0e10cSrcweir finite resolution, it is thus sufficient to stop subdivision if the
973cdf0e10cSrcweir curve does not deviate more than one pixel from a straight line.
974cdf0e10cSrcweir
975cdf0e10cSrcweir */
ImplAdaptiveSubdivide(::std::back_insert_iterator<::std::vector<Point>> & rPointIter,const double old_d2,int recursionDepth,const double d2,const double P1x,const double P1y,const double P2x,const double P2y,const double P3x,const double P3y,const double P4x,const double P4y)976cdf0e10cSrcweir static void ImplAdaptiveSubdivide( ::std::back_insert_iterator< ::std::vector< Point > >& rPointIter,
977cdf0e10cSrcweir const double old_d2,
978cdf0e10cSrcweir int recursionDepth,
979cdf0e10cSrcweir const double d2,
980cdf0e10cSrcweir const double P1x, const double P1y,
981cdf0e10cSrcweir const double P2x, const double P2y,
982cdf0e10cSrcweir const double P3x, const double P3y,
983cdf0e10cSrcweir const double P4x, const double P4y )
984cdf0e10cSrcweir {
985cdf0e10cSrcweir // Hard limit on recursion depth, empiric number.
986cdf0e10cSrcweir enum {maxRecursionDepth=128};
987cdf0e10cSrcweir
988cdf0e10cSrcweir // Perform bezier flatness test (lecture notes from R. Schaback,
989cdf0e10cSrcweir // Mathematics of Computer-Aided Design, Uni Goettingen, 2000)
990cdf0e10cSrcweir //
991cdf0e10cSrcweir // ||P(t) - L(t)|| <= max ||b_j - b_0 - j/n(b_n - b_0)||
992cdf0e10cSrcweir // 0<=j<=n
993cdf0e10cSrcweir //
994cdf0e10cSrcweir // What is calculated here is an upper bound to the distance from
995cdf0e10cSrcweir // a line through b_0 and b_3 (P1 and P4 in our notation) and the
996cdf0e10cSrcweir // curve. We can drop 0 and n from the running indices, since the
997cdf0e10cSrcweir // argument of max becomes zero for those cases.
998cdf0e10cSrcweir const double fJ1x( P2x - P1x - 1.0/3.0*(P4x - P1x) );
999cdf0e10cSrcweir const double fJ1y( P2y - P1y - 1.0/3.0*(P4y - P1y) );
1000cdf0e10cSrcweir const double fJ2x( P3x - P1x - 2.0/3.0*(P4x - P1x) );
1001cdf0e10cSrcweir const double fJ2y( P3y - P1y - 2.0/3.0*(P4y - P1y) );
1002cdf0e10cSrcweir const double distance2( ::std::max( fJ1x*fJ1x + fJ1y*fJ1y,
1003cdf0e10cSrcweir fJ2x*fJ2x + fJ2y*fJ2y) );
1004cdf0e10cSrcweir
1005cdf0e10cSrcweir // stop if error measure does not improve anymore. This is a
1006cdf0e10cSrcweir // safety guard against floating point inaccuracies.
1007cdf0e10cSrcweir // stop at recursion level 128. This is a safety guard against
1008cdf0e10cSrcweir // floating point inaccuracies.
1009cdf0e10cSrcweir // stop if distance from line is guaranteed to be bounded by d
1010cdf0e10cSrcweir if( old_d2 > d2 &&
1011cdf0e10cSrcweir recursionDepth < maxRecursionDepth &&
1012cdf0e10cSrcweir distance2 >= d2 )
1013cdf0e10cSrcweir {
1014cdf0e10cSrcweir // deCasteljau bezier arc, split at t=0.5
1015cdf0e10cSrcweir // Foley/vanDam, p. 508
1016cdf0e10cSrcweir const double L1x( P1x ), L1y( P1y );
1017cdf0e10cSrcweir const double L2x( (P1x + P2x)*0.5 ), L2y( (P1y + P2y)*0.5 );
1018cdf0e10cSrcweir const double Hx ( (P2x + P3x)*0.5 ), Hy ( (P2y + P3y)*0.5 );
1019cdf0e10cSrcweir const double L3x( (L2x + Hx)*0.5 ), L3y( (L2y + Hy)*0.5 );
1020cdf0e10cSrcweir const double R4x( P4x ), R4y( P4y );
1021cdf0e10cSrcweir const double R3x( (P3x + P4x)*0.5 ), R3y( (P3y + P4y)*0.5 );
1022cdf0e10cSrcweir const double R2x( (Hx + R3x)*0.5 ), R2y( (Hy + R3y)*0.5 );
1023cdf0e10cSrcweir const double R1x( (L3x + R2x)*0.5 ), R1y( (L3y + R2y)*0.5 );
1024cdf0e10cSrcweir const double L4x( R1x ), L4y( R1y );
1025cdf0e10cSrcweir
1026cdf0e10cSrcweir // subdivide further
1027cdf0e10cSrcweir ++recursionDepth;
1028cdf0e10cSrcweir ImplAdaptiveSubdivide(rPointIter, distance2, recursionDepth, d2, L1x, L1y, L2x, L2y, L3x, L3y, L4x, L4y);
1029cdf0e10cSrcweir ImplAdaptiveSubdivide(rPointIter, distance2, recursionDepth, d2, R1x, R1y, R2x, R2y, R3x, R3y, R4x, R4y);
1030cdf0e10cSrcweir }
1031cdf0e10cSrcweir else
1032cdf0e10cSrcweir {
1033cdf0e10cSrcweir // requested resolution reached.
1034cdf0e10cSrcweir // Add end points to output iterator.
1035cdf0e10cSrcweir // order is preserved, since this is so to say depth first traversal.
1036cdf0e10cSrcweir *rPointIter++ = Point( FRound(P1x), FRound(P1y) );
1037cdf0e10cSrcweir }
1038cdf0e10cSrcweir }
1039cdf0e10cSrcweir
1040cdf0e10cSrcweir // =======================================================================
1041cdf0e10cSrcweir
AdaptiveSubdivide(Polygon & rResult,const double d) const1042cdf0e10cSrcweir void Polygon::AdaptiveSubdivide( Polygon& rResult, const double d ) const
1043cdf0e10cSrcweir {
1044cdf0e10cSrcweir if( !mpImplPolygon->mpFlagAry )
1045cdf0e10cSrcweir {
1046cdf0e10cSrcweir rResult = *this;
1047cdf0e10cSrcweir }
1048cdf0e10cSrcweir else
1049cdf0e10cSrcweir {
1050cdf0e10cSrcweir sal_uInt16 i;
1051cdf0e10cSrcweir sal_uInt16 nPts( GetSize() );
1052cdf0e10cSrcweir ::std::vector< Point > aPoints;
1053cdf0e10cSrcweir aPoints.reserve( nPts );
1054cdf0e10cSrcweir ::std::back_insert_iterator< ::std::vector< Point > > aPointIter( aPoints );
1055cdf0e10cSrcweir
1056cdf0e10cSrcweir for(i=0; i<nPts;)
1057cdf0e10cSrcweir {
1058cdf0e10cSrcweir if( ( i + 3 ) < nPts )
1059cdf0e10cSrcweir {
1060cdf0e10cSrcweir sal_uInt8 P1( mpImplPolygon->mpFlagAry[ i ] );
1061cdf0e10cSrcweir sal_uInt8 P4( mpImplPolygon->mpFlagAry[ i + 3 ] );
1062cdf0e10cSrcweir
1063cdf0e10cSrcweir if( ( POLY_NORMAL == P1 || POLY_SMOOTH == P1 || POLY_SYMMTR == P1 ) &&
1064cdf0e10cSrcweir ( POLY_CONTROL == mpImplPolygon->mpFlagAry[ i + 1 ] ) &&
1065cdf0e10cSrcweir ( POLY_CONTROL == mpImplPolygon->mpFlagAry[ i + 2 ] ) &&
1066cdf0e10cSrcweir ( POLY_NORMAL == P4 || POLY_SMOOTH == P4 || POLY_SYMMTR == P4 ) )
1067cdf0e10cSrcweir {
1068cdf0e10cSrcweir ImplAdaptiveSubdivide( aPointIter, d*d+1.0, 0, d*d,
1069cdf0e10cSrcweir mpImplPolygon->mpPointAry[ i ].X(), mpImplPolygon->mpPointAry[ i ].Y(),
1070cdf0e10cSrcweir mpImplPolygon->mpPointAry[ i+1 ].X(), mpImplPolygon->mpPointAry[ i+1 ].Y(),
1071cdf0e10cSrcweir mpImplPolygon->mpPointAry[ i+2 ].X(), mpImplPolygon->mpPointAry[ i+2 ].Y(),
1072cdf0e10cSrcweir mpImplPolygon->mpPointAry[ i+3 ].X(), mpImplPolygon->mpPointAry[ i+3 ].Y() );
1073cdf0e10cSrcweir i += 3;
1074cdf0e10cSrcweir continue;
1075cdf0e10cSrcweir }
1076cdf0e10cSrcweir }
1077cdf0e10cSrcweir
1078cdf0e10cSrcweir *aPointIter++ = mpImplPolygon->mpPointAry[ i++ ];
1079*a61ca253SJürgen Schmidt
1080*a61ca253SJürgen Schmidt if (aPoints.size() >= SAL_MAX_UINT16)
1081*a61ca253SJürgen Schmidt {
1082*a61ca253SJürgen Schmidt OSL_ENSURE(aPoints.size() < SAL_MAX_UINT16,
1083*a61ca253SJürgen Schmidt "Polygon::AdapativeSubdivision created polygon too many points;"
1084*a61ca253SJürgen Schmidt " using original polygon instead");
1085*a61ca253SJürgen Schmidt
1086*a61ca253SJürgen Schmidt // The resulting polygon can not hold all the points
1087*a61ca253SJürgen Schmidt // that we have created so far. Stop the subdivision
1088*a61ca253SJürgen Schmidt // and return a copy of the unmodified polygon.
1089*a61ca253SJürgen Schmidt rResult = *this;
1090*a61ca253SJürgen Schmidt return;
1091*a61ca253SJürgen Schmidt }
1092cdf0e10cSrcweir }
1093cdf0e10cSrcweir
1094cdf0e10cSrcweir // fill result polygon
1095cdf0e10cSrcweir rResult = Polygon( (sal_uInt16)aPoints.size() ); // ensure sufficient size for copy
1096cdf0e10cSrcweir ::std::copy(aPoints.begin(), aPoints.end(), rResult.mpImplPolygon->mpPointAry);
1097cdf0e10cSrcweir }
1098cdf0e10cSrcweir }
1099cdf0e10cSrcweir
1100cdf0e10cSrcweir // -----------------------------------------------------------------------
1101cdf0e10cSrcweir
GetIntersection(const PolyPolygon & rPolyPoly,PolyPolygon & rResult) const1102cdf0e10cSrcweir void Polygon::GetIntersection( const PolyPolygon& rPolyPoly, PolyPolygon& rResult ) const
1103cdf0e10cSrcweir {
1104cdf0e10cSrcweir const PolyPolygon aTmp( *this );
1105cdf0e10cSrcweir aTmp.GetIntersection( rPolyPoly, rResult );
1106cdf0e10cSrcweir }
1107cdf0e10cSrcweir
1108cdf0e10cSrcweir // -----------------------------------------------------------------------
1109cdf0e10cSrcweir
GetUnion(const PolyPolygon & rPolyPoly,PolyPolygon & rResult) const1110cdf0e10cSrcweir void Polygon::GetUnion( const PolyPolygon& rPolyPoly, PolyPolygon& rResult ) const
1111cdf0e10cSrcweir {
1112cdf0e10cSrcweir const PolyPolygon aTmp( *this );
1113cdf0e10cSrcweir aTmp.GetUnion( rPolyPoly, rResult );
1114cdf0e10cSrcweir }
1115cdf0e10cSrcweir
1116cdf0e10cSrcweir // -----------------------------------------------------------------------
1117cdf0e10cSrcweir
GetDifference(const PolyPolygon & rPolyPoly,PolyPolygon & rResult) const1118cdf0e10cSrcweir void Polygon::GetDifference( const PolyPolygon& rPolyPoly, PolyPolygon& rResult ) const
1119cdf0e10cSrcweir {
1120cdf0e10cSrcweir const PolyPolygon aTmp( *this );
1121cdf0e10cSrcweir aTmp.GetDifference( rPolyPoly, rResult );
1122cdf0e10cSrcweir }
1123cdf0e10cSrcweir
1124cdf0e10cSrcweir // -----------------------------------------------------------------------
1125cdf0e10cSrcweir
GetXOR(const PolyPolygon & rPolyPoly,PolyPolygon & rResult) const1126cdf0e10cSrcweir void Polygon::GetXOR( const PolyPolygon& rPolyPoly, PolyPolygon& rResult ) const
1127cdf0e10cSrcweir {
1128cdf0e10cSrcweir const PolyPolygon aTmp( *this );
1129cdf0e10cSrcweir aTmp.GetXOR( rPolyPoly, rResult );
1130cdf0e10cSrcweir }
1131cdf0e10cSrcweir
1132cdf0e10cSrcweir // -----------------------------------------------------------------------
1133cdf0e10cSrcweir
ImplReduceEdges(Polygon & rPoly,const double & rArea,sal_uInt16 nPercent)1134cdf0e10cSrcweir void Polygon::ImplReduceEdges( Polygon& rPoly, const double& rArea, sal_uInt16 nPercent )
1135cdf0e10cSrcweir {
1136cdf0e10cSrcweir const double fBound = 2000.0 * ( 100 - nPercent ) * 0.01;
1137cdf0e10cSrcweir sal_uInt16 nNumNoChange = 0, nNumRuns = 0;
1138cdf0e10cSrcweir
1139cdf0e10cSrcweir while( nNumNoChange < 2 )
1140cdf0e10cSrcweir {
1141cdf0e10cSrcweir sal_uInt16 nPntCnt = rPoly.GetSize(), nNewPos = 0;
1142cdf0e10cSrcweir Polygon aNewPoly( nPntCnt );
1143cdf0e10cSrcweir sal_Bool bChangeInThisRun = sal_False;
1144cdf0e10cSrcweir
1145cdf0e10cSrcweir for( sal_uInt16 n = 0; n < nPntCnt; n++ )
1146cdf0e10cSrcweir {
1147cdf0e10cSrcweir sal_Bool bDeletePoint = sal_False;
1148cdf0e10cSrcweir
1149cdf0e10cSrcweir if( ( n + nNumRuns ) % 2 )
1150cdf0e10cSrcweir {
1151cdf0e10cSrcweir sal_uInt16 nIndPrev = !n ? nPntCnt - 1 : n - 1;
1152cdf0e10cSrcweir sal_uInt16 nIndPrevPrev = !nIndPrev ? nPntCnt - 1 : nIndPrev - 1;
1153cdf0e10cSrcweir sal_uInt16 nIndNext = ( n == nPntCnt-1 ) ? 0 : n + 1;
1154cdf0e10cSrcweir sal_uInt16 nIndNextNext = ( nIndNext == nPntCnt - 1 ) ? 0 : nIndNext + 1;
1155cdf0e10cSrcweir Vector2D aVec1( rPoly[ nIndPrev ] ); aVec1 -= rPoly[ nIndPrevPrev ];
1156cdf0e10cSrcweir Vector2D aVec2( rPoly[ n ] ); aVec2 -= rPoly[ nIndPrev ];
1157cdf0e10cSrcweir Vector2D aVec3( rPoly[ nIndNext ] ); aVec3 -= rPoly[ n ];
1158cdf0e10cSrcweir Vector2D aVec4( rPoly[ nIndNextNext ] ); aVec4 -= rPoly[ nIndNext ];
1159cdf0e10cSrcweir double fDist1 = aVec1.GetLength(), fDist2 = aVec2.GetLength();
1160cdf0e10cSrcweir double fDist3 = aVec3.GetLength(), fDist4 = aVec4.GetLength();
1161cdf0e10cSrcweir double fTurnB = aVec2.Normalize().Scalar( aVec3.Normalize() );
1162cdf0e10cSrcweir
1163cdf0e10cSrcweir if( fabs( fTurnB ) < ( 1.0 + SMALL_DVALUE ) && fabs( fTurnB ) > ( 1.0 - SMALL_DVALUE ) )
1164cdf0e10cSrcweir bDeletePoint = sal_True;
1165cdf0e10cSrcweir else
1166cdf0e10cSrcweir {
1167cdf0e10cSrcweir Vector2D aVecB( rPoly[ nIndNext ] );
1168cdf0e10cSrcweir double fDistB = ( aVecB -= rPoly[ nIndPrev ] ).GetLength();
1169cdf0e10cSrcweir double fLenWithB = fDist2 + fDist3;
1170cdf0e10cSrcweir double fLenFact = ( fDistB != 0.0 ) ? fLenWithB / fDistB : 1.0;
1171cdf0e10cSrcweir double fTurnPrev = aVec1.Normalize().Scalar( aVec2 );
1172cdf0e10cSrcweir double fTurnNext = aVec3.Scalar( aVec4.Normalize() );
1173cdf0e10cSrcweir double fGradPrev, fGradB, fGradNext;
1174cdf0e10cSrcweir
1175cdf0e10cSrcweir if( fabs( fTurnPrev ) < ( 1.0 + SMALL_DVALUE ) && fabs( fTurnPrev ) > ( 1.0 - SMALL_DVALUE ) )
1176cdf0e10cSrcweir fGradPrev = 0.0;
1177cdf0e10cSrcweir else
1178cdf0e10cSrcweir fGradPrev = acos( fTurnPrev ) / ( aVec1.IsNegative( aVec2 ) ? -F_PI180 : F_PI180 );
1179cdf0e10cSrcweir
1180cdf0e10cSrcweir fGradB = acos( fTurnB ) / ( aVec2.IsNegative( aVec3 ) ? -F_PI180 : F_PI180 );
1181cdf0e10cSrcweir
1182cdf0e10cSrcweir if( fabs( fTurnNext ) < ( 1.0 + SMALL_DVALUE ) && fabs( fTurnNext ) > ( 1.0 - SMALL_DVALUE ) )
1183cdf0e10cSrcweir fGradNext = 0.0;
1184cdf0e10cSrcweir else
1185cdf0e10cSrcweir fGradNext = acos( fTurnNext ) / ( aVec3.IsNegative( aVec4 ) ? -F_PI180 : F_PI180 );
1186cdf0e10cSrcweir
1187cdf0e10cSrcweir if( ( fGradPrev > 0.0 && fGradB < 0.0 && fGradNext > 0.0 ) ||
1188cdf0e10cSrcweir ( fGradPrev < 0.0 && fGradB > 0.0 && fGradNext < 0.0 ) )
1189cdf0e10cSrcweir {
1190cdf0e10cSrcweir if( ( fLenFact < ( FSQRT2 + SMALL_DVALUE ) ) &&
1191cdf0e10cSrcweir ( ( ( fDist1 + fDist4 ) / ( fDist2 + fDist3 ) ) * 2000.0 ) > fBound )
1192cdf0e10cSrcweir {
1193cdf0e10cSrcweir bDeletePoint = sal_True;
1194cdf0e10cSrcweir }
1195cdf0e10cSrcweir }
1196cdf0e10cSrcweir else
1197cdf0e10cSrcweir {
1198cdf0e10cSrcweir double fRelLen = 1.0 - sqrt( fDistB / rArea );
1199cdf0e10cSrcweir
1200cdf0e10cSrcweir if( fRelLen < 0.0 )
1201cdf0e10cSrcweir fRelLen = 0.0;
1202cdf0e10cSrcweir else if( fRelLen > 1.0 )
1203cdf0e10cSrcweir fRelLen = 1.0;
1204cdf0e10cSrcweir
1205cdf0e10cSrcweir if( ( (sal_uInt32) ( ( ( fLenFact - 1.0 ) * 1000000.0 ) + 0.5 ) < fBound ) &&
1206cdf0e10cSrcweir ( fabs( fGradB ) <= ( fRelLen * fBound * 0.01 ) ) )
1207cdf0e10cSrcweir {
1208cdf0e10cSrcweir bDeletePoint = sal_True;
1209cdf0e10cSrcweir }
1210cdf0e10cSrcweir }
1211cdf0e10cSrcweir }
1212cdf0e10cSrcweir }
1213cdf0e10cSrcweir
1214cdf0e10cSrcweir if( !bDeletePoint )
1215cdf0e10cSrcweir aNewPoly[ nNewPos++ ] = rPoly[ n ];
1216cdf0e10cSrcweir else
1217cdf0e10cSrcweir bChangeInThisRun = sal_True;
1218cdf0e10cSrcweir }
1219cdf0e10cSrcweir
1220cdf0e10cSrcweir if( bChangeInThisRun && nNewPos )
1221cdf0e10cSrcweir {
1222cdf0e10cSrcweir aNewPoly.SetSize( nNewPos );
1223cdf0e10cSrcweir rPoly = aNewPoly;
1224cdf0e10cSrcweir nNumNoChange = 0;
1225cdf0e10cSrcweir }
1226cdf0e10cSrcweir else
1227cdf0e10cSrcweir nNumNoChange++;
1228cdf0e10cSrcweir
1229cdf0e10cSrcweir nNumRuns++;
1230cdf0e10cSrcweir }
1231cdf0e10cSrcweir }
1232cdf0e10cSrcweir
1233cdf0e10cSrcweir // -----------------------------------------------------------------------
1234cdf0e10cSrcweir
Move(long nHorzMove,long nVertMove)1235cdf0e10cSrcweir void Polygon::Move( long nHorzMove, long nVertMove )
1236cdf0e10cSrcweir {
1237cdf0e10cSrcweir DBG_CHKTHIS( Polygon, NULL );
1238cdf0e10cSrcweir
1239cdf0e10cSrcweir // Diese Abfrage sollte man fuer die DrawEngine durchfuehren
1240cdf0e10cSrcweir if ( !nHorzMove && !nVertMove )
1241cdf0e10cSrcweir return;
1242cdf0e10cSrcweir
1243cdf0e10cSrcweir ImplMakeUnique();
1244cdf0e10cSrcweir
1245cdf0e10cSrcweir // Punkte verschieben
1246cdf0e10cSrcweir sal_uInt16 nCount = mpImplPolygon->mnPoints;
1247cdf0e10cSrcweir for ( sal_uInt16 i = 0; i < nCount; i++ )
1248cdf0e10cSrcweir {
1249cdf0e10cSrcweir Point* pPt = &(mpImplPolygon->mpPointAry[i]);
1250cdf0e10cSrcweir pPt->X() += nHorzMove;
1251cdf0e10cSrcweir pPt->Y() += nVertMove;
1252cdf0e10cSrcweir }
1253cdf0e10cSrcweir }
1254cdf0e10cSrcweir
1255cdf0e10cSrcweir // -----------------------------------------------------------------------
1256cdf0e10cSrcweir
Translate(const Point & rTrans)1257cdf0e10cSrcweir void Polygon::Translate(const Point& rTrans)
1258cdf0e10cSrcweir {
1259cdf0e10cSrcweir DBG_CHKTHIS( Polygon, NULL );
1260cdf0e10cSrcweir ImplMakeUnique();
1261cdf0e10cSrcweir
1262cdf0e10cSrcweir for ( sal_uInt16 i = 0, nCount = mpImplPolygon->mnPoints; i < nCount; i++ )
1263cdf0e10cSrcweir mpImplPolygon->mpPointAry[ i ] += rTrans;
1264cdf0e10cSrcweir }
1265cdf0e10cSrcweir
1266cdf0e10cSrcweir // -----------------------------------------------------------------------
1267cdf0e10cSrcweir
Scale(double fScaleX,double fScaleY)1268cdf0e10cSrcweir void Polygon::Scale( double fScaleX, double fScaleY )
1269cdf0e10cSrcweir {
1270cdf0e10cSrcweir DBG_CHKTHIS( Polygon, NULL );
1271cdf0e10cSrcweir ImplMakeUnique();
1272cdf0e10cSrcweir
1273cdf0e10cSrcweir for ( sal_uInt16 i = 0, nCount = mpImplPolygon->mnPoints; i < nCount; i++ )
1274cdf0e10cSrcweir {
1275cdf0e10cSrcweir Point& rPnt = mpImplPolygon->mpPointAry[i];
1276cdf0e10cSrcweir rPnt.X() = (long) ( fScaleX * rPnt.X() );
1277cdf0e10cSrcweir rPnt.Y() = (long) ( fScaleY * rPnt.Y() );
1278cdf0e10cSrcweir }
1279cdf0e10cSrcweir }
1280cdf0e10cSrcweir
1281cdf0e10cSrcweir // -----------------------------------------------------------------------
1282cdf0e10cSrcweir
Rotate(const Point & rCenter,sal_uInt16 nAngle10)1283cdf0e10cSrcweir void Polygon::Rotate( const Point& rCenter, sal_uInt16 nAngle10 )
1284cdf0e10cSrcweir {
1285cdf0e10cSrcweir DBG_CHKTHIS( Polygon, NULL );
1286cdf0e10cSrcweir nAngle10 %= 3600;
1287cdf0e10cSrcweir
1288cdf0e10cSrcweir if( nAngle10 )
1289cdf0e10cSrcweir {
1290cdf0e10cSrcweir const double fAngle = F_PI1800 * nAngle10;
1291cdf0e10cSrcweir Rotate( rCenter, sin( fAngle ), cos( fAngle ) );
1292cdf0e10cSrcweir }
1293cdf0e10cSrcweir }
1294cdf0e10cSrcweir
1295cdf0e10cSrcweir // -----------------------------------------------------------------------
1296cdf0e10cSrcweir
Rotate(const Point & rCenter,double fSin,double fCos)1297cdf0e10cSrcweir void Polygon::Rotate( const Point& rCenter, double fSin, double fCos )
1298cdf0e10cSrcweir {
1299cdf0e10cSrcweir DBG_CHKTHIS( Polygon, NULL );
1300cdf0e10cSrcweir ImplMakeUnique();
1301cdf0e10cSrcweir
1302cdf0e10cSrcweir long nX, nY;
1303cdf0e10cSrcweir long nCenterX = rCenter.X();
1304cdf0e10cSrcweir long nCenterY = rCenter.Y();
1305cdf0e10cSrcweir
1306cdf0e10cSrcweir for( sal_uInt16 i = 0, nCount = mpImplPolygon->mnPoints; i < nCount; i++ )
1307cdf0e10cSrcweir {
1308cdf0e10cSrcweir Point& rPt = mpImplPolygon->mpPointAry[ i ];
1309cdf0e10cSrcweir
1310cdf0e10cSrcweir nX = rPt.X() - nCenterX;
1311cdf0e10cSrcweir nY = rPt.Y() - nCenterY;
1312cdf0e10cSrcweir rPt.X() = (long) FRound( fCos * nX + fSin * nY ) + nCenterX;
1313cdf0e10cSrcweir rPt.Y() = -(long) FRound( fSin * nX - fCos * nY ) + nCenterY;
1314cdf0e10cSrcweir }
1315cdf0e10cSrcweir }
1316cdf0e10cSrcweir
1317cdf0e10cSrcweir // -----------------------------------------------------------------------
1318cdf0e10cSrcweir
SlantX(long nYRef,double fSin,double fCos)1319cdf0e10cSrcweir void Polygon::SlantX( long nYRef, double fSin, double fCos )
1320cdf0e10cSrcweir {
1321cdf0e10cSrcweir DBG_CHKTHIS( Polygon, NULL );
1322cdf0e10cSrcweir ImplMakeUnique();
1323cdf0e10cSrcweir
1324cdf0e10cSrcweir for( sal_uInt16 i = 0, nCount = mpImplPolygon->mnPoints; i < nCount; i++ )
1325cdf0e10cSrcweir {
1326cdf0e10cSrcweir Point& rPnt = mpImplPolygon->mpPointAry[ i ];
1327cdf0e10cSrcweir const long nDy = rPnt.Y() - nYRef;
1328cdf0e10cSrcweir
1329cdf0e10cSrcweir rPnt.X() += (long)( fSin * nDy );
1330cdf0e10cSrcweir rPnt.Y() = nYRef + (long)( fCos * nDy );
1331cdf0e10cSrcweir }
1332cdf0e10cSrcweir }
1333cdf0e10cSrcweir
1334cdf0e10cSrcweir // -----------------------------------------------------------------------
1335cdf0e10cSrcweir
SlantY(long nXRef,double fSin,double fCos)1336cdf0e10cSrcweir void Polygon::SlantY( long nXRef, double fSin, double fCos )
1337cdf0e10cSrcweir {
1338cdf0e10cSrcweir DBG_CHKTHIS( Polygon, NULL );
1339cdf0e10cSrcweir ImplMakeUnique();
1340cdf0e10cSrcweir
1341cdf0e10cSrcweir for( sal_uInt16 i = 0, nCount = mpImplPolygon->mnPoints; i < nCount; i++ )
1342cdf0e10cSrcweir {
1343cdf0e10cSrcweir Point& rPnt = mpImplPolygon->mpPointAry[ i ];
1344cdf0e10cSrcweir const long nDx = rPnt.X() - nXRef;
1345cdf0e10cSrcweir
1346cdf0e10cSrcweir rPnt.X() = nXRef + (long)( fCos * nDx );
1347cdf0e10cSrcweir rPnt.Y() -= (long)( fSin * nDx );
1348cdf0e10cSrcweir }
1349cdf0e10cSrcweir }
1350cdf0e10cSrcweir
1351cdf0e10cSrcweir // -----------------------------------------------------------------------
1352cdf0e10cSrcweir
Distort(const Rectangle & rRefRect,const Polygon & rDistortedRect)1353cdf0e10cSrcweir void Polygon::Distort( const Rectangle& rRefRect, const Polygon& rDistortedRect )
1354cdf0e10cSrcweir {
1355cdf0e10cSrcweir DBG_CHKTHIS( Polygon, NULL );
1356cdf0e10cSrcweir ImplMakeUnique();
1357cdf0e10cSrcweir
1358cdf0e10cSrcweir long Xr, Wr, X1, X2, X3, X4;
1359cdf0e10cSrcweir long Yr, Hr, Y1, Y2, Y3, Y4;
1360cdf0e10cSrcweir double fTx, fTy, fUx, fUy;
1361cdf0e10cSrcweir
1362cdf0e10cSrcweir Xr = rRefRect.Left();
1363cdf0e10cSrcweir Yr = rRefRect.Top();
1364cdf0e10cSrcweir Wr = rRefRect.GetWidth();
1365cdf0e10cSrcweir Hr = rRefRect.GetHeight();
1366cdf0e10cSrcweir
1367cdf0e10cSrcweir if( Wr && Hr )
1368cdf0e10cSrcweir {
1369cdf0e10cSrcweir DBG_ASSERT( rDistortedRect.mpImplPolygon->mnPoints >= 4, "Distort rect too small!" );
1370cdf0e10cSrcweir
1371cdf0e10cSrcweir X1 = rDistortedRect[0].X();
1372cdf0e10cSrcweir Y1 = rDistortedRect[0].Y();
1373cdf0e10cSrcweir X2 = rDistortedRect[1].X();
1374cdf0e10cSrcweir Y2 = rDistortedRect[1].Y();
1375cdf0e10cSrcweir X3 = rDistortedRect[3].X();
1376cdf0e10cSrcweir Y3 = rDistortedRect[3].Y();
1377cdf0e10cSrcweir X4 = rDistortedRect[2].X();
1378cdf0e10cSrcweir Y4 = rDistortedRect[2].Y();
1379cdf0e10cSrcweir
1380cdf0e10cSrcweir for( sal_uInt16 i = 0, nCount = mpImplPolygon->mnPoints; i < nCount; i++ )
1381cdf0e10cSrcweir {
1382cdf0e10cSrcweir Point& rPnt = mpImplPolygon->mpPointAry[ i ];
1383cdf0e10cSrcweir
1384cdf0e10cSrcweir fTx = (double)( rPnt.X() - Xr) / Wr;
1385cdf0e10cSrcweir fTy = (double)( rPnt.Y() - Yr) / Hr;
1386cdf0e10cSrcweir fUx = 1.0 - fTx;
1387cdf0e10cSrcweir fUy = 1.0 - fTy;
1388cdf0e10cSrcweir
1389cdf0e10cSrcweir rPnt.X() = (long) ( fUy * (fUx * X1 + fTx * X2) + fTy * (fUx * X3 + fTx * X4) );
1390cdf0e10cSrcweir rPnt.Y() = (long) ( fUx * (fUy * Y1 + fTy * Y3) + fTx * (fUy * Y2 + fTy * Y4) );
1391cdf0e10cSrcweir }
1392cdf0e10cSrcweir }
1393cdf0e10cSrcweir }
1394cdf0e10cSrcweir
1395cdf0e10cSrcweir // -----------------------------------------------------------------------
1396cdf0e10cSrcweir
1397cdf0e10cSrcweir class ImplPointFilter
1398cdf0e10cSrcweir {
1399cdf0e10cSrcweir public:
1400cdf0e10cSrcweir virtual void LastPoint() = 0;
1401cdf0e10cSrcweir virtual void Input( const Point& rPoint ) = 0;
1402cdf0e10cSrcweir };
1403cdf0e10cSrcweir
1404cdf0e10cSrcweir class ImplPolygonPointFilter : public ImplPointFilter
1405cdf0e10cSrcweir {
1406cdf0e10cSrcweir public:
1407cdf0e10cSrcweir ImplPolygon* mpPoly; // Nicht loeschen, wird dem Polygon zugewiesen
1408cdf0e10cSrcweir sal_uInt16 mnSize;
1409cdf0e10cSrcweir
ImplPolygonPointFilter(sal_uInt16 nDestSize)1410cdf0e10cSrcweir ImplPolygonPointFilter( sal_uInt16 nDestSize ) :
1411cdf0e10cSrcweir mnSize( 0 )
1412cdf0e10cSrcweir {
1413cdf0e10cSrcweir mpPoly = new ImplPolygon( nDestSize );
1414cdf0e10cSrcweir }
1415cdf0e10cSrcweir
1416cdf0e10cSrcweir virtual void LastPoint();
1417cdf0e10cSrcweir virtual void Input( const Point& rPoint );
1418cdf0e10cSrcweir };
1419cdf0e10cSrcweir
Input(const Point & rPoint)1420cdf0e10cSrcweir void ImplPolygonPointFilter::Input( const Point& rPoint )
1421cdf0e10cSrcweir {
1422cdf0e10cSrcweir if ( !mnSize || (rPoint != mpPoly->mpPointAry[mnSize-1]) )
1423cdf0e10cSrcweir {
1424cdf0e10cSrcweir mnSize++;
1425cdf0e10cSrcweir if ( mnSize > mpPoly->mnPoints )
1426cdf0e10cSrcweir mpPoly->ImplSetSize( mnSize );
1427cdf0e10cSrcweir mpPoly->mpPointAry[mnSize-1] = rPoint;
1428cdf0e10cSrcweir }
1429cdf0e10cSrcweir }
1430cdf0e10cSrcweir
LastPoint()1431cdf0e10cSrcweir void ImplPolygonPointFilter::LastPoint()
1432cdf0e10cSrcweir {
1433cdf0e10cSrcweir if ( mnSize < mpPoly->mnPoints )
1434cdf0e10cSrcweir mpPoly->ImplSetSize( mnSize );
1435cdf0e10cSrcweir };
1436cdf0e10cSrcweir
1437cdf0e10cSrcweir class ImplEdgePointFilter : public ImplPointFilter
1438cdf0e10cSrcweir {
1439cdf0e10cSrcweir Point maFirstPoint;
1440cdf0e10cSrcweir Point maLastPoint;
1441cdf0e10cSrcweir ImplPointFilter& mrNextFilter;
1442cdf0e10cSrcweir const long mnLow;
1443cdf0e10cSrcweir const long mnHigh;
1444cdf0e10cSrcweir const int mnEdge;
1445cdf0e10cSrcweir int mnLastOutside;
1446cdf0e10cSrcweir sal_Bool mbFirst;
1447cdf0e10cSrcweir
1448cdf0e10cSrcweir public:
ImplEdgePointFilter(int nEdge,long nLow,long nHigh,ImplPointFilter & rNextFilter)1449cdf0e10cSrcweir ImplEdgePointFilter( int nEdge, long nLow, long nHigh,
1450cdf0e10cSrcweir ImplPointFilter& rNextFilter ) :
1451cdf0e10cSrcweir mrNextFilter( rNextFilter ),
1452cdf0e10cSrcweir mnLow( nLow ),
1453cdf0e10cSrcweir mnHigh( nHigh ),
1454cdf0e10cSrcweir mnEdge( nEdge ),
1455cdf0e10cSrcweir mbFirst( sal_True )
1456cdf0e10cSrcweir {
1457cdf0e10cSrcweir }
1458cdf0e10cSrcweir
1459cdf0e10cSrcweir Point EdgeSection( const Point& rPoint, int nEdge ) const;
1460cdf0e10cSrcweir int VisibleSide( const Point& rPoint ) const;
IsPolygon() const1461cdf0e10cSrcweir int IsPolygon() const
1462cdf0e10cSrcweir { return maFirstPoint == maLastPoint; }
1463cdf0e10cSrcweir
1464cdf0e10cSrcweir virtual void Input( const Point& rPoint );
1465cdf0e10cSrcweir virtual void LastPoint();
1466cdf0e10cSrcweir };
1467cdf0e10cSrcweir
VisibleSide(const Point & rPoint) const1468cdf0e10cSrcweir inline int ImplEdgePointFilter::VisibleSide( const Point& rPoint ) const
1469cdf0e10cSrcweir {
1470cdf0e10cSrcweir if ( mnEdge & EDGE_HORZ )
1471cdf0e10cSrcweir {
1472cdf0e10cSrcweir return rPoint.X() < mnLow ? EDGE_LEFT :
1473cdf0e10cSrcweir rPoint.X() > mnHigh ? EDGE_RIGHT : 0;
1474cdf0e10cSrcweir }
1475cdf0e10cSrcweir else
1476cdf0e10cSrcweir {
1477cdf0e10cSrcweir return rPoint.Y() < mnLow ? EDGE_TOP :
1478cdf0e10cSrcweir rPoint.Y() > mnHigh ? EDGE_BOTTOM : 0;
1479cdf0e10cSrcweir }
1480cdf0e10cSrcweir }
1481cdf0e10cSrcweir
EdgeSection(const Point & rPoint,int nEdge) const1482cdf0e10cSrcweir Point ImplEdgePointFilter::EdgeSection( const Point& rPoint, int nEdge ) const
1483cdf0e10cSrcweir {
1484cdf0e10cSrcweir long lx = maLastPoint.X();
1485cdf0e10cSrcweir long ly = maLastPoint.Y();
1486cdf0e10cSrcweir long md = rPoint.X() - lx;
1487cdf0e10cSrcweir long mn = rPoint.Y() - ly;
1488cdf0e10cSrcweir long nNewX;
1489cdf0e10cSrcweir long nNewY;
1490cdf0e10cSrcweir
1491cdf0e10cSrcweir if ( nEdge & EDGE_VERT )
1492cdf0e10cSrcweir {
1493cdf0e10cSrcweir nNewY = (nEdge == EDGE_TOP) ? mnLow : mnHigh;
1494cdf0e10cSrcweir long dy = nNewY - ly;
1495cdf0e10cSrcweir if ( !md )
1496cdf0e10cSrcweir nNewX = lx;
1497cdf0e10cSrcweir else if ( (LONG_MAX / Abs(md)) >= Abs(dy) )
1498cdf0e10cSrcweir nNewX = (dy * md) / mn + lx;
1499cdf0e10cSrcweir else
1500cdf0e10cSrcweir {
1501cdf0e10cSrcweir BigInt ady = dy;
1502cdf0e10cSrcweir ady *= md;
1503cdf0e10cSrcweir if( ady.IsNeg() )
1504cdf0e10cSrcweir if( mn < 0 )
1505cdf0e10cSrcweir ady += mn/2;
1506cdf0e10cSrcweir else
1507cdf0e10cSrcweir ady -= (mn-1)/2;
1508cdf0e10cSrcweir else
1509cdf0e10cSrcweir if( mn < 0 )
1510cdf0e10cSrcweir ady -= (mn+1)/2;
1511cdf0e10cSrcweir else
1512cdf0e10cSrcweir ady += mn/2;
1513cdf0e10cSrcweir ady /= mn;
1514cdf0e10cSrcweir nNewX = (long)ady + lx;
1515cdf0e10cSrcweir }
1516cdf0e10cSrcweir }
1517cdf0e10cSrcweir else
1518cdf0e10cSrcweir {
1519cdf0e10cSrcweir nNewX = (nEdge == EDGE_LEFT) ? mnLow : mnHigh;
1520cdf0e10cSrcweir long dx = nNewX - lx;
1521cdf0e10cSrcweir if ( !mn )
1522cdf0e10cSrcweir nNewY = ly;
1523cdf0e10cSrcweir else if ( (LONG_MAX / Abs(mn)) >= Abs(dx) )
1524cdf0e10cSrcweir nNewY = (dx * mn) / md + ly;
1525cdf0e10cSrcweir else
1526cdf0e10cSrcweir {
1527cdf0e10cSrcweir BigInt adx = dx;
1528cdf0e10cSrcweir adx *= mn;
1529cdf0e10cSrcweir if( adx.IsNeg() )
1530cdf0e10cSrcweir if( md < 0 )
1531cdf0e10cSrcweir adx += md/2;
1532cdf0e10cSrcweir else
1533cdf0e10cSrcweir adx -= (md-1)/2;
1534cdf0e10cSrcweir else
1535cdf0e10cSrcweir if( md < 0 )
1536cdf0e10cSrcweir adx -= (md+1)/2;
1537cdf0e10cSrcweir else
1538cdf0e10cSrcweir adx += md/2;
1539cdf0e10cSrcweir adx /= md;
1540cdf0e10cSrcweir nNewY = (long)adx + ly;
1541cdf0e10cSrcweir }
1542cdf0e10cSrcweir }
1543cdf0e10cSrcweir
1544cdf0e10cSrcweir return Point( nNewX, nNewY );
1545cdf0e10cSrcweir }
1546cdf0e10cSrcweir
Input(const Point & rPoint)1547cdf0e10cSrcweir void ImplEdgePointFilter::Input( const Point& rPoint )
1548cdf0e10cSrcweir {
1549cdf0e10cSrcweir int nOutside = VisibleSide( rPoint );
1550cdf0e10cSrcweir
1551cdf0e10cSrcweir if ( mbFirst )
1552cdf0e10cSrcweir {
1553cdf0e10cSrcweir maFirstPoint = rPoint;
1554cdf0e10cSrcweir mbFirst = sal_False;
1555cdf0e10cSrcweir if ( !nOutside )
1556cdf0e10cSrcweir mrNextFilter.Input( rPoint );
1557cdf0e10cSrcweir }
1558cdf0e10cSrcweir else if ( rPoint == maLastPoint )
1559cdf0e10cSrcweir return;
1560cdf0e10cSrcweir else if ( !nOutside )
1561cdf0e10cSrcweir {
1562cdf0e10cSrcweir if ( mnLastOutside )
1563cdf0e10cSrcweir mrNextFilter.Input( EdgeSection( rPoint, mnLastOutside ) );
1564cdf0e10cSrcweir mrNextFilter.Input( rPoint );
1565cdf0e10cSrcweir }
1566cdf0e10cSrcweir else if ( !mnLastOutside )
1567cdf0e10cSrcweir mrNextFilter.Input( EdgeSection( rPoint, nOutside ) );
1568cdf0e10cSrcweir else if ( nOutside != mnLastOutside )
1569cdf0e10cSrcweir {
1570cdf0e10cSrcweir mrNextFilter.Input( EdgeSection( rPoint, mnLastOutside ) );
1571cdf0e10cSrcweir mrNextFilter.Input( EdgeSection( rPoint, nOutside ) );
1572cdf0e10cSrcweir }
1573cdf0e10cSrcweir
1574cdf0e10cSrcweir maLastPoint = rPoint;
1575cdf0e10cSrcweir mnLastOutside = nOutside;
1576cdf0e10cSrcweir }
1577cdf0e10cSrcweir
LastPoint()1578cdf0e10cSrcweir void ImplEdgePointFilter::LastPoint()
1579cdf0e10cSrcweir {
1580cdf0e10cSrcweir if ( !mbFirst )
1581cdf0e10cSrcweir {
1582cdf0e10cSrcweir int nOutside = VisibleSide( maFirstPoint );
1583cdf0e10cSrcweir
1584cdf0e10cSrcweir if ( nOutside != mnLastOutside )
1585cdf0e10cSrcweir Input( maFirstPoint );
1586cdf0e10cSrcweir mrNextFilter.LastPoint();
1587cdf0e10cSrcweir }
1588cdf0e10cSrcweir }
1589cdf0e10cSrcweir
1590cdf0e10cSrcweir // -----------------------------------------------------------------------
1591cdf0e10cSrcweir
Clip(const Rectangle & rRect,sal_Bool bPolygon)1592cdf0e10cSrcweir void Polygon::Clip( const Rectangle& rRect, sal_Bool bPolygon )
1593cdf0e10cSrcweir {
1594cdf0e10cSrcweir // #105251# Justify rect befor edge filtering
1595cdf0e10cSrcweir Rectangle aJustifiedRect( rRect );
1596cdf0e10cSrcweir aJustifiedRect.Justify();
1597cdf0e10cSrcweir
1598cdf0e10cSrcweir sal_uInt16 nSourceSize = mpImplPolygon->mnPoints;
1599cdf0e10cSrcweir ImplPolygonPointFilter aPolygon( nSourceSize );
1600cdf0e10cSrcweir ImplEdgePointFilter aHorzFilter( EDGE_HORZ, aJustifiedRect.Left(), aJustifiedRect.Right(),
1601cdf0e10cSrcweir aPolygon );
1602cdf0e10cSrcweir ImplEdgePointFilter aVertFilter( EDGE_VERT, aJustifiedRect.Top(), aJustifiedRect.Bottom(),
1603cdf0e10cSrcweir aHorzFilter );
1604cdf0e10cSrcweir
1605cdf0e10cSrcweir for ( sal_uInt16 i = 0; i < nSourceSize; i++ )
1606cdf0e10cSrcweir aVertFilter.Input( mpImplPolygon->mpPointAry[i] );
1607cdf0e10cSrcweir if ( bPolygon || aVertFilter.IsPolygon() )
1608cdf0e10cSrcweir aVertFilter.LastPoint();
1609cdf0e10cSrcweir else
1610cdf0e10cSrcweir aPolygon.LastPoint();
1611cdf0e10cSrcweir
1612cdf0e10cSrcweir // Alte ImpPolygon-Daten loeschen und die vom ImpPolygonPointFilter
1613cdf0e10cSrcweir // zuweisen
1614cdf0e10cSrcweir if ( mpImplPolygon->mnRefCount )
1615cdf0e10cSrcweir {
1616cdf0e10cSrcweir if ( mpImplPolygon->mnRefCount > 1 )
1617cdf0e10cSrcweir mpImplPolygon->mnRefCount--;
1618cdf0e10cSrcweir else
1619cdf0e10cSrcweir delete mpImplPolygon;
1620cdf0e10cSrcweir }
1621cdf0e10cSrcweir mpImplPolygon = aPolygon.mpPoly;
1622cdf0e10cSrcweir }
1623cdf0e10cSrcweir
1624cdf0e10cSrcweir // -----------------------------------------------------------------------
1625cdf0e10cSrcweir
GetBoundRect() const1626cdf0e10cSrcweir Rectangle Polygon::GetBoundRect() const
1627cdf0e10cSrcweir {
1628cdf0e10cSrcweir DBG_CHKTHIS( Polygon, NULL );
1629cdf0e10cSrcweir // Removing the assert. Bezier curves have the attribute that each single
1630cdf0e10cSrcweir // curve segment defined by four points can not exit the four-point polygon
1631cdf0e10cSrcweir // defined by that points. This allows to say that the curve segment can also
1632cdf0e10cSrcweir // never leave the Range of it's defining points.
1633cdf0e10cSrcweir // The result is that Polygon::GetBoundRect() may not create the minimal
1634cdf0e10cSrcweir // BoundRect of the Polygon (to get that, use basegfx::B2DPolygon classes),
1635cdf0e10cSrcweir // but will always create a valid BoundRect, at least as long as this method
1636cdf0e10cSrcweir // 'blindly' travels over all points, including control points.
1637cdf0e10cSrcweir //
1638cdf0e10cSrcweir // DBG_ASSERT( !mpImplPolygon->mpFlagAry, "GetBoundRect could fail with beziers!" );
1639cdf0e10cSrcweir
1640cdf0e10cSrcweir sal_uInt16 nCount = mpImplPolygon->mnPoints;
1641cdf0e10cSrcweir if( ! nCount )
1642cdf0e10cSrcweir return Rectangle();
1643cdf0e10cSrcweir
1644cdf0e10cSrcweir long nXMin, nXMax, nYMin, nYMax;
1645cdf0e10cSrcweir
1646cdf0e10cSrcweir const Point* pPt = &(mpImplPolygon->mpPointAry[0]);
1647cdf0e10cSrcweir nXMin = nXMax = pPt->X();
1648cdf0e10cSrcweir nYMin = nYMax = pPt->Y();
1649cdf0e10cSrcweir
1650cdf0e10cSrcweir for ( sal_uInt16 i = 0; i < nCount; i++ )
1651cdf0e10cSrcweir {
1652cdf0e10cSrcweir pPt = &(mpImplPolygon->mpPointAry[i]);
1653cdf0e10cSrcweir
1654cdf0e10cSrcweir if ( pPt->X() < nXMin )
1655cdf0e10cSrcweir nXMin = pPt->X();
1656cdf0e10cSrcweir if ( pPt->X() > nXMax )
1657cdf0e10cSrcweir nXMax = pPt->X();
1658cdf0e10cSrcweir if ( pPt->Y() < nYMin )
1659cdf0e10cSrcweir nYMin = pPt->Y();
1660cdf0e10cSrcweir if ( pPt->Y() > nYMax )
1661cdf0e10cSrcweir nYMax = pPt->Y();
1662cdf0e10cSrcweir }
1663cdf0e10cSrcweir
1664cdf0e10cSrcweir return Rectangle( nXMin, nYMin, nXMax, nYMax );
1665cdf0e10cSrcweir }
1666cdf0e10cSrcweir
1667cdf0e10cSrcweir // -----------------------------------------------------------------------
1668cdf0e10cSrcweir
GetArea() const1669cdf0e10cSrcweir double Polygon::GetArea() const
1670cdf0e10cSrcweir {
1671cdf0e10cSrcweir const double fArea = GetSignedArea();
1672cdf0e10cSrcweir return( ( fArea < 0.0 ) ? -fArea : fArea );
1673cdf0e10cSrcweir }
1674cdf0e10cSrcweir
1675cdf0e10cSrcweir // -----------------------------------------------------------------------
1676cdf0e10cSrcweir
GetSignedArea() const1677cdf0e10cSrcweir double Polygon::GetSignedArea() const
1678cdf0e10cSrcweir {
1679cdf0e10cSrcweir DBG_CHKTHIS( Polygon, NULL );
1680cdf0e10cSrcweir DBG_ASSERT( !mpImplPolygon->mpFlagAry, "GetArea could fail with beziers!" );
1681cdf0e10cSrcweir
1682cdf0e10cSrcweir double fArea = 0.0;
1683cdf0e10cSrcweir
1684cdf0e10cSrcweir if( mpImplPolygon->mnPoints > 2 )
1685cdf0e10cSrcweir {
1686cdf0e10cSrcweir const sal_uInt16 nCount1 = mpImplPolygon->mnPoints - 1;
1687cdf0e10cSrcweir
1688cdf0e10cSrcweir for( sal_uInt16 i = 0; i < nCount1; )
1689cdf0e10cSrcweir {
1690cdf0e10cSrcweir const Point& rPt = mpImplPolygon->mpPointAry[ i ];
1691cdf0e10cSrcweir const Point& rPt1 = mpImplPolygon->mpPointAry[ ++i ];
1692cdf0e10cSrcweir fArea += ( rPt.X() - rPt1.X() ) * ( rPt.Y() + rPt1.Y() );
1693cdf0e10cSrcweir }
1694cdf0e10cSrcweir
1695cdf0e10cSrcweir const Point& rPt = mpImplPolygon->mpPointAry[ nCount1 ];
1696cdf0e10cSrcweir const Point& rPt0 = mpImplPolygon->mpPointAry[ 0 ];
1697cdf0e10cSrcweir fArea += ( rPt.X() - rPt0.X() ) * ( rPt.Y() + rPt0.Y() );
1698cdf0e10cSrcweir }
1699cdf0e10cSrcweir
1700cdf0e10cSrcweir return fArea;
1701cdf0e10cSrcweir }
1702cdf0e10cSrcweir
1703cdf0e10cSrcweir // -----------------------------------------------------------------------
1704cdf0e10cSrcweir
IsInside(const Point & rPoint) const1705cdf0e10cSrcweir sal_Bool Polygon::IsInside( const Point& rPoint ) const
1706cdf0e10cSrcweir {
1707cdf0e10cSrcweir DBG_CHKTHIS( Polygon, NULL );
1708cdf0e10cSrcweir DBG_ASSERT( !mpImplPolygon->mpFlagAry, "IsInside could fail with beziers!" );
1709cdf0e10cSrcweir
1710cdf0e10cSrcweir const Rectangle aBound( GetBoundRect() );
1711cdf0e10cSrcweir const Line aLine( rPoint, Point( aBound.Right() + 100L, rPoint.Y() ) );
1712cdf0e10cSrcweir sal_uInt16 nCount = mpImplPolygon->mnPoints;
1713cdf0e10cSrcweir sal_uInt16 nPCounter = 0;
1714cdf0e10cSrcweir
1715cdf0e10cSrcweir if ( ( nCount > 2 ) && aBound.IsInside( rPoint ) )
1716cdf0e10cSrcweir {
1717cdf0e10cSrcweir Point aPt1( mpImplPolygon->mpPointAry[ 0 ] );
1718cdf0e10cSrcweir Point aIntersection;
1719cdf0e10cSrcweir Point aLastIntersection;
1720cdf0e10cSrcweir
1721cdf0e10cSrcweir while ( ( aPt1 == mpImplPolygon->mpPointAry[ nCount - 1 ] ) && ( nCount > 3 ) )
1722cdf0e10cSrcweir nCount--;
1723cdf0e10cSrcweir
1724cdf0e10cSrcweir for ( sal_uInt16 i = 1; i <= nCount; i++ )
1725cdf0e10cSrcweir {
1726cdf0e10cSrcweir const Point& rPt2 = mpImplPolygon->mpPointAry[ ( i < nCount ) ? i : 0 ];
1727cdf0e10cSrcweir
1728cdf0e10cSrcweir if ( aLine.Intersection( Line( aPt1, rPt2 ), aIntersection ) )
1729cdf0e10cSrcweir {
1730cdf0e10cSrcweir // Hiermit verhindern wir das Einfuegen von
1731cdf0e10cSrcweir // doppelten Intersections, die gleich hintereinander folgen
1732cdf0e10cSrcweir if ( nPCounter )
1733cdf0e10cSrcweir {
1734cdf0e10cSrcweir if ( aIntersection != aLastIntersection )
1735cdf0e10cSrcweir {
1736cdf0e10cSrcweir aLastIntersection = aIntersection;
1737cdf0e10cSrcweir nPCounter++;
1738cdf0e10cSrcweir }
1739cdf0e10cSrcweir }
1740cdf0e10cSrcweir else
1741cdf0e10cSrcweir {
1742cdf0e10cSrcweir aLastIntersection = aIntersection;
1743cdf0e10cSrcweir nPCounter++;
1744cdf0e10cSrcweir }
1745cdf0e10cSrcweir }
1746cdf0e10cSrcweir
1747cdf0e10cSrcweir aPt1 = rPt2;
1748cdf0e10cSrcweir }
1749cdf0e10cSrcweir }
1750cdf0e10cSrcweir
1751cdf0e10cSrcweir // innerhalb, wenn die Anzahl der Schnittpunkte ungerade ist
1752cdf0e10cSrcweir return ( ( nPCounter & 1 ) == 1 );
1753cdf0e10cSrcweir }
1754cdf0e10cSrcweir
1755cdf0e10cSrcweir // -----------------------------------------------------------------------
1756cdf0e10cSrcweir
IsRightOrientated() const1757cdf0e10cSrcweir sal_Bool Polygon::IsRightOrientated() const
1758cdf0e10cSrcweir {
1759cdf0e10cSrcweir DBG_CHKTHIS( Polygon, NULL );
1760cdf0e10cSrcweir return GetSignedArea() >= 0.0;
1761cdf0e10cSrcweir }
1762cdf0e10cSrcweir
1763cdf0e10cSrcweir // -----------------------------------------------------------------------
1764cdf0e10cSrcweir
Insert(sal_uInt16 nPos,const Point & rPt,PolyFlags eFlags)1765cdf0e10cSrcweir void Polygon::Insert( sal_uInt16 nPos, const Point& rPt, PolyFlags eFlags )
1766cdf0e10cSrcweir {
1767cdf0e10cSrcweir DBG_CHKTHIS( Polygon, NULL );
1768cdf0e10cSrcweir ImplMakeUnique();
1769cdf0e10cSrcweir
1770cdf0e10cSrcweir if( nPos >= mpImplPolygon->mnPoints )
1771cdf0e10cSrcweir nPos = mpImplPolygon->mnPoints;
1772cdf0e10cSrcweir
1773cdf0e10cSrcweir mpImplPolygon->ImplSplit( nPos, 1 );
1774cdf0e10cSrcweir mpImplPolygon->mpPointAry[ nPos ] = rPt;
1775cdf0e10cSrcweir
1776cdf0e10cSrcweir if( POLY_NORMAL != eFlags )
1777cdf0e10cSrcweir {
1778cdf0e10cSrcweir mpImplPolygon->ImplCreateFlagArray();
1779cdf0e10cSrcweir mpImplPolygon->mpFlagAry[ nPos ] = (sal_uInt8) eFlags;
1780cdf0e10cSrcweir }
1781cdf0e10cSrcweir }
1782cdf0e10cSrcweir
1783cdf0e10cSrcweir // -----------------------------------------------------------------------
1784cdf0e10cSrcweir
Insert(sal_uInt16 nPos,const Polygon & rPoly)1785cdf0e10cSrcweir void Polygon::Insert( sal_uInt16 nPos, const Polygon& rPoly )
1786cdf0e10cSrcweir {
1787cdf0e10cSrcweir DBG_CHKTHIS( Polygon, NULL );
1788cdf0e10cSrcweir const sal_uInt16 nInsertCount = rPoly.mpImplPolygon->mnPoints;
1789cdf0e10cSrcweir
1790cdf0e10cSrcweir if( nInsertCount )
1791cdf0e10cSrcweir {
1792cdf0e10cSrcweir ImplMakeUnique();
1793cdf0e10cSrcweir
1794cdf0e10cSrcweir if( nPos >= mpImplPolygon->mnPoints )
1795cdf0e10cSrcweir nPos = mpImplPolygon->mnPoints;
1796cdf0e10cSrcweir
1797cdf0e10cSrcweir if( rPoly.mpImplPolygon->mpFlagAry )
1798cdf0e10cSrcweir mpImplPolygon->ImplCreateFlagArray();
1799cdf0e10cSrcweir
1800cdf0e10cSrcweir mpImplPolygon->ImplSplit( nPos, nInsertCount, rPoly.mpImplPolygon );
1801cdf0e10cSrcweir }
1802cdf0e10cSrcweir }
1803cdf0e10cSrcweir
1804cdf0e10cSrcweir // -----------------------------------------------------------------------
1805cdf0e10cSrcweir
Remove(sal_uInt16 nPos,sal_uInt16 nCount)1806cdf0e10cSrcweir void Polygon::Remove( sal_uInt16 nPos, sal_uInt16 nCount )
1807cdf0e10cSrcweir {
1808cdf0e10cSrcweir DBG_CHKTHIS( Polygon, NULL );
1809cdf0e10cSrcweir if( nCount && ( nPos < mpImplPolygon->mnPoints ) )
1810cdf0e10cSrcweir {
1811cdf0e10cSrcweir ImplMakeUnique();
1812cdf0e10cSrcweir mpImplPolygon->ImplRemove( nPos, nCount );
1813cdf0e10cSrcweir }
1814cdf0e10cSrcweir }
1815cdf0e10cSrcweir
1816cdf0e10cSrcweir // -----------------------------------------------------------------------
1817cdf0e10cSrcweir
operator [](sal_uInt16 nPos)1818cdf0e10cSrcweir Point& Polygon::operator[]( sal_uInt16 nPos )
1819cdf0e10cSrcweir {
1820cdf0e10cSrcweir DBG_CHKTHIS( Polygon, NULL );
1821cdf0e10cSrcweir DBG_ASSERT( nPos < mpImplPolygon->mnPoints, "Polygon::[]: nPos >= nPoints" );
1822cdf0e10cSrcweir
1823cdf0e10cSrcweir ImplMakeUnique();
1824cdf0e10cSrcweir return mpImplPolygon->mpPointAry[nPos];
1825cdf0e10cSrcweir }
1826cdf0e10cSrcweir
1827cdf0e10cSrcweir // -----------------------------------------------------------------------
1828cdf0e10cSrcweir
operator =(const Polygon & rPoly)1829cdf0e10cSrcweir Polygon& Polygon::operator=( const Polygon& rPoly )
1830cdf0e10cSrcweir {
1831cdf0e10cSrcweir DBG_CHKTHIS( Polygon, NULL );
1832cdf0e10cSrcweir DBG_CHKOBJ( &rPoly, Polygon, NULL );
1833cdf0e10cSrcweir DBG_ASSERT( rPoly.mpImplPolygon->mnRefCount < 0xFFFFFFFE, "Polygon: RefCount overflow" );
1834cdf0e10cSrcweir
1835cdf0e10cSrcweir // Zuerst Referenzcounter erhoehen, damit man sich selbst zuweisen kann
1836cdf0e10cSrcweir // RefCount == 0 fuer statische Objekte
1837cdf0e10cSrcweir if ( rPoly.mpImplPolygon->mnRefCount )
1838cdf0e10cSrcweir rPoly.mpImplPolygon->mnRefCount++;
1839cdf0e10cSrcweir
1840cdf0e10cSrcweir // Wenn es keine statischen ImpDaten sind, dann loeschen, wenn es
1841cdf0e10cSrcweir // die letzte Referenz ist, sonst Referenzcounter decrementieren
1842cdf0e10cSrcweir if ( mpImplPolygon->mnRefCount )
1843cdf0e10cSrcweir {
1844cdf0e10cSrcweir if ( mpImplPolygon->mnRefCount > 1 )
1845cdf0e10cSrcweir mpImplPolygon->mnRefCount--;
1846cdf0e10cSrcweir else
1847cdf0e10cSrcweir delete mpImplPolygon;
1848cdf0e10cSrcweir }
1849cdf0e10cSrcweir
1850cdf0e10cSrcweir mpImplPolygon = rPoly.mpImplPolygon;
1851cdf0e10cSrcweir return *this;
1852cdf0e10cSrcweir }
1853cdf0e10cSrcweir
1854cdf0e10cSrcweir // -----------------------------------------------------------------------
1855cdf0e10cSrcweir
operator ==(const Polygon & rPoly) const1856cdf0e10cSrcweir sal_Bool Polygon::operator==( const Polygon& rPoly ) const
1857cdf0e10cSrcweir {
1858cdf0e10cSrcweir DBG_CHKTHIS( Polygon, NULL );
1859cdf0e10cSrcweir DBG_CHKOBJ( &rPoly, Polygon, NULL );
1860cdf0e10cSrcweir
1861cdf0e10cSrcweir if ( (rPoly.mpImplPolygon == mpImplPolygon) )
1862cdf0e10cSrcweir return sal_True;
1863cdf0e10cSrcweir else
1864cdf0e10cSrcweir return sal_False;
1865cdf0e10cSrcweir }
1866cdf0e10cSrcweir
1867cdf0e10cSrcweir // -----------------------------------------------------------------------
1868cdf0e10cSrcweir
IsEqual(const Polygon & rPoly) const1869cdf0e10cSrcweir sal_Bool Polygon::IsEqual( const Polygon& rPoly ) const
1870cdf0e10cSrcweir {
1871cdf0e10cSrcweir sal_Bool bIsEqual = sal_True;;
1872cdf0e10cSrcweir sal_uInt16 i;
1873cdf0e10cSrcweir if ( GetSize() != rPoly.GetSize() )
1874cdf0e10cSrcweir bIsEqual = sal_False;
1875cdf0e10cSrcweir else
1876cdf0e10cSrcweir {
1877cdf0e10cSrcweir for ( i = 0; i < GetSize(); i++ )
1878cdf0e10cSrcweir {
1879cdf0e10cSrcweir if ( ( GetPoint( i ) != rPoly.GetPoint( i ) ) ||
1880cdf0e10cSrcweir ( GetFlags( i ) != rPoly.GetFlags( i ) ) )
1881cdf0e10cSrcweir {
1882cdf0e10cSrcweir bIsEqual = sal_False;
1883cdf0e10cSrcweir break;
1884cdf0e10cSrcweir }
1885cdf0e10cSrcweir }
1886cdf0e10cSrcweir }
1887cdf0e10cSrcweir return bIsEqual;
1888cdf0e10cSrcweir }
1889cdf0e10cSrcweir
1890cdf0e10cSrcweir // -----------------------------------------------------------------------
1891cdf0e10cSrcweir
operator >>(SvStream & rIStream,Polygon & rPoly)1892cdf0e10cSrcweir SvStream& operator>>( SvStream& rIStream, Polygon& rPoly )
1893cdf0e10cSrcweir {
1894cdf0e10cSrcweir DBG_CHKOBJ( &rPoly, Polygon, NULL );
1895cdf0e10cSrcweir DBG_ASSERTWARNING( rIStream.GetVersion(), "Polygon::>> - Solar-Version not set on rIStream" );
1896cdf0e10cSrcweir
1897cdf0e10cSrcweir sal_uInt16 i;
1898cdf0e10cSrcweir sal_uInt16 nStart;
1899cdf0e10cSrcweir sal_uInt16 nCurPoints;
1900cdf0e10cSrcweir sal_uInt16 nPoints;
1901cdf0e10cSrcweir unsigned char bShort;
1902cdf0e10cSrcweir short nShortX;
1903cdf0e10cSrcweir short nShortY;
1904cdf0e10cSrcweir long nLongX;
1905cdf0e10cSrcweir long nLongY;
1906cdf0e10cSrcweir
1907cdf0e10cSrcweir // Anzahl der Punkte einlesen und Array erzeugen
1908cdf0e10cSrcweir rIStream >> nPoints;
1909cdf0e10cSrcweir if ( rPoly.mpImplPolygon->mnRefCount != 1 )
1910cdf0e10cSrcweir {
1911cdf0e10cSrcweir if ( rPoly.mpImplPolygon->mnRefCount )
1912cdf0e10cSrcweir rPoly.mpImplPolygon->mnRefCount--;
1913cdf0e10cSrcweir rPoly.mpImplPolygon = new ImplPolygon( nPoints );
1914cdf0e10cSrcweir }
1915cdf0e10cSrcweir else
1916cdf0e10cSrcweir rPoly.mpImplPolygon->ImplSetSize( nPoints, sal_False );
1917cdf0e10cSrcweir
1918cdf0e10cSrcweir // Je nach CompressMode das Polygon einlesen
1919cdf0e10cSrcweir if ( rIStream.GetCompressMode() == COMPRESSMODE_FULL )
1920cdf0e10cSrcweir {
1921cdf0e10cSrcweir i = 0;
1922cdf0e10cSrcweir while ( i < nPoints )
1923cdf0e10cSrcweir {
1924cdf0e10cSrcweir rIStream >> bShort >> nCurPoints;
1925cdf0e10cSrcweir
1926cdf0e10cSrcweir if ( bShort )
1927cdf0e10cSrcweir {
1928cdf0e10cSrcweir for ( nStart = i; i < nStart+nCurPoints; i++ )
1929cdf0e10cSrcweir {
1930cdf0e10cSrcweir rIStream >> nShortX >> nShortY;
1931cdf0e10cSrcweir rPoly.mpImplPolygon->mpPointAry[i].X() = nShortX;
1932cdf0e10cSrcweir rPoly.mpImplPolygon->mpPointAry[i].Y() = nShortY;
1933cdf0e10cSrcweir }
1934cdf0e10cSrcweir }
1935cdf0e10cSrcweir else
1936cdf0e10cSrcweir {
1937cdf0e10cSrcweir for ( nStart = i; i < nStart+nCurPoints; i++ )
1938cdf0e10cSrcweir {
1939cdf0e10cSrcweir rIStream >> nLongX >> nLongY;
1940cdf0e10cSrcweir rPoly.mpImplPolygon->mpPointAry[i].X() = nLongX;
1941cdf0e10cSrcweir rPoly.mpImplPolygon->mpPointAry[i].Y() = nLongY;
1942cdf0e10cSrcweir }
1943cdf0e10cSrcweir }
1944cdf0e10cSrcweir }
1945cdf0e10cSrcweir }
1946cdf0e10cSrcweir else
1947cdf0e10cSrcweir {
1948cdf0e10cSrcweir // Feststellen, ob ueber die Operatoren geschrieben werden muss
1949cdf0e10cSrcweir #if (SAL_TYPES_SIZEOFLONG) != 4
1950cdf0e10cSrcweir if ( 1 )
1951cdf0e10cSrcweir #else
1952cdf0e10cSrcweir #ifdef OSL_BIGENDIAN
1953cdf0e10cSrcweir if ( rIStream.GetNumberFormatInt() != NUMBERFORMAT_INT_BIGENDIAN )
1954cdf0e10cSrcweir #else
1955cdf0e10cSrcweir if ( rIStream.GetNumberFormatInt() != NUMBERFORMAT_INT_LITTLEENDIAN )
1956cdf0e10cSrcweir #endif
1957cdf0e10cSrcweir #endif
1958cdf0e10cSrcweir {
1959cdf0e10cSrcweir for( i = 0; i < nPoints; i++ )
1960cdf0e10cSrcweir {
1961cdf0e10cSrcweir rIStream >> rPoly.mpImplPolygon->mpPointAry[i].X()
1962cdf0e10cSrcweir >> rPoly.mpImplPolygon->mpPointAry[i].Y();
1963cdf0e10cSrcweir }
1964cdf0e10cSrcweir }
1965cdf0e10cSrcweir else
1966cdf0e10cSrcweir rIStream.Read( rPoly.mpImplPolygon->mpPointAry, nPoints*sizeof(Point) );
1967cdf0e10cSrcweir }
1968cdf0e10cSrcweir
1969cdf0e10cSrcweir return rIStream;
1970cdf0e10cSrcweir }
1971cdf0e10cSrcweir
1972cdf0e10cSrcweir // -----------------------------------------------------------------------
1973cdf0e10cSrcweir
operator <<(SvStream & rOStream,const Polygon & rPoly)1974cdf0e10cSrcweir SvStream& operator<<( SvStream& rOStream, const Polygon& rPoly )
1975cdf0e10cSrcweir {
1976cdf0e10cSrcweir DBG_CHKOBJ( &rPoly, Polygon, NULL );
1977cdf0e10cSrcweir DBG_ASSERTWARNING( rOStream.GetVersion(), "Polygon::<< - Solar-Version not set on rOStream" );
1978cdf0e10cSrcweir
1979cdf0e10cSrcweir unsigned char bShort;
1980cdf0e10cSrcweir unsigned char bCurShort;
1981cdf0e10cSrcweir sal_uInt16 nStart;
1982cdf0e10cSrcweir sal_uInt16 i;
1983cdf0e10cSrcweir sal_uInt16 nPoints = rPoly.GetSize();
1984cdf0e10cSrcweir
1985cdf0e10cSrcweir // Anzahl der Punkte rausschreiben
1986cdf0e10cSrcweir rOStream << nPoints;
1987cdf0e10cSrcweir
1988cdf0e10cSrcweir // Je nach CompressMode das Polygon rausschreiben
1989cdf0e10cSrcweir if ( rOStream.GetCompressMode() == COMPRESSMODE_FULL )
1990cdf0e10cSrcweir {
1991cdf0e10cSrcweir i = 0;
1992cdf0e10cSrcweir while ( i < nPoints )
1993cdf0e10cSrcweir {
1994cdf0e10cSrcweir nStart = i;
1995cdf0e10cSrcweir
1996cdf0e10cSrcweir // Feststellen, welcher Typ geschrieben werden soll
1997cdf0e10cSrcweir if ( ((rPoly.mpImplPolygon->mpPointAry[nStart].X() >= SHRT_MIN) &&
1998cdf0e10cSrcweir (rPoly.mpImplPolygon->mpPointAry[nStart].X() <= SHRT_MAX)) &&
1999cdf0e10cSrcweir ((rPoly.mpImplPolygon->mpPointAry[nStart].Y() >= SHRT_MIN) &&
2000cdf0e10cSrcweir (rPoly.mpImplPolygon->mpPointAry[nStart].Y() <= SHRT_MAX)) )
2001cdf0e10cSrcweir bShort = sal_True;
2002cdf0e10cSrcweir else
2003cdf0e10cSrcweir bShort = sal_False;
2004cdf0e10cSrcweir while ( i < nPoints )
2005cdf0e10cSrcweir {
2006cdf0e10cSrcweir // Feststellen, welcher Typ geschrieben werden soll
2007cdf0e10cSrcweir if ( ((rPoly.mpImplPolygon->mpPointAry[nStart].X() >= SHRT_MIN) &&
2008cdf0e10cSrcweir (rPoly.mpImplPolygon->mpPointAry[nStart].X() <= SHRT_MAX)) &&
2009cdf0e10cSrcweir ((rPoly.mpImplPolygon->mpPointAry[nStart].Y() >= SHRT_MIN) &&
2010cdf0e10cSrcweir (rPoly.mpImplPolygon->mpPointAry[nStart].Y() <= SHRT_MAX)) )
2011cdf0e10cSrcweir bCurShort = sal_True;
2012cdf0e10cSrcweir else
2013cdf0e10cSrcweir bCurShort = sal_False;
2014cdf0e10cSrcweir
2015cdf0e10cSrcweir // Wenn sich die Werte in einen anderen Bereich begeben,
2016cdf0e10cSrcweir // muessen wir neu rausschreiben
2017cdf0e10cSrcweir if ( bCurShort != bShort )
2018cdf0e10cSrcweir {
2019cdf0e10cSrcweir bShort = bCurShort;
2020cdf0e10cSrcweir break;
2021cdf0e10cSrcweir }
2022cdf0e10cSrcweir
2023cdf0e10cSrcweir i++;
2024cdf0e10cSrcweir }
2025cdf0e10cSrcweir
2026cdf0e10cSrcweir rOStream << bShort << (sal_uInt16)(i-nStart);
2027cdf0e10cSrcweir
2028cdf0e10cSrcweir if ( bShort )
2029cdf0e10cSrcweir {
2030cdf0e10cSrcweir for( ; nStart < i; nStart++ )
2031cdf0e10cSrcweir {
2032cdf0e10cSrcweir rOStream << (short)rPoly.mpImplPolygon->mpPointAry[nStart].X()
2033cdf0e10cSrcweir << (short)rPoly.mpImplPolygon->mpPointAry[nStart].Y();
2034cdf0e10cSrcweir }
2035cdf0e10cSrcweir }
2036cdf0e10cSrcweir else
2037cdf0e10cSrcweir {
2038cdf0e10cSrcweir for( ; nStart < i; nStart++ )
2039cdf0e10cSrcweir {
2040cdf0e10cSrcweir rOStream << rPoly.mpImplPolygon->mpPointAry[nStart].X()
2041cdf0e10cSrcweir << rPoly.mpImplPolygon->mpPointAry[nStart].Y();
2042cdf0e10cSrcweir }
2043cdf0e10cSrcweir }
2044cdf0e10cSrcweir }
2045cdf0e10cSrcweir }
2046cdf0e10cSrcweir else
2047cdf0e10cSrcweir {
2048cdf0e10cSrcweir // Feststellen, ob ueber die Operatoren geschrieben werden muss
2049cdf0e10cSrcweir #if (SAL_TYPES_SIZEOFLONG) != 4
2050cdf0e10cSrcweir if ( 1 )
2051cdf0e10cSrcweir #else
2052cdf0e10cSrcweir #ifdef OSL_BIGENDIAN
2053cdf0e10cSrcweir if ( rOStream.GetNumberFormatInt() != NUMBERFORMAT_INT_BIGENDIAN )
2054cdf0e10cSrcweir #else
2055cdf0e10cSrcweir if ( rOStream.GetNumberFormatInt() != NUMBERFORMAT_INT_LITTLEENDIAN )
2056cdf0e10cSrcweir #endif
2057cdf0e10cSrcweir #endif
2058cdf0e10cSrcweir {
2059cdf0e10cSrcweir for( i = 0; i < nPoints; i++ )
2060cdf0e10cSrcweir {
2061cdf0e10cSrcweir rOStream << rPoly.mpImplPolygon->mpPointAry[i].X()
2062cdf0e10cSrcweir << rPoly.mpImplPolygon->mpPointAry[i].Y();
2063cdf0e10cSrcweir }
2064cdf0e10cSrcweir }
2065cdf0e10cSrcweir else
2066cdf0e10cSrcweir {
2067cdf0e10cSrcweir if ( nPoints )
2068cdf0e10cSrcweir rOStream.Write( rPoly.mpImplPolygon->mpPointAry, nPoints*sizeof(Point) );
2069cdf0e10cSrcweir }
2070cdf0e10cSrcweir }
2071cdf0e10cSrcweir
2072cdf0e10cSrcweir return rOStream;
2073cdf0e10cSrcweir }
2074cdf0e10cSrcweir
2075cdf0e10cSrcweir // -----------------------------------------------------------------------
2076cdf0e10cSrcweir
ImplRead(SvStream & rIStream)2077cdf0e10cSrcweir void Polygon::ImplRead( SvStream& rIStream )
2078cdf0e10cSrcweir {
2079cdf0e10cSrcweir sal_uInt8 bHasPolyFlags;
2080cdf0e10cSrcweir
2081cdf0e10cSrcweir rIStream >> *this
2082cdf0e10cSrcweir >> bHasPolyFlags;
2083cdf0e10cSrcweir
2084cdf0e10cSrcweir if ( bHasPolyFlags )
2085cdf0e10cSrcweir {
2086cdf0e10cSrcweir mpImplPolygon->mpFlagAry = new sal_uInt8[ mpImplPolygon->mnPoints ];
2087cdf0e10cSrcweir rIStream.Read( mpImplPolygon->mpFlagAry, mpImplPolygon->mnPoints );
2088cdf0e10cSrcweir }
2089cdf0e10cSrcweir }
2090cdf0e10cSrcweir
2091cdf0e10cSrcweir // -----------------------------------------------------------------------
2092cdf0e10cSrcweir
Read(SvStream & rIStream)2093cdf0e10cSrcweir void Polygon::Read( SvStream& rIStream )
2094cdf0e10cSrcweir {
2095cdf0e10cSrcweir VersionCompat aCompat( rIStream, STREAM_READ );
2096cdf0e10cSrcweir
2097cdf0e10cSrcweir ImplRead( rIStream );
2098cdf0e10cSrcweir }
2099cdf0e10cSrcweir
2100cdf0e10cSrcweir // -----------------------------------------------------------------------
2101cdf0e10cSrcweir
ImplWrite(SvStream & rOStream) const2102cdf0e10cSrcweir void Polygon::ImplWrite( SvStream& rOStream ) const
2103cdf0e10cSrcweir {
2104cdf0e10cSrcweir sal_uInt8 bHasPolyFlags = mpImplPolygon->mpFlagAry != NULL;
2105cdf0e10cSrcweir rOStream << *this
2106cdf0e10cSrcweir << bHasPolyFlags;
2107cdf0e10cSrcweir
2108cdf0e10cSrcweir if ( bHasPolyFlags )
2109cdf0e10cSrcweir rOStream.Write( mpImplPolygon->mpFlagAry, mpImplPolygon->mnPoints );
2110cdf0e10cSrcweir }
2111cdf0e10cSrcweir
2112cdf0e10cSrcweir // -----------------------------------------------------------------------
2113cdf0e10cSrcweir
Write(SvStream & rOStream) const2114cdf0e10cSrcweir void Polygon::Write( SvStream& rOStream ) const
2115cdf0e10cSrcweir {
2116cdf0e10cSrcweir VersionCompat aCompat( rOStream, STREAM_WRITE, 1 );
2117cdf0e10cSrcweir
2118cdf0e10cSrcweir ImplWrite( rOStream );
2119cdf0e10cSrcweir }
2120cdf0e10cSrcweir
2121cdf0e10cSrcweir // -----------------------------------------------------------------------
212212315255SArmin Le Grand // numerical correction method for B2DPolygon
impCorrectContinuity(basegfx::B2DPolygon & roPolygon,sal_uInt32 nIndex,sal_uInt8 nCFlag)2123cdf0e10cSrcweir void impCorrectContinuity(basegfx::B2DPolygon& roPolygon, sal_uInt32 nIndex, sal_uInt8 nCFlag)
2124cdf0e10cSrcweir {
2125cdf0e10cSrcweir const sal_uInt32 nPointCount(roPolygon.count());
2126cdf0e10cSrcweir OSL_ENSURE(nIndex < nPointCount, "impCorrectContinuity: index access out of range (!)");
2127cdf0e10cSrcweir
2128cdf0e10cSrcweir if(nIndex < nPointCount && (POLY_SMOOTH == nCFlag || POLY_SYMMTR == nCFlag))
2129cdf0e10cSrcweir {
2130cdf0e10cSrcweir if(roPolygon.isPrevControlPointUsed(nIndex) && roPolygon.isNextControlPointUsed(nIndex))
2131cdf0e10cSrcweir {
213212315255SArmin Le Grand // #115917# Patch from osnola (modified, thanks for showing the porblem)
213312315255SArmin Le Grand //
213412315255SArmin Le Grand // The correction is needed because an integer polygon with control points
213512315255SArmin Le Grand // is converted to double precision. When C1 or C2 is used the involved vectors
213612315255SArmin Le Grand // may not have the same directions/lengths since these come from integer coordinates
213712315255SArmin Le Grand // and may have been snapped to different nearest integer coordinates. The snap error
213812315255SArmin Le Grand // is in the range of +-1 in y and y, thus 0.0 <= error <= sqrt(2.0). Nonetheless,
213912315255SArmin Le Grand // it needs to be corrected to be able to detect the continuity in this points
214012315255SArmin Le Grand // correctly.
214112315255SArmin Le Grand //
214212315255SArmin Le Grand // We only have the integer data here (already in double precision form, but no mantisses
214312315255SArmin Le Grand // used), so the best correction is to use:
214412315255SArmin Le Grand //
214512315255SArmin Le Grand // for C1: The longest vector since it potentially has best preserved the original vector.
214612315255SArmin Le Grand // Even better the sum of the vectors, weighted by their length. This gives the
214712315255SArmin Le Grand // normal vector addition to get the vector itself, lengths need to be preserved.
214812315255SArmin Le Grand // for C2: The mediated vector(s) since both should be the same, but mirrored
214912315255SArmin Le Grand
215012315255SArmin Le Grand // extract the point and vectors
2151cdf0e10cSrcweir const basegfx::B2DPoint aPoint(roPolygon.getB2DPoint(nIndex));
215212315255SArmin Le Grand const basegfx::B2DVector aNext(roPolygon.getNextControlPoint(nIndex) - aPoint);
215312315255SArmin Le Grand const basegfx::B2DVector aPrev(aPoint - roPolygon.getPrevControlPoint(nIndex));
215412315255SArmin Le Grand
215512315255SArmin Le Grand // calculate common direction vector, normalize
215612315255SArmin Le Grand const basegfx::B2DVector aDirection(aNext + aPrev);
2157cdf0e10cSrcweir
2158cdf0e10cSrcweir if(POLY_SMOOTH == nCFlag)
2159cdf0e10cSrcweir {
216012315255SArmin Le Grand // C1: apply common direction vector, preserve individual lengths
216112315255SArmin Le Grand const double fInvDirectionLen(1.0 / aDirection.getLength());
216212315255SArmin Le Grand roPolygon.setNextControlPoint(nIndex, basegfx::B2DPoint(aPoint + (aDirection * (aNext.getLength() * fInvDirectionLen))));
216312315255SArmin Le Grand roPolygon.setPrevControlPoint(nIndex, basegfx::B2DPoint(aPoint - (aDirection * (aPrev.getLength() * fInvDirectionLen))));
2164cdf0e10cSrcweir }
2165cdf0e10cSrcweir else // POLY_SYMMTR
2166cdf0e10cSrcweir {
216712315255SArmin Le Grand // C2: get mediated length. Taking half of the unnormalized direction would be
216812315255SArmin Le Grand // an approximation, but not correct.
216912315255SArmin Le Grand const double fMedLength((aNext.getLength() + aPrev.getLength()) * (0.5 / aDirection.getLength()));
217012315255SArmin Le Grand const basegfx::B2DVector aScaledDirection(aDirection * fMedLength);
217112315255SArmin Le Grand
217212315255SArmin Le Grand // Bring Direction to correct length and apply
217312315255SArmin Le Grand roPolygon.setNextControlPoint(nIndex, basegfx::B2DPoint(aPoint + aScaledDirection));
217412315255SArmin Le Grand roPolygon.setPrevControlPoint(nIndex, basegfx::B2DPoint(aPoint - aScaledDirection));
2175cdf0e10cSrcweir }
2176cdf0e10cSrcweir }
2177cdf0e10cSrcweir }
2178cdf0e10cSrcweir }
2179cdf0e10cSrcweir
2180cdf0e10cSrcweir // -----------------------------------------------------------------------
2181cdf0e10cSrcweir // convert to basegfx::B2DPolygon and return
getB2DPolygon() const2182cdf0e10cSrcweir basegfx::B2DPolygon Polygon::getB2DPolygon() const
2183cdf0e10cSrcweir {
2184cdf0e10cSrcweir basegfx::B2DPolygon aRetval;
2185cdf0e10cSrcweir const sal_uInt16 nCount(mpImplPolygon->mnPoints);
2186cdf0e10cSrcweir
2187cdf0e10cSrcweir if(nCount)
2188cdf0e10cSrcweir {
2189cdf0e10cSrcweir if(mpImplPolygon->mpFlagAry)
2190cdf0e10cSrcweir {
2191cdf0e10cSrcweir // handling for curves. Add start point
2192cdf0e10cSrcweir const Point aStartPoint(mpImplPolygon->mpPointAry[0]);
2193cdf0e10cSrcweir sal_uInt8 nPointFlag(mpImplPolygon->mpFlagAry[0]);
2194cdf0e10cSrcweir aRetval.append(basegfx::B2DPoint(aStartPoint.X(), aStartPoint.Y()));
2195cdf0e10cSrcweir Point aControlA, aControlB;
2196cdf0e10cSrcweir
2197cdf0e10cSrcweir for(sal_uInt16 a(1); a < nCount;)
2198cdf0e10cSrcweir {
2199cdf0e10cSrcweir bool bControlA(false);
2200cdf0e10cSrcweir bool bControlB(false);
2201cdf0e10cSrcweir
2202cdf0e10cSrcweir if(POLY_CONTROL == mpImplPolygon->mpFlagAry[a])
2203cdf0e10cSrcweir {
2204cdf0e10cSrcweir aControlA = mpImplPolygon->mpPointAry[a++];
2205cdf0e10cSrcweir bControlA = true;
2206cdf0e10cSrcweir }
2207cdf0e10cSrcweir
2208cdf0e10cSrcweir if(a < nCount && POLY_CONTROL == mpImplPolygon->mpFlagAry[a])
2209cdf0e10cSrcweir {
2210cdf0e10cSrcweir aControlB = mpImplPolygon->mpPointAry[a++];
2211cdf0e10cSrcweir bControlB = true;
2212cdf0e10cSrcweir }
2213cdf0e10cSrcweir
2214cdf0e10cSrcweir // assert invalid polygons
2215cdf0e10cSrcweir OSL_ENSURE(bControlA == bControlB, "Polygon::getB2DPolygon: Invalid source polygon (!)");
2216cdf0e10cSrcweir
2217cdf0e10cSrcweir if(a < nCount)
2218cdf0e10cSrcweir {
2219cdf0e10cSrcweir const Point aEndPoint(mpImplPolygon->mpPointAry[a]);
2220cdf0e10cSrcweir
2221cdf0e10cSrcweir if(bControlA)
2222cdf0e10cSrcweir {
2223cdf0e10cSrcweir // bezier edge, add
2224cdf0e10cSrcweir aRetval.appendBezierSegment(
2225cdf0e10cSrcweir basegfx::B2DPoint(aControlA.X(), aControlA.Y()),
2226cdf0e10cSrcweir basegfx::B2DPoint(aControlB.X(), aControlB.Y()),
2227cdf0e10cSrcweir basegfx::B2DPoint(aEndPoint.X(), aEndPoint.Y()));
2228cdf0e10cSrcweir
2229cdf0e10cSrcweir impCorrectContinuity(aRetval, aRetval.count() - 2, nPointFlag);
2230cdf0e10cSrcweir }
2231cdf0e10cSrcweir else
2232cdf0e10cSrcweir {
2233cdf0e10cSrcweir // no bezier edge, add end point
2234cdf0e10cSrcweir aRetval.append(basegfx::B2DPoint(aEndPoint.X(), aEndPoint.Y()));
2235cdf0e10cSrcweir }
2236cdf0e10cSrcweir
2237cdf0e10cSrcweir nPointFlag = mpImplPolygon->mpFlagAry[a++];
2238cdf0e10cSrcweir }
2239cdf0e10cSrcweir }
2240cdf0e10cSrcweir
2241cdf0e10cSrcweir // if exist, remove double first/last points, set closed and correct control points
2242cdf0e10cSrcweir basegfx::tools::checkClosed(aRetval);
2243cdf0e10cSrcweir
2244cdf0e10cSrcweir if(aRetval.isClosed())
2245cdf0e10cSrcweir {
2246cdf0e10cSrcweir // closeWithGeometryChange did really close, so last point(s) were removed.
2247cdf0e10cSrcweir // Correct the continuity in the changed point
2248cdf0e10cSrcweir impCorrectContinuity(aRetval, 0, mpImplPolygon->mpFlagAry[0]);
2249cdf0e10cSrcweir }
2250cdf0e10cSrcweir }
2251cdf0e10cSrcweir else
2252cdf0e10cSrcweir {
2253cdf0e10cSrcweir // extra handling for non-curves (most-used case) for speedup
2254cdf0e10cSrcweir for(sal_uInt16 a(0); a < nCount; a++)
2255cdf0e10cSrcweir {
2256cdf0e10cSrcweir // get point and add
2257cdf0e10cSrcweir const Point aPoint(mpImplPolygon->mpPointAry[a]);
2258cdf0e10cSrcweir aRetval.append(basegfx::B2DPoint(aPoint.X(), aPoint.Y()));
2259cdf0e10cSrcweir }
2260cdf0e10cSrcweir
2261cdf0e10cSrcweir // set closed flag
2262cdf0e10cSrcweir basegfx::tools::checkClosed(aRetval);
2263cdf0e10cSrcweir }
2264cdf0e10cSrcweir }
2265cdf0e10cSrcweir
2266cdf0e10cSrcweir return aRetval;
2267cdf0e10cSrcweir }
2268cdf0e10cSrcweir
2269cdf0e10cSrcweir // -----------------------------------------------------------------------
2270cdf0e10cSrcweir // constructor to convert from basegfx::B2DPolygon
2271cdf0e10cSrcweir // #i76891# Needed to change from adding all control points (even for unused
2272cdf0e10cSrcweir // edges) and creating a fixed-size Polygon in the first run to creating the
2273cdf0e10cSrcweir // minimal Polygon. This requires a temporary Point- and Flag-Array for curves
2274cdf0e10cSrcweir // and a memcopy at ImplPolygon creation, but contains no zero-controlpoints
2275cdf0e10cSrcweir // for straight edges.
Polygon(const basegfx::B2DPolygon & rPolygon)2276cdf0e10cSrcweir Polygon::Polygon(const basegfx::B2DPolygon& rPolygon)
2277cdf0e10cSrcweir : mpImplPolygon(0)
2278cdf0e10cSrcweir {
2279cdf0e10cSrcweir DBG_CTOR( Polygon, NULL );
2280cdf0e10cSrcweir
2281cdf0e10cSrcweir const bool bCurve(rPolygon.areControlPointsUsed());
2282cdf0e10cSrcweir const bool bClosed(rPolygon.isClosed());
2283cdf0e10cSrcweir sal_uInt32 nB2DLocalCount(rPolygon.count());
2284cdf0e10cSrcweir
2285cdf0e10cSrcweir if(bCurve)
2286cdf0e10cSrcweir {
2287cdf0e10cSrcweir // #127979# Reduce source point count hard to the limit of the tools Polygon
2288cdf0e10cSrcweir if(nB2DLocalCount > ((0x0000ffff / 3L) - 1L))
2289cdf0e10cSrcweir {
2290cdf0e10cSrcweir DBG_ERROR("Polygon::Polygon: Too many points in given B2DPolygon, need to reduce hard to maximum of tools Polygon (!)");
2291cdf0e10cSrcweir nB2DLocalCount = ((0x0000ffff / 3L) - 1L);
2292cdf0e10cSrcweir }
2293cdf0e10cSrcweir
2294cdf0e10cSrcweir // calculate target point count
2295cdf0e10cSrcweir const sal_uInt32 nLoopCount(bClosed ? nB2DLocalCount : (nB2DLocalCount ? nB2DLocalCount - 1L : 0L ));
2296cdf0e10cSrcweir
2297cdf0e10cSrcweir if(nLoopCount)
2298cdf0e10cSrcweir {
2299cdf0e10cSrcweir // calculate maximum array size and allocate; prepare insert index
2300cdf0e10cSrcweir const sal_uInt32 nMaxTargetCount((nLoopCount * 3) + 1);
2301cdf0e10cSrcweir mpImplPolygon = new ImplPolygon(static_cast< sal_uInt16 >(nMaxTargetCount), true);
2302cdf0e10cSrcweir
2303cdf0e10cSrcweir // prepare insert index and current point
2304cdf0e10cSrcweir sal_uInt32 nArrayInsert(0);
2305cdf0e10cSrcweir basegfx::B2DCubicBezier aBezier;
2306cdf0e10cSrcweir aBezier.setStartPoint(rPolygon.getB2DPoint(0));
2307cdf0e10cSrcweir
2308cdf0e10cSrcweir for(sal_uInt32 a(0L); a < nLoopCount; a++)
2309cdf0e10cSrcweir {
2310cdf0e10cSrcweir // add current point (always) and remember StartPointIndex for evtl. later corrections
2311cdf0e10cSrcweir const Point aStartPoint(FRound(aBezier.getStartPoint().getX()), FRound(aBezier.getStartPoint().getY()));
2312cdf0e10cSrcweir const sal_uInt32 nStartPointIndex(nArrayInsert);
2313cdf0e10cSrcweir mpImplPolygon->mpPointAry[nStartPointIndex] = aStartPoint;
2314cdf0e10cSrcweir mpImplPolygon->mpFlagAry[nStartPointIndex] = (sal_uInt8)POLY_NORMAL;
2315cdf0e10cSrcweir nArrayInsert++;
2316cdf0e10cSrcweir
2317cdf0e10cSrcweir // prepare next segment
2318cdf0e10cSrcweir const sal_uInt32 nNextIndex((a + 1) % nB2DLocalCount);
2319cdf0e10cSrcweir aBezier.setEndPoint(rPolygon.getB2DPoint(nNextIndex));
2320cdf0e10cSrcweir aBezier.setControlPointA(rPolygon.getNextControlPoint(a));
2321cdf0e10cSrcweir aBezier.setControlPointB(rPolygon.getPrevControlPoint(nNextIndex));
2322cdf0e10cSrcweir
2323cdf0e10cSrcweir if(aBezier.isBezier())
2324cdf0e10cSrcweir {
2325cdf0e10cSrcweir // if one is used, add always two control points due to the old schema
2326cdf0e10cSrcweir mpImplPolygon->mpPointAry[nArrayInsert] = Point(FRound(aBezier.getControlPointA().getX()), FRound(aBezier.getControlPointA().getY()));
2327cdf0e10cSrcweir mpImplPolygon->mpFlagAry[nArrayInsert] = (sal_uInt8)POLY_CONTROL;
2328cdf0e10cSrcweir nArrayInsert++;
2329cdf0e10cSrcweir
2330cdf0e10cSrcweir mpImplPolygon->mpPointAry[nArrayInsert] = Point(FRound(aBezier.getControlPointB().getX()), FRound(aBezier.getControlPointB().getY()));
2331cdf0e10cSrcweir mpImplPolygon->mpFlagAry[nArrayInsert] = (sal_uInt8)POLY_CONTROL;
2332cdf0e10cSrcweir nArrayInsert++;
2333cdf0e10cSrcweir }
2334cdf0e10cSrcweir
2335cdf0e10cSrcweir // test continuity with previous control point to set flag value
2336cdf0e10cSrcweir if(aBezier.getControlPointA() != aBezier.getStartPoint() && (bClosed || a))
2337cdf0e10cSrcweir {
2338cdf0e10cSrcweir const basegfx::B2VectorContinuity eCont(rPolygon.getContinuityInPoint(a));
2339cdf0e10cSrcweir
2340cdf0e10cSrcweir if(basegfx::CONTINUITY_C1 == eCont)
2341cdf0e10cSrcweir {
2342cdf0e10cSrcweir mpImplPolygon->mpFlagAry[nStartPointIndex] = (sal_uInt8)POLY_SMOOTH;
2343cdf0e10cSrcweir }
2344cdf0e10cSrcweir else if(basegfx::CONTINUITY_C2 == eCont)
2345cdf0e10cSrcweir {
2346cdf0e10cSrcweir mpImplPolygon->mpFlagAry[nStartPointIndex] = (sal_uInt8)POLY_SYMMTR;
2347cdf0e10cSrcweir }
2348cdf0e10cSrcweir }
2349cdf0e10cSrcweir
2350cdf0e10cSrcweir // prepare next polygon step
2351cdf0e10cSrcweir aBezier.setStartPoint(aBezier.getEndPoint());
2352cdf0e10cSrcweir }
2353cdf0e10cSrcweir
2354cdf0e10cSrcweir if(bClosed)
2355cdf0e10cSrcweir {
2356cdf0e10cSrcweir // add first point again as closing point due to old definition
2357cdf0e10cSrcweir mpImplPolygon->mpPointAry[nArrayInsert] = mpImplPolygon->mpPointAry[0];
2358cdf0e10cSrcweir mpImplPolygon->mpFlagAry[nArrayInsert] = (sal_uInt8)POLY_NORMAL;
2359cdf0e10cSrcweir nArrayInsert++;
2360cdf0e10cSrcweir }
2361cdf0e10cSrcweir else
2362cdf0e10cSrcweir {
2363cdf0e10cSrcweir // add last point as closing point
2364cdf0e10cSrcweir const basegfx::B2DPoint aClosingPoint(rPolygon.getB2DPoint(nB2DLocalCount - 1L));
2365cdf0e10cSrcweir const Point aEnd(FRound(aClosingPoint.getX()), FRound(aClosingPoint.getY()));
2366cdf0e10cSrcweir mpImplPolygon->mpPointAry[nArrayInsert] = aEnd;
2367cdf0e10cSrcweir mpImplPolygon->mpFlagAry[nArrayInsert] = (sal_uInt8)POLY_NORMAL;
2368cdf0e10cSrcweir nArrayInsert++;
2369cdf0e10cSrcweir }
2370cdf0e10cSrcweir
2371cdf0e10cSrcweir DBG_ASSERT(nArrayInsert <= nMaxTargetCount, "Polygon::Polygon from basegfx::B2DPolygon: wrong max point count estimation (!)");
2372cdf0e10cSrcweir
2373cdf0e10cSrcweir if(nArrayInsert != nMaxTargetCount)
2374cdf0e10cSrcweir {
2375cdf0e10cSrcweir mpImplPolygon->ImplSetSize(static_cast< sal_uInt16 >(nArrayInsert), true);
2376cdf0e10cSrcweir }
2377cdf0e10cSrcweir }
2378cdf0e10cSrcweir }
2379cdf0e10cSrcweir else
2380cdf0e10cSrcweir {
2381cdf0e10cSrcweir // #127979# Reduce source point count hard to the limit of the tools Polygon
2382cdf0e10cSrcweir if(nB2DLocalCount > (0x0000ffff - 1L))
2383cdf0e10cSrcweir {
2384cdf0e10cSrcweir DBG_ERROR("Polygon::Polygon: Too many points in given B2DPolygon, need to reduce hard to maximum of tools Polygon (!)");
2385cdf0e10cSrcweir nB2DLocalCount = (0x0000ffff - 1L);
2386cdf0e10cSrcweir }
2387cdf0e10cSrcweir
2388cdf0e10cSrcweir if(nB2DLocalCount)
2389cdf0e10cSrcweir {
2390cdf0e10cSrcweir // point list creation
2391cdf0e10cSrcweir const sal_uInt32 nTargetCount(nB2DLocalCount + (bClosed ? 1L : 0L));
2392cdf0e10cSrcweir mpImplPolygon = new ImplPolygon( static_cast< sal_uInt16 >(nTargetCount) );
2393cdf0e10cSrcweir sal_uInt16 nIndex(0);
2394cdf0e10cSrcweir
2395cdf0e10cSrcweir for(sal_uInt32 a(0L); a < nB2DLocalCount; a++)
2396cdf0e10cSrcweir {
2397cdf0e10cSrcweir basegfx::B2DPoint aB2DPoint(rPolygon.getB2DPoint(a));
2398cdf0e10cSrcweir Point aPoint(FRound(aB2DPoint.getX()), FRound(aB2DPoint.getY()));
2399cdf0e10cSrcweir mpImplPolygon->mpPointAry[nIndex++] = aPoint;
2400cdf0e10cSrcweir }
2401cdf0e10cSrcweir
2402cdf0e10cSrcweir if(bClosed)
2403cdf0e10cSrcweir {
2404cdf0e10cSrcweir // add first point as closing point
2405cdf0e10cSrcweir mpImplPolygon->mpPointAry[nIndex] = mpImplPolygon->mpPointAry[0];
2406cdf0e10cSrcweir }
2407cdf0e10cSrcweir }
2408cdf0e10cSrcweir }
2409cdf0e10cSrcweir
2410cdf0e10cSrcweir if(!mpImplPolygon)
2411cdf0e10cSrcweir {
2412cdf0e10cSrcweir // no content yet, create empty polygon
2413cdf0e10cSrcweir mpImplPolygon = (ImplPolygon*)(&aStaticImplPolygon);
2414cdf0e10cSrcweir }
2415cdf0e10cSrcweir }
2416cdf0e10cSrcweir
2417cdf0e10cSrcweir // eof
2418