1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: region.cxx,v $
10 * $Revision: 1.18.36.1 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_vcl.hxx"
35 #include <tools/vcompat.hxx>
36 #include <vcl/salbtype.hxx>
37 #include <tools/stream.hxx>
38 #include <tools/debug.hxx>
40 #include <vcl/region.h>
43 #include <vcl/region.hxx>
46 #include <vcl/regband.hxx>
49 #include <basegfx/matrix/b2dhommatrix.hxx>
50 #include <basegfx/polygon/b2dpolypolygontools.hxx>
51 #include <basegfx/range/b2drange.hxx>
53 // =======================================================================
57 // Die Klassen RegionBand/ImplRegionBand speichert Regionen in Form von
58 // Rechtecken ab. Die Region ist in Y-Richtung in Baendern unterteilt, die
59 // wiederum ein oder mehrere Rechtecke mit der Hoehe des Bandes enthalten.
61 // Leere Baender werden entfernt.
63 // Polygone und PolyPolygone werden ebenfalls in Rechtecke zerlegt und in
64 // der Baendern abgelegt. Hierzu werden alle Punkte der einzelnen Polygone
65 // mit dem Bresenham-Algorithmus berechnet und in die Baender eingetragen.
66 // Nach der vollstaendigen Berechung aller Kanten werden die entsprechenden
67 // Rechntecke berechnet
69 // =======================================================================
71 static ImplRegionBase
aImplNullRegion( 0 );
72 static ImplRegionBase
aImplEmptyRegion( 0 );
74 // =======================================================================
78 DBG_NAMEEX( PolyPolygon
)
82 /** Return <TRUE/> when the given polygon is rectiliner and oriented so that
83 all sides are either horizontal or vertical.
85 bool ImplIsPolygonRectilinear (const PolyPolygon
& rPolyPoly
)
87 // Iterate over all polygons.
88 const USHORT nPolyCount
= rPolyPoly
.Count();
89 for (USHORT nPoly
= 0; nPoly
< nPolyCount
; ++nPoly
)
91 const Polygon
& aPoly
= rPolyPoly
.GetObject(nPoly
);
93 // Iterate over all edges of the current polygon.
94 const USHORT nSize
= aPoly
.GetSize();
98 Point
aPoint (aPoly
.GetPoint(0));
99 const Point
aLastPoint (aPoint
);
100 for (USHORT nPoint
= 1; nPoint
< nSize
; ++nPoint
)
102 const Point
aNextPoint (aPoly
.GetPoint(nPoint
));
103 // When there is at least one edge that is neither vertical nor
104 // horizontal then the entire polygon is not rectilinear (and
105 // oriented along primary axes.)
106 if (aPoint
.X() != aNextPoint
.X() && aPoint
.Y() != aNextPoint
.Y())
111 // Compare closing edge.
112 if (aLastPoint
.X() != aPoint
.X() && aLastPoint
.Y() != aPoint
.Y())
120 /** This function is similar to the ImplRegion::InsertBands() method.
121 It creates a minimal set of missing bands so that the entire vertical
122 interval from nTop to nBottom is covered by bands.
124 void ImplAddMissingBands (
125 ImplRegion
* pImplRegion
,
129 // Iterate over already existing bands and add missing bands atop the
130 // first and between two bands.
131 ImplRegionBand
* pPreviousBand
= NULL
;
132 ImplRegionBand
* pBand
= pImplRegion
->ImplGetFirstRegionBand();
133 long nCurrentTop (nTop
);
134 while (pBand
!= NULL
&& nCurrentTop
<nBottom
)
136 if (nCurrentTop
< pBand
->mnYTop
)
138 // Create new band above the current band.
139 ImplRegionBand
* pAboveBand
= new ImplRegionBand(
141 ::std::min(nBottom
,pBand
->mnYTop
-1));
142 pImplRegion
->InsertBand(pPreviousBand
, pAboveBand
);
145 // Adapt the top of the interval to prevent overlapping bands.
146 nCurrentTop
= ::std::max(nTop
, pBand
->mnYBottom
+1);
148 // Advance to next band.
149 pPreviousBand
= pBand
;
150 pBand
= pBand
->mpNextBand
;
153 // We still have to cover two cases:
154 // 1. The region does not yet contain any bands.
155 // 2. The intervall nTop->nBottom extends past the bottom most band.
156 if (nCurrentTop
< nBottom
&& (pBand
==NULL
|| nBottom
>pBand
->mnYBottom
))
158 // When there is no previous band then the new one will be the
159 // first. Otherwise the new band is inserted behind the last band.
160 pImplRegion
->InsertBand(
170 /** Convert a rectilinear polygon (that is oriented along the primary axes)
171 to a list of bands. For this special form of polygon we can use an
172 optimization that prevents the creation of one band per y value.
173 However, it still is possible that some temporary bands are created that
174 later can be optimized away.
176 A set of zero, one, or more polygons, nested or not, that are
177 converted into a list of bands.
179 A new ImplRegion object is returned that contains the bands that
180 represent the given poly-polygon.
182 ImplRegion
* ImplRectilinearPolygonToBands (const PolyPolygon
& rPolyPoly
)
184 OSL_ASSERT(ImplIsPolygonRectilinear (rPolyPoly
));
186 // Create a new ImplRegion object as container of the bands.
187 ImplRegion
* pImplRegion
= new ImplRegion();
190 // Iterate over all polygons.
191 const USHORT nPolyCount
= rPolyPoly
.Count();
192 for (USHORT nPoly
= 0; nPoly
< nPolyCount
; ++nPoly
)
194 const Polygon
& aPoly
= rPolyPoly
.GetObject(nPoly
);
196 // Iterate over all edges of the current polygon.
197 const USHORT nSize
= aPoly
.GetSize();
200 // Avoid fetching every point twice (each point is the start point
201 // of one and the end point of another edge.)
202 Point
aStart (aPoly
.GetPoint(0));
204 for (USHORT nPoint
= 1; nPoint
<= nSize
; ++nPoint
, aStart
=aEnd
)
206 // We take the implicit closing edge into account by mapping
208 aEnd
= aPoly
.GetPoint(nPoint
%nSize
);
209 if (aStart
.Y() == aEnd
.Y())
211 // Horizontal lines are ignored.
215 // At this point the line has to be vertical.
216 OSL_ASSERT(aStart
.X() == aEnd
.X());
218 // Sort y-coordinates to simplify the algorithm and store the
219 // direction seperately. The direction is calculated as it is
220 // in other places (but seems to be the wrong way.)
221 const long nTop (::std::min(aStart
.Y(), aEnd
.Y()));
222 const long nBottom (::std::max(aStart
.Y(), aEnd
.Y()));
223 const LineType
eLineType (aStart
.Y() > aEnd
.Y() ? LINE_DESCENDING
: LINE_ASCENDING
);
225 // Make sure that the current line is covered by bands.
226 ImplAddMissingBands(pImplRegion
, nTop
,nBottom
);
228 // Find top-most band that may contain nTop.
229 ImplRegionBand
* pBand
= pImplRegion
->ImplGetFirstRegionBand();
230 while (pBand
!=NULL
&& pBand
->mnYBottom
< nTop
)
231 pBand
= pBand
->mpNextBand
;
232 ImplRegionBand
* pTopBand
= pBand
;
233 // If necessary split the band at nTop so that nTop is contained
234 // in the lower band.
235 if ( // Prevent the current band from becoming 0 pixel high
237 // this allows the lowest pixel of the band to be split off
238 && pBand
->mnYBottom
>=nTop
239 // do not split a band that is just one pixel high
240 && pBand
->mnYTop
<pBand
->mnYBottom
)
242 // Split the top band.
243 pTopBand
= pBand
->SplitBand(nTop
);
246 // Advance to band that may contain nBottom.
247 while (pBand
!=NULL
&& pBand
->mnYBottom
< nBottom
)
248 pBand
= pBand
->mpNextBand
;
249 // The lowest band may have to be split at nBottom so that
250 // nBottom itself remains in the upper band.
251 if ( // allow the current band becoming 1 pixel high
252 pBand
->mnYTop
<=nBottom
253 // prevent splitting off a band that is 0 pixel high
254 && pBand
->mnYBottom
>nBottom
255 // do not split a band that is just one pixel high
256 && pBand
->mnYTop
<pBand
->mnYBottom
)
258 // Split the bottom band.
259 pBand
->SplitBand(nBottom
+1);
262 // Note that we remember the top band (in pTopBand) but not the
263 // bottom band. The later can be determined by comparing y
266 // Add the x-value as point to all bands in the nTop->nBottom range.
267 for (pBand
=pTopBand
; pBand
!=NULL
&&pBand
->mnYTop
<=nBottom
; pBand
=pBand
->mpNextBand
)
268 pBand
->InsertPoint(aStart
.X(), nLineId
++, TRUE
, eLineType
);
278 /** Convert a general polygon (one for which ImplIsPolygonRectilinear()
279 returns <FALSE/>) to bands.
281 ImplRegion
* ImplGeneralPolygonToBands (
282 const PolyPolygon
& rPolyPoly
,
283 const Rectangle
& rPolygonBoundingBox
)
287 // initialisation and creation of Bands
288 ImplRegion
* pImplRegion
= new ImplRegion();
289 pImplRegion
->CreateBandRange( rPolygonBoundingBox
.Top(), rPolygonBoundingBox
.Bottom() );
292 const USHORT nPolyCount
= rPolyPoly
.Count();
293 for ( USHORT nPoly
= 0; nPoly
< nPolyCount
; nPoly
++ )
295 // get reference to current polygon
296 const Polygon
& aPoly
= rPolyPoly
.GetObject( nPoly
);
297 const USHORT nSize
= aPoly
.GetSize();
299 // not enough points ( <= 2 )? -> nothing to do!
304 for ( USHORT nPoint
= 1; nPoint
< nSize
; nPoint
++ )
305 pImplRegion
->InsertLine( aPoly
.GetPoint(nPoint
-1), aPoly
.GetPoint(nPoint
), nLineID
++ );
307 // close polygon with line from first point to last point, if neccesary
308 const Point rLastPoint
= aPoly
.GetPoint(nSize
-1);
309 const Point rFirstPoint
= aPoly
.GetPoint(0);
310 if ( rLastPoint
!= rFirstPoint
)
311 pImplRegion
->InsertLine( rLastPoint
, rFirstPoint
, nLineID
++ );
318 } // end of anonymous namespace
321 // -----------------------------------------------------------------------
324 const char* ImplDbgTestRegion( const void* pObj
)
326 Region
* pRegion
= (Region
*)pObj
;
327 ImplRegion
* pImplRegion
= pRegion
->ImplGetImplRegion();
329 if ( aImplNullRegion
.mnRefCount
)
330 return "Null-Region-RefCount modified";
331 if ( aImplNullRegion
.mnRectCount
)
332 return "Null-Region-RectCount modified";
333 if ( aImplNullRegion
.mpPolyPoly
)
334 return "Null-Region-PolyPoly modified";
335 if ( aImplEmptyRegion
.mnRefCount
)
336 return "Emptry-Region-RefCount modified";
337 if ( aImplEmptyRegion
.mnRectCount
)
338 return "Emptry-Region-RectCount modified";
339 if ( aImplEmptyRegion
.mpPolyPoly
)
340 return "Emptry-Region-PolyPoly modified";
342 if ( (pImplRegion
!= &aImplEmptyRegion
) && (pImplRegion
!= &aImplNullRegion
) )
345 const ImplRegionBand
* pBand
= pImplRegion
->ImplGetFirstRegionBand();
348 if ( pBand
->mnYBottom
< pBand
->mnYTop
)
349 return "YBottom < YTop";
350 if ( pBand
->mpNextBand
)
352 if ( pBand
->mnYBottom
>= pBand
->mpNextBand
->mnYTop
)
353 return "overlapping bands in region";
355 if ( pBand
->mbTouched
> 1 )
356 return "Band-mbTouched overwrite";
358 ImplRegionBandSep
* pSep
= pBand
->mpFirstSep
;
361 if ( pSep
->mnXRight
< pSep
->mnXLeft
)
362 return "XLeft < XRight";
363 if ( pSep
->mpNextSep
)
365 if ( pSep
->mnXRight
>= pSep
->mpNextSep
->mnXLeft
)
366 return "overlapping separations in region";
368 if ( pSep
->mbRemoved
> 1 )
369 return "Sep-mbRemoved overwrite";
372 pSep
= pSep
->mpNextSep
;
375 pBand
= pBand
->mpNextBand
;
378 if ( pImplRegion
->mnRectCount
!= nCount
)
379 return "mnRetCount is not valid";
385 void TraceBands (const ImplRegionBand
* pFirstBand
)
388 const ImplRegionBand
* pBand
= pFirstBand
;
389 while (pBand
!= NULL
)
391 OSL_TRACE(" band %d %d->%d : ", nBandIndex
++,
392 pBand
->mnYTop
, pBand
->mnYBottom
);
394 ImplRegionBandPoint
* pPoint
= pBand
->mpFirstBandPoint
;
395 while (pPoint
!= NULL
)
397 OSL_TRACE(" %d ", pPoint
->mnX
);
398 pPoint
= pPoint
->mpNextBandPoint
;
402 ImplRegionBandSep
* pSep
= pBand
->mpFirstSep
;
405 OSL_TRACE(" %d->%d ", pSep
->mnXLeft
, pSep
->mnXRight
);
406 pSep
= pSep
->mpNextSep
;
410 pBand
= pBand
->mpNextBand
;
415 // =======================================================================
417 inline void Region::ImplPolyPolyRegionToBandRegion()
419 if( mpImplRegion
->mpPolyPoly
|| mpImplRegion
->mpB2DPolyPoly
)
420 ImplPolyPolyRegionToBandRegionFunc();
423 // =======================================================================
425 ImplRegionBase::ImplRegionBase( int nRefCount
)
426 : mnRefCount( nRefCount
)
429 , mpB2DPolyPoly( NULL
)
432 // ------------------------------------------------------------------------
434 ImplRegion::ImplRegion()
437 mpLastCheckedBand
= NULL
;
440 // ------------------------------------------------------------------------
442 ImplRegion::ImplRegion( const PolyPolygon
& rPolyPoly
)
445 mpLastCheckedBand
= NULL
;
446 mpPolyPoly
= new PolyPolygon( rPolyPoly
);
449 // ------------------------------------------------------------------------
451 ImplRegion::ImplRegion( const basegfx::B2DPolyPolygon
& rPolyPoly
)
454 mpLastCheckedBand
= NULL
;
455 mpB2DPolyPoly
= new basegfx::B2DPolyPolygon( rPolyPoly
);
458 // -----------------------------------------------------------------------
460 ImplRegion::ImplRegion( const ImplRegion
& rImplRegion
)
464 mpLastCheckedBand
= NULL
;
465 mnRectCount
= rImplRegion
.mnRectCount
;
467 if ( rImplRegion
.mpPolyPoly
)
468 mpPolyPoly
= new PolyPolygon( *rImplRegion
.mpPolyPoly
);
469 else if( rImplRegion
.mpB2DPolyPoly
)
470 mpB2DPolyPoly
= new basegfx::B2DPolyPolygon( *rImplRegion
.mpB2DPolyPoly
);
472 // insert band(s) into the list
473 ImplRegionBand
* pNewBand
;
474 ImplRegionBand
* pPrevBand
= 0;
475 ImplRegionBand
* pBand
= rImplRegion
.mpFirstBand
;
478 pNewBand
= new ImplRegionBand( *pBand
);
480 // first element? -> set as first into the list
481 if ( pBand
== rImplRegion
.mpFirstBand
)
482 mpFirstBand
= pNewBand
;
484 pPrevBand
->mpNextBand
= pNewBand
;
486 pPrevBand
= pNewBand
;
487 pBand
= pBand
->mpNextBand
;
491 // -----------------------------------------------------------------------
493 ImplRegion::~ImplRegion()
495 DBG_ASSERT( (this != &aImplEmptyRegion
) && (this != &aImplNullRegion
),
496 "ImplRegion::~ImplRegion() - Empty oder NULL-Region" );
498 ImplRegionBand
* pBand
= mpFirstBand
;
501 ImplRegionBand
* pTempBand
= pBand
->mpNextBand
;
507 // -----------------------------------------------------------------------
509 ImplRegionBase::~ImplRegionBase()
512 delete mpB2DPolyPoly
;
515 // -----------------------------------------------------------------------
517 // create complete range of bands in single steps
519 void ImplRegion::CreateBandRange( long nYTop
, long nYBottom
)
522 mpFirstBand
= new ImplRegionBand( nYTop
-1, nYTop
-1 );
524 // begin first search from the first element
525 mpLastCheckedBand
= mpFirstBand
;
527 ImplRegionBand
* pBand
= mpFirstBand
;
528 for ( int i
= nYTop
; i
<= nYBottom
+1; i
++ )
531 ImplRegionBand
* pNewBand
= new ImplRegionBand( i
, i
);
532 pBand
->mpNextBand
= pNewBand
;
533 if ( pBand
!= mpFirstBand
)
534 pNewBand
->mpPrevBand
= pBand
;
536 pBand
= pBand
->mpNextBand
;
540 // -----------------------------------------------------------------------
542 BOOL
ImplRegion::InsertLine( const Point
& rStartPt
, const Point
& rEndPt
,
547 // lines consisting of a single point do not interest here
548 if ( rStartPt
== rEndPt
)
551 LineType eLineType
= (rStartPt
.Y() > rEndPt
.Y()) ? LINE_DESCENDING
: LINE_ASCENDING
;
552 if ( rStartPt
.X() == rEndPt
.X() )
555 const long nEndY
= rEndPt
.Y();
562 for ( ; nY
<= nEndY
; nY
++ )
564 Point
aNewPoint( nX
, nY
);
565 InsertPoint( aNewPoint
, nLineId
,
566 (aNewPoint
== rEndPt
) || (aNewPoint
== rStartPt
),
572 for ( ; nY
>= nEndY
; nY
-- )
574 Point
aNewPoint( nX
, nY
);
575 InsertPoint( aNewPoint
, nLineId
,
576 (aNewPoint
== rEndPt
) || (aNewPoint
== rStartPt
),
581 else if ( rStartPt
.Y() != rEndPt
.Y() )
583 const long nDX
= labs( rEndPt
.X() - rStartPt
.X() );
584 const long nDY
= labs( rEndPt
.Y() - rStartPt
.Y() );
585 const long nStartX
= rStartPt
.X();
586 const long nStartY
= rStartPt
.Y();
587 const long nEndX
= rEndPt
.X();
588 const long nEndY
= rEndPt
.Y();
589 const long nXInc
= ( nStartX
< nEndX
) ? 1L : -1L;
590 const long nYInc
= ( nStartY
< nEndY
) ? 1L : -1L;
594 const long nDYX
= ( nDY
- nDX
) << 1;
595 const long nDY2
= nDY
<< 1;
596 long nD
= nDY2
- nDX
;
598 for ( nX
= nStartX
, nY
= nStartY
; nX
!= nEndX
; nX
+= nXInc
)
600 InsertPoint( Point( nX
, nY
), nLineId
, nStartX
== nX
, eLineType
);
605 nD
+= nDYX
, nY
+= nYInc
;
610 const long nDYX
= ( nDX
- nDY
) << 1;
611 const long nDY2
= nDX
<< 1;
612 long nD
= nDY2
- nDY
;
614 for ( nX
= nStartX
, nY
= nStartY
; nY
!= nEndY
; nY
+= nYInc
)
616 InsertPoint( Point( nX
, nY
), nLineId
, nStartY
== nY
, eLineType
);
621 nD
+= nDYX
, nX
+= nXInc
;
626 InsertPoint( Point( nEndX
, nEndY
), nLineId
, TRUE
, eLineType
);
632 // -----------------------------------------------------------------------
634 // search for appropriate place for the new point
636 BOOL
ImplRegion::InsertPoint( const Point
&rPoint
, long nLineID
,
637 BOOL bEndPoint
, LineType eLineType
)
639 DBG_ASSERT( mpFirstBand
!= NULL
, "ImplRegion::InsertPoint - no bands available!" );
641 if ( rPoint
.Y() == mpLastCheckedBand
->mnYTop
)
643 mpLastCheckedBand
->InsertPoint( rPoint
.X(), nLineID
, bEndPoint
, eLineType
);
647 if ( rPoint
.Y() > mpLastCheckedBand
->mnYTop
)
650 while ( mpLastCheckedBand
)
652 // Insert point if possible
653 if ( rPoint
.Y() == mpLastCheckedBand
->mnYTop
)
655 mpLastCheckedBand
->InsertPoint( rPoint
.X(), nLineID
, bEndPoint
, eLineType
);
659 mpLastCheckedBand
= mpLastCheckedBand
->mpNextBand
;
662 DBG_ERROR( "ImplRegion::InsertPoint reached the end of the list!" );
667 while ( mpLastCheckedBand
)
669 // Insert point if possible
670 if ( rPoint
.Y() == mpLastCheckedBand
->mnYTop
)
672 mpLastCheckedBand
->InsertPoint( rPoint
.X(), nLineID
, bEndPoint
, eLineType
);
676 mpLastCheckedBand
= mpLastCheckedBand
->mpPrevBand
;
679 DBG_ERROR( "ImplRegion::InsertPoint reached the beginning of the list!" );
682 DBG_ERROR( "ImplRegion::InsertPoint point not inserted!" );
684 // reinitialize pointer (should never be reached!)
685 mpLastCheckedBand
= mpFirstBand
;
690 // -----------------------------------------------------------------------
692 // search for appropriate places for the new bands
694 void ImplRegion::InsertBands( long nTop
, long nBottom
)
696 // region empty? -> set rectagle as first entry!
699 // add band with boundaries of the rectangle
700 mpFirstBand
= new ImplRegionBand( nTop
, nBottom
);
704 // find/insert bands for the boundaries of the rectangle
705 BOOL bTopBoundaryInserted
= FALSE
;
706 BOOL bTop2BoundaryInserted
= FALSE
;
707 BOOL bBottomBoundaryInserted
= FALSE
;
709 // special case: top boundary is above the first band
710 ImplRegionBand
* pNewBand
;
711 if ( nTop
< mpFirstBand
->mnYTop
)
713 // create new band above the first in the list
714 pNewBand
= new ImplRegionBand( nTop
, mpFirstBand
->mnYTop
);
715 if ( nBottom
< mpFirstBand
->mnYTop
)
716 pNewBand
->mnYBottom
= nBottom
;
718 // insert band into the list
719 pNewBand
->mpNextBand
= mpFirstBand
;
720 mpFirstBand
= pNewBand
;
722 bTopBoundaryInserted
= TRUE
;
725 // insert band(s) into the list
726 ImplRegionBand
* pBand
= mpFirstBand
;
729 // Insert Bands if possible
730 if ( !bTopBoundaryInserted
)
731 bTopBoundaryInserted
= InsertSingleBand( pBand
, nTop
- 1 );
733 if ( !bTop2BoundaryInserted
)
734 bTop2BoundaryInserted
= InsertSingleBand( pBand
, nTop
);
736 if ( !bBottomBoundaryInserted
&& (nTop
!= nBottom
) )
737 bBottomBoundaryInserted
= InsertSingleBand( pBand
, nBottom
);
739 // both boundaries inserted? -> nothing more to do
740 if ( bTopBoundaryInserted
&& bTop2BoundaryInserted
&& bBottomBoundaryInserted
)
743 // insert bands between two bands if neccessary
744 if ( pBand
->mpNextBand
)
746 if ( (pBand
->mnYBottom
+ 1) < pBand
->mpNextBand
->mnYTop
)
748 // copy band with list and set new boundary
749 pNewBand
= new ImplRegionBand( pBand
->mnYBottom
+1,
750 pBand
->mpNextBand
->mnYTop
-1 );
752 // insert band into the list
753 pNewBand
->mpNextBand
= pBand
->mpNextBand
;
754 pBand
->mpNextBand
= pNewBand
;
758 pBand
= pBand
->mpNextBand
;
762 // -----------------------------------------------------------------------
764 // create new band and insert it into the list
766 BOOL
ImplRegion::InsertSingleBand( ImplRegionBand
* pBand
,
767 long nYBandPosition
)
769 // boundary already included in band with height 1? -> nothing to do!
770 if ( (pBand
->mnYTop
== pBand
->mnYBottom
) &&
771 (nYBandPosition
== pBand
->mnYTop
) )
774 // insert single height band on top?
775 ImplRegionBand
* pNewBand
;
776 if ( nYBandPosition
== pBand
->mnYTop
)
778 // copy band with list and set new boundary
779 pNewBand
= new ImplRegionBand( *pBand
);
780 pNewBand
->mnYTop
= nYBandPosition
+1;
782 // insert band into the list
783 pNewBand
->mpNextBand
= pBand
->mpNextBand
;
784 pBand
->mnYBottom
= nYBandPosition
;
785 pBand
->mpNextBand
= pNewBand
;
790 // top of new rectangle within the current band? -> insert new band and copy data
791 if ( (nYBandPosition
> pBand
->mnYTop
) &&
792 (nYBandPosition
< pBand
->mnYBottom
) )
794 // copy band with list and set new boundary
795 pNewBand
= new ImplRegionBand( *pBand
);
796 pNewBand
->mnYTop
= nYBandPosition
;
798 // insert band into the list
799 pNewBand
->mpNextBand
= pBand
->mpNextBand
;
800 pBand
->mnYBottom
= nYBandPosition
;
801 pBand
->mpNextBand
= pNewBand
;
803 // copy band with list and set new boundary
804 pNewBand
= new ImplRegionBand( *pBand
);
805 pNewBand
->mnYTop
= nYBandPosition
;
807 // insert band into the list
808 pBand
->mpNextBand
->mnYTop
= nYBandPosition
+1;
810 pNewBand
->mpNextBand
= pBand
->mpNextBand
;
811 pBand
->mnYBottom
= nYBandPosition
- 1;
812 pBand
->mpNextBand
= pNewBand
;
817 // create new band behind the current in the list
818 if ( !pBand
->mpNextBand
)
820 if ( nYBandPosition
== pBand
->mnYBottom
)
822 // copy band with list and set new boundary
823 pNewBand
= new ImplRegionBand( *pBand
);
824 pNewBand
->mnYTop
= pBand
->mnYBottom
;
825 pNewBand
->mnYBottom
= nYBandPosition
;
827 pBand
->mnYBottom
= nYBandPosition
-1;
829 // append band to the list
830 pBand
->mpNextBand
= pNewBand
;
834 if ( nYBandPosition
> pBand
->mnYBottom
)
837 pNewBand
= new ImplRegionBand( pBand
->mnYBottom
+ 1, nYBandPosition
);
839 // append band to the list
840 pBand
->mpNextBand
= pNewBand
;
848 // ------------------------------------------------------------------------
850 void ImplRegion::InsertBand (ImplRegionBand
* pPreviousBand
, ImplRegionBand
* pBandToInsert
)
852 OSL_ASSERT(pBandToInsert
!=NULL
);
854 if (pPreviousBand
== NULL
)
856 // Insert band before all others.
857 if (mpFirstBand
!= NULL
)
858 mpFirstBand
->mpPrevBand
= pBandToInsert
;
859 pBandToInsert
->mpNextBand
= mpFirstBand
;
860 mpFirstBand
= pBandToInsert
;
864 // Insert band directly after pPreviousBand.
865 pBandToInsert
->mpNextBand
= pPreviousBand
->mpNextBand
;
866 pPreviousBand
->mpNextBand
= pBandToInsert
;
867 pBandToInsert
->mpPrevBand
= pPreviousBand
;
871 // ------------------------------------------------------------------------
873 void ImplRegion::Union( long nLeft
, long nTop
, long nRight
, long nBottom
)
875 DBG_ASSERT( nLeft
<= nRight
, "ImplRegion::Union() - nLeft > nRight" );
876 DBG_ASSERT( nTop
<= nBottom
, "ImplRegion::Union() - nTop > nBottom" );
879 ImplRegionBand
* pBand
= mpFirstBand
;
882 if ( pBand
->mnYTop
>= nTop
)
884 if ( pBand
->mnYBottom
<= nBottom
)
885 pBand
->Union( nLeft
, nRight
);
889 long nCurY
= pBand
->mnYBottom
;
890 pBand
= pBand
->mpNextBand
;
893 if ( (pBand
->mnYTop
< nCurY
) || (pBand
->mnYBottom
< nCurY
) )
895 DBG_ERROR( "ImplRegion::Union() - Bands not sorted!" );
897 pBand
= pBand
->mpNextBand
;
904 pBand
= pBand
->mpNextBand
;
908 // -----------------------------------------------------------------------
910 void ImplRegion::Exclude( long nLeft
, long nTop
, long nRight
, long nBottom
)
912 DBG_ASSERT( nLeft
<= nRight
, "ImplRegion::Exclude() - nLeft > nRight" );
913 DBG_ASSERT( nTop
<= nBottom
, "ImplRegion::Exclude() - nTop > nBottom" );
916 ImplRegionBand
* pBand
= mpFirstBand
;
919 if ( pBand
->mnYTop
>= nTop
)
921 if ( pBand
->mnYBottom
<= nBottom
)
922 pBand
->Exclude( nLeft
, nRight
);
926 long nCurY
= pBand
->mnYBottom
;
927 pBand
= pBand
->mpNextBand
;
930 if ( (pBand
->mnYTop
< nCurY
) || (pBand
->mnYBottom
< nCurY
) )
932 DBG_ERROR( "ImplRegion::Exclude() - Bands not sorted!" );
934 pBand
= pBand
->mpNextBand
;
941 pBand
= pBand
->mpNextBand
;
945 // -----------------------------------------------------------------------
947 void ImplRegion::XOr( long nLeft
, long nTop
, long nRight
, long nBottom
)
949 DBG_ASSERT( nLeft
<= nRight
, "ImplRegion::Exclude() - nLeft > nRight" );
950 DBG_ASSERT( nTop
<= nBottom
, "ImplRegion::Exclude() - nTop > nBottom" );
953 ImplRegionBand
* pBand
= mpFirstBand
;
956 if ( pBand
->mnYTop
>= nTop
)
958 if ( pBand
->mnYBottom
<= nBottom
)
959 pBand
->XOr( nLeft
, nRight
);
963 long nCurY
= pBand
->mnYBottom
;
964 pBand
= pBand
->mpNextBand
;
967 if ( (pBand
->mnYTop
< nCurY
) || (pBand
->mnYBottom
< nCurY
) )
969 DBG_ERROR( "ImplRegion::XOr() - Bands not sorted!" );
971 pBand
= pBand
->mpNextBand
;
978 pBand
= pBand
->mpNextBand
;
982 // -----------------------------------------------------------------------
984 // remove empty bands
986 BOOL
ImplRegion::OptimizeBandList()
988 DBG_ASSERT( (this != &aImplNullRegion
) && (this != &aImplEmptyRegion
),
989 "ImplRegion::OptimizeBandList() - Empty oder NULL-Region" );
993 ImplRegionBand
* pPrevBand
= 0;
994 ImplRegionBand
* pBand
= mpFirstBand
;
997 const BOOL bBTEqual
= pBand
->mpNextBand
&&
998 (pBand
->mnYBottom
== pBand
->mpNextBand
->mnYTop
);
1000 // no separation? -> remove!
1001 if ( pBand
->IsEmpty() || (bBTEqual
&& (pBand
->mnYBottom
== pBand
->mnYTop
)) )
1004 ImplRegionBand
* pOldBand
= pBand
;
1006 // previous element of the list
1007 if ( pBand
== mpFirstBand
)
1008 mpFirstBand
= pBand
->mpNextBand
;
1010 pPrevBand
->mpNextBand
= pBand
->mpNextBand
;
1012 pBand
= pBand
->mpNextBand
;
1019 pBand
->mnYBottom
= pBand
->mpNextBand
->mnYTop
-1;
1021 // this and next band with equal separations? -> combine!
1022 if ( pBand
->mpNextBand
&&
1023 ((pBand
->mnYBottom
+1) == pBand
->mpNextBand
->mnYTop
) &&
1024 (*pBand
== *pBand
->mpNextBand
) )
1026 // expand current height
1027 pBand
->mnYBottom
= pBand
->mpNextBand
->mnYBottom
;
1029 // remove next band from list
1030 ImplRegionBand
* pDeletedBand
= pBand
->mpNextBand
;
1031 pBand
->mpNextBand
= pDeletedBand
->mpNextBand
;
1032 delete pDeletedBand
;
1034 // check band again!
1038 // count rectangles within band
1039 ImplRegionBandSep
* pSep
= pBand
->mpFirstSep
;
1043 pSep
= pSep
->mpNextSep
;
1047 pBand
= pBand
->mpNextBand
;
1053 pBand
= mpFirstBand
;
1056 DBG_ASSERT( pBand
->mpFirstSep
!= NULL
,
1057 "Exiting ImplRegion::OptimizeBandList(): empty band in region!" );
1059 if ( pBand
->mnYBottom
< pBand
->mnYTop
)
1060 DBG_ERROR( "ImplRegion::OptimizeBandList(): YBottomBoundary < YTopBoundary" );
1062 if ( pBand
->mpNextBand
)
1064 if ( pBand
->mnYBottom
>= pBand
->mpNextBand
->mnYTop
)
1065 DBG_ERROR( "ImplRegion::OptimizeBandList(): overlapping bands in region!" );
1068 pBand
= pBand
->mpNextBand
;
1072 return (mnRectCount
!= 0);
1075 // =======================================================================
1077 void Region::ImplCopyData()
1079 mpImplRegion
->mnRefCount
--;
1080 mpImplRegion
= new ImplRegion( *mpImplRegion
);
1083 // =======================================================================
1087 DBG_CTOR( Region
, ImplDbgTestRegion
);
1089 mpImplRegion
= (ImplRegion
*)(&aImplEmptyRegion
);
1092 // -----------------------------------------------------------------------
1094 Region::Region( RegionType eType
)
1096 DBG_CTOR( Region
, ImplDbgTestRegion
);
1097 DBG_ASSERT( (eType
== REGION_NULL
) || (eType
== REGION_EMPTY
),
1098 "Region( RegionType ) - RegionType != EMPTY/NULL" );
1100 if ( eType
== REGION_NULL
)
1101 mpImplRegion
= (ImplRegion
*)(&aImplNullRegion
);
1103 mpImplRegion
= (ImplRegion
*)(&aImplEmptyRegion
);
1106 // -----------------------------------------------------------------------
1108 Region::Region( const Rectangle
& rRect
)
1110 DBG_CTOR( Region
, ImplDbgTestRegion
);
1112 ImplCreateRectRegion( rRect
);
1115 // -----------------------------------------------------------------------
1117 Region::Region( const Polygon
& rPolygon
)
1119 DBG_CTOR( Region
, ImplDbgTestRegion
);
1120 DBG_CHKOBJ( &rPolygon
, Polygon
, NULL
);
1122 ImplCreatePolyPolyRegion( rPolygon
);
1125 // -----------------------------------------------------------------------
1127 Region::Region( const PolyPolygon
& rPolyPoly
)
1129 DBG_CTOR( Region
, ImplDbgTestRegion
);
1130 DBG_CHKOBJ( &rPolyPoly
, PolyPolygon
, NULL
);
1132 ImplCreatePolyPolyRegion( rPolyPoly
);
1135 // -----------------------------------------------------------------------
1137 Region::Region( const basegfx::B2DPolyPolygon
& rPolyPoly
)
1139 DBG_CTOR( Region
, ImplDbgTestRegion
);
1140 DBG_CHKOBJ( &rPolyPoly
, PolyPolygon
, NULL
);
1142 mpImplRegion
= new ImplRegion( rPolyPoly
);
1145 // -----------------------------------------------------------------------
1147 Region::Region( const Region
& rRegion
)
1149 DBG_CTOR( Region
, ImplDbgTestRegion
);
1150 DBG_CHKOBJ( &rRegion
, Region
, ImplDbgTestRegion
);
1151 DBG_ASSERT( rRegion
.mpImplRegion
->mnRefCount
< 0xFFFFFFFE, "Region: RefCount overflow" );
1153 // copy pointer to instance of implementation
1154 mpImplRegion
= rRegion
.mpImplRegion
;
1155 if ( mpImplRegion
->mnRefCount
)
1156 mpImplRegion
->mnRefCount
++;
1159 // -----------------------------------------------------------------------
1163 DBG_DTOR( Region
, ImplDbgTestRegion
);
1165 // statische Object haben RefCount von 0
1166 if ( mpImplRegion
->mnRefCount
)
1168 if ( mpImplRegion
->mnRefCount
> 1 )
1169 mpImplRegion
->mnRefCount
--;
1171 delete mpImplRegion
;
1175 // -----------------------------------------------------------------------
1177 void Region::ImplCreateRectRegion( const Rectangle
& rRect
)
1179 if ( rRect
.IsEmpty() )
1180 mpImplRegion
= (ImplRegion
*)(&aImplEmptyRegion
);
1183 // get justified rectangle
1184 long nTop
= Min( rRect
.Top(), rRect
.Bottom() );
1185 long nBottom
= Max( rRect
.Top(), rRect
.Bottom() );
1186 long nLeft
= Min( rRect
.Left(), rRect
.Right() );
1187 long nRight
= Max( rRect
.Left(), rRect
.Right() );
1189 // create instance of implementation class
1190 mpImplRegion
= new ImplRegion();
1192 // add band with boundaries of the rectangle
1193 mpImplRegion
->mpFirstBand
= new ImplRegionBand( nTop
, nBottom
);
1195 // Set left and right boundaries of the band
1196 mpImplRegion
->mpFirstBand
->Union( nLeft
, nRight
);
1197 mpImplRegion
->mnRectCount
= 1;
1201 // -----------------------------------------------------------------------
1203 void Region::ImplCreatePolyPolyRegion( const PolyPolygon
& rPolyPoly
)
1205 const USHORT nPolyCount
= rPolyPoly
.Count();
1208 // polypolygon empty? -> empty region
1209 const Rectangle
aRect( rPolyPoly
.GetBoundRect() );
1211 if ( !aRect
.IsEmpty() )
1213 // width OR height == 1 ? => Rectangular region
1214 if ( (aRect
.GetWidth() == 1)
1215 || (aRect
.GetHeight() == 1)
1216 || rPolyPoly
.IsRect() )
1218 ImplCreateRectRegion( aRect
);
1221 mpImplRegion
= new ImplRegion( rPolyPoly
);
1224 mpImplRegion
= (ImplRegion
*)(&aImplEmptyRegion
);
1227 mpImplRegion
= (ImplRegion
*)(&aImplEmptyRegion
);
1230 // -----------------------------------------------------------------------
1232 void Region::ImplPolyPolyRegionToBandRegionFunc()
1234 // ensure to subdivide when bezier segemnts are used, it's going to
1235 // be expanded to rectangles
1236 PolyPolygon aPolyPoly
;
1237 GetPolyPolygon().AdaptiveSubdivide(aPolyPoly
);
1239 if ( mpImplRegion
->mnRefCount
> 1 )
1240 mpImplRegion
->mnRefCount
--;
1242 delete mpImplRegion
;
1244 if ( aPolyPoly
.Count() )
1246 // polypolygon empty? -> empty region
1247 const Rectangle
aRect( aPolyPoly
.GetBoundRect() );
1249 if ( !aRect
.IsEmpty() )
1251 if (ImplIsPolygonRectilinear(aPolyPoly
))
1253 // For rectilinear polygons there is an optimized band conversion.
1254 mpImplRegion
= ImplRectilinearPolygonToBands(aPolyPoly
);
1258 mpImplRegion
= ImplGeneralPolygonToBands(aPolyPoly
, aRect
);
1261 // Convert points into seps.
1262 ImplRegionBand
* pRegionBand
= mpImplRegion
->mpFirstBand
;
1263 while ( pRegionBand
)
1265 // generate separations from the lines and process union
1266 pRegionBand
->ProcessPoints();
1267 pRegionBand
= pRegionBand
->mpNextBand
;
1270 // Optimize list of bands. Adjacent bands with identical lists
1271 // of seps are joined.
1272 if ( !mpImplRegion
->OptimizeBandList() )
1274 delete mpImplRegion
;
1275 mpImplRegion
= (ImplRegion
*)(&aImplEmptyRegion
);
1279 mpImplRegion
= (ImplRegion
*)(&aImplEmptyRegion
);
1282 mpImplRegion
= (ImplRegion
*)(&aImplEmptyRegion
);
1285 // -----------------------------------------------------------------------
1287 void Region::Move( long nHorzMove
, long nVertMove
)
1289 DBG_CHKTHIS( Region
, ImplDbgTestRegion
);
1291 // no region data? -> nothing to do
1292 if ( (mpImplRegion
== &aImplEmptyRegion
) || (mpImplRegion
== &aImplNullRegion
) )
1295 // no own instance data? -> make own copy!
1296 if ( mpImplRegion
->mnRefCount
> 1 )
1299 if ( mpImplRegion
->mpPolyPoly
)
1300 mpImplRegion
->mpPolyPoly
->Move( nHorzMove
, nVertMove
);
1301 else if( mpImplRegion
->mpB2DPolyPoly
)
1303 ::basegfx::B2DHomMatrix aTransform
;
1304 aTransform
.translate( nHorzMove
, nVertMove
);
1305 mpImplRegion
->mpB2DPolyPoly
->transform( aTransform
);
1309 ImplRegionBand
* pBand
= mpImplRegion
->mpFirstBand
;
1312 // process the vertical move
1313 if ( nVertMove
!= 0)
1315 pBand
->mnYTop
= pBand
->mnYTop
+ nVertMove
;
1316 pBand
->mnYBottom
= pBand
->mnYBottom
+ nVertMove
;
1319 // process the horizontal move
1320 if ( nHorzMove
!= 0)
1321 pBand
->MoveX( nHorzMove
);
1323 pBand
= pBand
->mpNextBand
;
1328 // -----------------------------------------------------------------------
1330 void Region::Scale( double fScaleX
, double fScaleY
)
1332 DBG_CHKTHIS( Region
, ImplDbgTestRegion
);
1334 // no region data? -> nothing to do
1335 if ( (mpImplRegion
== &aImplEmptyRegion
) || (mpImplRegion
== &aImplNullRegion
) )
1338 // no own instance data? -> make own copy!
1339 if ( mpImplRegion
->mnRefCount
> 1 )
1342 if ( mpImplRegion
->mpPolyPoly
)
1343 mpImplRegion
->mpPolyPoly
->Scale( fScaleX
, fScaleY
);
1344 else if( mpImplRegion
->mpB2DPolyPoly
)
1346 ::basegfx::B2DHomMatrix aTransform
;
1347 aTransform
.scale( fScaleX
, fScaleY
);
1348 mpImplRegion
->mpB2DPolyPoly
->transform( aTransform
);
1352 ImplRegionBand
* pBand
= mpImplRegion
->mpFirstBand
;
1355 // process the vertical move
1356 if ( fScaleY
!= 0.0 )
1358 pBand
->mnYTop
= FRound( pBand
->mnYTop
* fScaleY
);
1359 pBand
->mnYBottom
= FRound( pBand
->mnYBottom
* fScaleY
);
1362 // process the horizontal move
1363 if ( fScaleX
!= 0.0 )
1364 pBand
->ScaleX( fScaleX
);
1366 pBand
= pBand
->mpNextBand
;
1371 // -----------------------------------------------------------------------
1373 BOOL
Region::Union( const Rectangle
& rRect
)
1375 DBG_CHKTHIS( Region
, ImplDbgTestRegion
);
1377 // is rectangle empty? -> nothing to do
1378 if ( rRect
.IsEmpty() )
1381 ImplPolyPolyRegionToBandRegion();
1383 // no instance data? -> create!
1384 if ( (mpImplRegion
== &aImplEmptyRegion
) || (mpImplRegion
== &aImplNullRegion
) )
1385 mpImplRegion
= new ImplRegion();
1387 // no own instance data? -> make own copy!
1388 if ( mpImplRegion
->mnRefCount
> 1 )
1391 // get justified rectangle
1392 long nLeft
= Min( rRect
.Left(), rRect
.Right() );
1393 long nTop
= Min( rRect
.Top(), rRect
.Bottom() );
1394 long nRight
= Max( rRect
.Left(), rRect
.Right() );
1395 long nBottom
= Max( rRect
.Top(), rRect
.Bottom() );
1397 // insert bands if the boundaries are not allready in the list
1398 mpImplRegion
->InsertBands( nTop
, nBottom
);
1401 mpImplRegion
->Union( nLeft
, nTop
, nRight
, nBottom
);
1404 if ( !mpImplRegion
->OptimizeBandList() )
1406 delete mpImplRegion
;
1407 mpImplRegion
= (ImplRegion
*)(&aImplEmptyRegion
);
1413 // -----------------------------------------------------------------------
1415 BOOL
Region::Intersect( const Rectangle
& rRect
)
1417 DBG_CHKTHIS( Region
, ImplDbgTestRegion
);
1419 // is rectangle empty? -> nothing to do
1420 if ( rRect
.IsEmpty() )
1422 // statische Object haben RefCount von 0
1423 if ( mpImplRegion
->mnRefCount
)
1425 if ( mpImplRegion
->mnRefCount
> 1 )
1426 mpImplRegion
->mnRefCount
--;
1428 delete mpImplRegion
;
1430 mpImplRegion
= (ImplRegion
*)(&aImplEmptyRegion
);
1434 // #103137# Avoid banding for special cases
1435 if ( mpImplRegion
->mpPolyPoly
)
1437 // #127431# make ImplRegion unique, if not already.
1438 if( mpImplRegion
->mnRefCount
> 1 )
1440 mpImplRegion
->mnRefCount
--;
1441 mpImplRegion
= new ImplRegion( *mpImplRegion
->mpPolyPoly
);
1444 // use the PolyPolygon::Clip method for rectangles, this is
1445 // fairly simple (does not even use GPC) and saves us from
1446 // unnecessary banding
1447 mpImplRegion
->mpPolyPoly
->Clip( rRect
);
1452 ImplPolyPolyRegionToBandRegion();
1454 // is region empty? -> nothing to do!
1455 if ( mpImplRegion
== &aImplEmptyRegion
)
1458 // get justified rectangle
1459 long nLeft
= Min( rRect
.Left(), rRect
.Right() );
1460 long nTop
= Min( rRect
.Top(), rRect
.Bottom() );
1461 long nRight
= Max( rRect
.Left(), rRect
.Right() );
1462 long nBottom
= Max( rRect
.Top(), rRect
.Bottom() );
1464 // is own region NULL-region? -> copy data!
1465 if ( mpImplRegion
== &aImplNullRegion
)
1467 // create instance of implementation class
1468 mpImplRegion
= new ImplRegion();
1470 // add band with boundaries of the rectangle
1471 mpImplRegion
->mpFirstBand
= new ImplRegionBand( nTop
, nBottom
);
1473 // Set left and right boundaries of the band
1474 mpImplRegion
->mpFirstBand
->Union( nLeft
, nRight
);
1475 mpImplRegion
->mnRectCount
= 1;
1480 // no own instance data? -> make own copy!
1481 if ( mpImplRegion
->mnRefCount
> 1 )
1484 // insert bands if the boundaries are not allready in the list
1485 mpImplRegion
->InsertBands( nTop
, nBottom
);
1487 // process intersections
1488 ImplRegionBand
* pPrevBand
= 0;
1489 ImplRegionBand
* pBand
= mpImplRegion
->mpFirstBand
;
1492 // band within intersection boundary? -> process. otherwise remove
1493 if ( (pBand
->mnYTop
>= nTop
) &&
1494 (pBand
->mnYBottom
<= nBottom
) )
1496 // process intersection
1497 pBand
->Intersect( nLeft
, nRight
);
1500 pBand
= pBand
->mpNextBand
;
1504 ImplRegionBand
* pOldBand
= pBand
;
1505 if ( pBand
== mpImplRegion
->mpFirstBand
)
1506 mpImplRegion
->mpFirstBand
= pBand
->mpNextBand
;
1508 pPrevBand
->mpNextBand
= pBand
->mpNextBand
;
1509 pBand
= pBand
->mpNextBand
;
1515 if ( !mpImplRegion
->OptimizeBandList() )
1517 delete mpImplRegion
;
1518 mpImplRegion
= (ImplRegion
*)(&aImplEmptyRegion
);
1524 // -----------------------------------------------------------------------
1526 BOOL
Region::Exclude( const Rectangle
& rRect
)
1528 DBG_CHKTHIS( Region
, ImplDbgTestRegion
);
1530 // is rectangle empty? -> nothing to do
1531 if ( rRect
.IsEmpty() )
1534 ImplPolyPolyRegionToBandRegion();
1536 // no instance data? -> create!
1537 if ( (mpImplRegion
== &aImplEmptyRegion
) || (mpImplRegion
== &aImplNullRegion
) )
1540 // no own instance data? -> make own copy!
1541 if ( mpImplRegion
->mnRefCount
> 1 )
1544 // get justified rectangle
1545 long nLeft
= Min( rRect
.Left(), rRect
.Right() );
1546 long nTop
= Min( rRect
.Top(), rRect
.Bottom() );
1547 long nRight
= Max( rRect
.Left(), rRect
.Right() );
1548 long nBottom
= Max( rRect
.Top(), rRect
.Bottom() );
1550 // insert bands if the boundaries are not allready in the list
1551 mpImplRegion
->InsertBands( nTop
, nBottom
);
1554 mpImplRegion
->Exclude( nLeft
, nTop
, nRight
, nBottom
);
1557 if ( !mpImplRegion
->OptimizeBandList() )
1559 delete mpImplRegion
;
1560 mpImplRegion
= (ImplRegion
*)(&aImplEmptyRegion
);
1566 // -----------------------------------------------------------------------
1568 BOOL
Region::XOr( const Rectangle
& rRect
)
1570 DBG_CHKTHIS( Region
, ImplDbgTestRegion
);
1572 // is rectangle empty? -> nothing to do
1573 if ( rRect
.IsEmpty() )
1576 ImplPolyPolyRegionToBandRegion();
1578 // no instance data? -> create!
1579 if ( (mpImplRegion
== &aImplEmptyRegion
) || (mpImplRegion
== &aImplNullRegion
) )
1580 mpImplRegion
= new ImplRegion();
1582 // no own instance data? -> make own copy!
1583 if ( mpImplRegion
->mnRefCount
> 1 )
1586 // get justified rectangle
1587 long nLeft
= Min( rRect
.Left(), rRect
.Right() );
1588 long nTop
= Min( rRect
.Top(), rRect
.Bottom() );
1589 long nRight
= Max( rRect
.Left(), rRect
.Right() );
1590 long nBottom
= Max( rRect
.Top(), rRect
.Bottom() );
1592 // insert bands if the boundaries are not allready in the list
1593 mpImplRegion
->InsertBands( nTop
, nBottom
);
1596 mpImplRegion
->XOr( nLeft
, nTop
, nRight
, nBottom
);
1599 if ( !mpImplRegion
->OptimizeBandList() )
1601 delete mpImplRegion
;
1602 mpImplRegion
= (ImplRegion
*)(&aImplEmptyRegion
);
1608 // -----------------------------------------------------------------------
1610 BOOL
Region::Union( const Region
& rRegion
)
1612 DBG_CHKTHIS( Region
, ImplDbgTestRegion
);
1614 ImplPolyPolyRegionToBandRegion();
1615 ((Region
*)&rRegion
)->ImplPolyPolyRegionToBandRegion();
1617 // is region empty or null? -> nothing to do
1618 if ( (rRegion
.mpImplRegion
== &aImplEmptyRegion
) || (rRegion
.mpImplRegion
== &aImplNullRegion
) )
1621 // no instance data? -> create!
1622 if ( (mpImplRegion
== &aImplEmptyRegion
) || (mpImplRegion
== &aImplNullRegion
) )
1623 mpImplRegion
= new ImplRegion();
1625 // no own instance data? -> make own copy!
1626 if ( mpImplRegion
->mnRefCount
> 1 )
1629 // Alle Rechtecke aus der uebergebenen Region auf diese Region anwenden
1630 ImplRegionBand
* pBand
= rRegion
.mpImplRegion
->mpFirstBand
;
1633 // insert bands if the boundaries are not allready in the list
1634 mpImplRegion
->InsertBands( pBand
->mnYTop
, pBand
->mnYBottom
);
1636 // process all elements of the list
1637 ImplRegionBandSep
* pSep
= pBand
->mpFirstSep
;
1640 mpImplRegion
->Union( pSep
->mnXLeft
, pBand
->mnYTop
,
1641 pSep
->mnXRight
, pBand
->mnYBottom
);
1642 pSep
= pSep
->mpNextSep
;
1645 pBand
= pBand
->mpNextBand
;
1649 if ( !mpImplRegion
->OptimizeBandList() )
1651 delete mpImplRegion
;
1652 mpImplRegion
= (ImplRegion
*)(&aImplEmptyRegion
);
1658 // -----------------------------------------------------------------------
1660 BOOL
Region::Intersect( const Region
& rRegion
)
1662 DBG_CHKTHIS( Region
, ImplDbgTestRegion
);
1664 // same instance data? -> nothing to do!
1665 if ( mpImplRegion
== rRegion
.mpImplRegion
)
1668 ImplPolyPolyRegionToBandRegion();
1669 ((Region
*)&rRegion
)->ImplPolyPolyRegionToBandRegion();
1671 if ( mpImplRegion
== &aImplEmptyRegion
)
1674 // is region null? -> nothing to do
1675 if ( rRegion
.mpImplRegion
== &aImplNullRegion
)
1678 // is rectangle empty? -> nothing to do
1679 if ( rRegion
.mpImplRegion
== &aImplEmptyRegion
)
1681 // statische Object haben RefCount von 0
1682 if ( mpImplRegion
->mnRefCount
)
1684 if ( mpImplRegion
->mnRefCount
> 1 )
1685 mpImplRegion
->mnRefCount
--;
1687 delete mpImplRegion
;
1689 mpImplRegion
= (ImplRegion
*)(&aImplEmptyRegion
);
1693 // is own region NULL-region? -> copy data!
1694 if ( mpImplRegion
== &aImplNullRegion
)
1696 mpImplRegion
= rRegion
.mpImplRegion
;
1697 rRegion
.mpImplRegion
->mnRefCount
++;
1701 // Wenn wir weniger Rechtecke haben, drehen wir den Intersect-Aufruf um
1702 if ( mpImplRegion
->mnRectCount
+2 < rRegion
.mpImplRegion
->mnRectCount
)
1704 Region aTempRegion
= rRegion
;
1705 aTempRegion
.Intersect( *this );
1706 *this = aTempRegion
;
1710 // no own instance data? -> make own copy!
1711 if ( mpImplRegion
->mnRefCount
> 1 )
1714 // mark all bands as untouched
1715 ImplRegionBand
* pBand
= mpImplRegion
->mpFirstBand
;
1718 pBand
->mbTouched
= FALSE
;
1719 pBand
= pBand
->mpNextBand
;
1722 pBand
= rRegion
.mpImplRegion
->mpFirstBand
;
1725 // insert bands if the boundaries are not allready in the list
1726 mpImplRegion
->InsertBands( pBand
->mnYTop
, pBand
->mnYBottom
);
1728 // process all elements of the list
1729 ImplRegionBandSep
* pSep
= pBand
->mpFirstSep
;
1733 if ( pSep
== pBand
->mpFirstSep
)
1735 // process intersection and do not remove untouched bands
1736 mpImplRegion
->Exclude( LONG_MIN
+1, pBand
->mnYTop
,
1737 pSep
->mnXLeft
-1, pBand
->mnYBottom
);
1741 if ( pSep
->mpNextSep
== NULL
)
1743 // process intersection and do not remove untouched bands
1744 mpImplRegion
->Exclude( pSep
->mnXRight
+1, pBand
->mnYTop
,
1745 LONG_MAX
-1, pBand
->mnYBottom
);
1749 // process intersection and do not remove untouched bands
1750 mpImplRegion
->Exclude( pSep
->mnXRight
+1, pBand
->mnYTop
,
1751 pSep
->mpNextSep
->mnXLeft
-1, pBand
->mnYBottom
);
1754 pSep
= pSep
->mpNextSep
;
1757 pBand
= pBand
->mpNextBand
;
1760 // remove all untouched bands if bands allready left
1761 ImplRegionBand
* pPrevBand
= 0;
1762 pBand
= mpImplRegion
->mpFirstBand
;
1765 if ( !pBand
->mbTouched
)
1768 ImplRegionBand
* pOldBand
= pBand
;
1770 // previous element of the list
1771 if ( pBand
== mpImplRegion
->mpFirstBand
)
1772 mpImplRegion
->mpFirstBand
= pBand
->mpNextBand
;
1774 pPrevBand
->mpNextBand
= pBand
->mpNextBand
;
1776 pBand
= pBand
->mpNextBand
;
1782 pBand
= pBand
->mpNextBand
;
1787 if ( !mpImplRegion
->OptimizeBandList() )
1789 delete mpImplRegion
;
1790 mpImplRegion
= (ImplRegion
*)(&aImplEmptyRegion
);
1797 // -----------------------------------------------------------------------
1799 BOOL
Region::Exclude( const Region
& rRegion
)
1801 DBG_CHKTHIS( Region
, ImplDbgTestRegion
);
1803 ImplPolyPolyRegionToBandRegion();
1804 ((Region
*)&rRegion
)->ImplPolyPolyRegionToBandRegion();
1806 // is region empty or null? -> nothing to do
1807 if ( (rRegion
.mpImplRegion
== &aImplEmptyRegion
) || (rRegion
.mpImplRegion
== &aImplNullRegion
) )
1810 // no instance data? -> nothing to do
1811 if ( (mpImplRegion
== &aImplEmptyRegion
) || (mpImplRegion
== &aImplNullRegion
) )
1814 // no own instance data? -> make own copy!
1815 if ( mpImplRegion
->mnRefCount
> 1 )
1818 // Alle Rechtecke aus der uebergebenen Region auf diese Region anwenden
1819 ImplRegionBand
* pBand
= rRegion
.mpImplRegion
->mpFirstBand
;
1822 // insert bands if the boundaries are not allready in the list
1823 mpImplRegion
->InsertBands( pBand
->mnYTop
, pBand
->mnYBottom
);
1825 // process all elements of the list
1826 ImplRegionBandSep
* pSep
= pBand
->mpFirstSep
;
1829 mpImplRegion
->Exclude( pSep
->mnXLeft
, pBand
->mnYTop
,
1830 pSep
->mnXRight
, pBand
->mnYBottom
);
1831 pSep
= pSep
->mpNextSep
;
1834 // Wir optimieren schon in der Schleife, da wir davon
1835 // ausgehen, das wir insgesammt weniger Baender ueberpruefen
1837 if ( !mpImplRegion
->OptimizeBandList() )
1839 delete mpImplRegion
;
1840 mpImplRegion
= (ImplRegion
*)(&aImplEmptyRegion
);
1844 pBand
= pBand
->mpNextBand
;
1850 // -----------------------------------------------------------------------
1852 BOOL
Region::XOr( const Region
& rRegion
)
1854 DBG_CHKTHIS( Region
, ImplDbgTestRegion
);
1856 ImplPolyPolyRegionToBandRegion();
1857 ((Region
*)&rRegion
)->ImplPolyPolyRegionToBandRegion();
1859 // is region empty or null? -> nothing to do
1860 if ( (rRegion
.mpImplRegion
== &aImplEmptyRegion
) || (rRegion
.mpImplRegion
== &aImplNullRegion
) )
1863 // no own instance data? -> XOr = copy
1864 if ( (mpImplRegion
== &aImplEmptyRegion
) || (mpImplRegion
== &aImplNullRegion
) )
1870 // no own instance data? -> make own copy!
1871 if ( mpImplRegion
->mnRefCount
> 1 )
1874 // Alle Rechtecke aus der uebergebenen Region auf diese Region anwenden
1875 ImplRegionBand
* pBand
= rRegion
.mpImplRegion
->mpFirstBand
;
1878 // insert bands if the boundaries are not allready in the list
1879 mpImplRegion
->InsertBands( pBand
->mnYTop
, pBand
->mnYBottom
);
1881 // process all elements of the list
1882 ImplRegionBandSep
* pSep
= pBand
->mpFirstSep
;
1885 mpImplRegion
->XOr( pSep
->mnXLeft
, pBand
->mnYTop
,
1886 pSep
->mnXRight
, pBand
->mnYBottom
);
1887 pSep
= pSep
->mpNextSep
;
1890 pBand
= pBand
->mpNextBand
;
1894 if ( !mpImplRegion
->OptimizeBandList() )
1896 delete mpImplRegion
;
1897 mpImplRegion
= (ImplRegion
*)(&aImplEmptyRegion
);
1903 // -----------------------------------------------------------------------
1905 Rectangle
Region::GetBoundRect() const
1907 DBG_CHKTHIS( Region
, ImplDbgTestRegion
);
1911 // no internal data? -> region is empty!
1912 if ( (mpImplRegion
== &aImplEmptyRegion
) || (mpImplRegion
== &aImplNullRegion
) )
1915 // PolyPolygon data im Imp structure?
1916 if ( mpImplRegion
->mpPolyPoly
)
1917 return mpImplRegion
->mpPolyPoly
->GetBoundRect();
1918 if( mpImplRegion
->mpB2DPolyPoly
)
1920 const basegfx::B2DRange aRange
= basegfx::tools::getRange( *mpImplRegion
->mpB2DPolyPoly
);
1921 aRect
.SetPos( Point( (int)aRange
.getMinX(), (int)aRange
.getMinY() ) );
1922 aRect
.SetSize( Size( (int)aRange
.getWidth(), (int)aRange
.getHeight() ) );
1926 // no band in the list? -> region is empty!
1927 if ( !mpImplRegion
->mpFirstBand
)
1930 // get the boundaries of the first band
1931 long nYTop
= mpImplRegion
->mpFirstBand
->mnYTop
;
1932 long nYBottom
= mpImplRegion
->mpFirstBand
->mnYBottom
;
1933 long nXLeft
= mpImplRegion
->mpFirstBand
->GetXLeftBoundary();
1934 long nXRight
= mpImplRegion
->mpFirstBand
->GetXRightBoundary();
1936 // look in the band list (don't test first band again!)
1937 ImplRegionBand
* pBand
= mpImplRegion
->mpFirstBand
->mpNextBand
;
1940 nYBottom
= pBand
->mnYBottom
;
1941 nXLeft
= Min( nXLeft
, pBand
->GetXLeftBoundary() );
1942 nXRight
= Max( nXRight
, pBand
->GetXRightBoundary() );
1944 pBand
= pBand
->mpNextBand
;
1948 aRect
= Rectangle( nXLeft
, nYTop
, nXRight
, nYBottom
);
1952 // -----------------------------------------------------------------------
1954 BOOL
Region::HasPolyPolygon() const
1956 DBG_CHKTHIS( Region
, ImplDbgTestRegion
);
1959 if( mpImplRegion
->mpPolyPoly
)
1961 if( mpImplRegion
->mpB2DPolyPoly
)
1966 // -----------------------------------------------------------------------
1968 PolyPolygon
Region::GetPolyPolygon() const
1970 DBG_CHKTHIS( Region
, ImplDbgTestRegion
);
1974 if( mpImplRegion
->mpPolyPoly
)
1975 aRet
= *mpImplRegion
->mpPolyPoly
;
1976 else if( mpImplRegion
->mpB2DPolyPoly
)
1978 // the polygon needs to be converted
1979 aRet
= PolyPolygon( *mpImplRegion
->mpB2DPolyPoly
);
1980 // TODO: cache the converted polygon?
1981 // mpImplRegion->mpB2DPolyPoly = aRet;
1987 // -----------------------------------------------------------------------
1989 const basegfx::B2DPolyPolygon
Region::GetB2DPolyPolygon() const
1991 DBG_CHKTHIS( Region
, ImplDbgTestRegion
);
1993 basegfx::B2DPolyPolygon aRet
;
1995 if( mpImplRegion
->mpB2DPolyPoly
)
1996 aRet
= *mpImplRegion
->mpB2DPolyPoly
;
1997 else if( mpImplRegion
->mpPolyPoly
)
1999 // the polygon needs to be converted
2000 aRet
= mpImplRegion
->mpPolyPoly
->getB2DPolyPolygon();
2001 // TODO: cache the converted polygon?
2002 // mpImplRegion->mpB2DPolyPoly = aRet;
2008 // -----------------------------------------------------------------------
2010 BOOL
Region::ImplGetFirstRect( ImplRegionInfo
& rImplRegionInfo
,
2012 long& rWidth
, long& rHeight
) const
2014 DBG_CHKTHIS( Region
, ImplDbgTestRegion
);
2016 ((Region
*)this)->ImplPolyPolyRegionToBandRegion();
2018 // no internal data? -> region is empty!
2019 if ( (mpImplRegion
== &aImplEmptyRegion
) || (mpImplRegion
== &aImplNullRegion
) )
2022 // no band in the list? -> region is empty!
2023 if ( mpImplRegion
->mpFirstBand
== NULL
)
2026 // initialise pointer for first access
2027 ImplRegionBand
* pCurrRectBand
= mpImplRegion
->mpFirstBand
;
2028 ImplRegionBandSep
* pCurrRectBandSep
= pCurrRectBand
->mpFirstSep
;
2030 DBG_ASSERT( pCurrRectBandSep
!= NULL
, "Erstes Band wurde nicht optimiert." );
2031 if ( !pCurrRectBandSep
)
2034 // get boundaries of current rectangle
2035 rX
= pCurrRectBandSep
->mnXLeft
;
2036 rY
= pCurrRectBand
->mnYTop
;
2037 rWidth
= pCurrRectBandSep
->mnXRight
- pCurrRectBandSep
->mnXLeft
+ 1;
2038 rHeight
= pCurrRectBand
->mnYBottom
- pCurrRectBand
->mnYTop
+ 1;
2041 rImplRegionInfo
.mpVoidCurrRectBand
= (void*)pCurrRectBand
;
2042 rImplRegionInfo
.mpVoidCurrRectBandSep
= (void*)pCurrRectBandSep
;
2047 // -----------------------------------------------------------------------
2049 BOOL
Region::ImplGetNextRect( ImplRegionInfo
& rImplRegionInfo
,
2051 long& rWidth
, long& rHeight
) const
2053 DBG_CHKTHIS( Region
, ImplDbgTestRegion
);
2055 // no internal data? -> region is empty!
2056 if ( (mpImplRegion
== &aImplEmptyRegion
) || (mpImplRegion
== &aImplNullRegion
) )
2059 // get last pointers
2060 ImplRegionBand
* pCurrRectBand
= (ImplRegionBand
*)rImplRegionInfo
.mpVoidCurrRectBand
;
2061 ImplRegionBandSep
* pCurrRectBandSep
= (ImplRegionBandSep
*)rImplRegionInfo
.mpVoidCurrRectBandSep
;
2063 // get next separation from current band
2064 pCurrRectBandSep
= pCurrRectBandSep
->mpNextSep
;
2066 // no separation found? -> go to next band!
2067 if ( !pCurrRectBandSep
)
2070 pCurrRectBand
= pCurrRectBand
->mpNextBand
;
2072 // no band found? -> not further rectangles!
2073 if( !pCurrRectBand
)
2076 // get first separation in current band
2077 pCurrRectBandSep
= pCurrRectBand
->mpFirstSep
;
2080 // get boundaries of current rectangle
2081 rX
= pCurrRectBandSep
->mnXLeft
;
2082 rY
= pCurrRectBand
->mnYTop
;
2083 rWidth
= pCurrRectBandSep
->mnXRight
- pCurrRectBandSep
->mnXLeft
+ 1;
2084 rHeight
= pCurrRectBand
->mnYBottom
- pCurrRectBand
->mnYTop
+ 1;
2086 // save new pointers
2087 rImplRegionInfo
.mpVoidCurrRectBand
= (void*)pCurrRectBand
;
2088 rImplRegionInfo
.mpVoidCurrRectBandSep
= (void*)pCurrRectBandSep
;
2093 // -----------------------------------------------------------------------
2095 RegionType
Region::GetType() const
2097 if ( mpImplRegion
== &aImplEmptyRegion
)
2098 return REGION_EMPTY
;
2099 else if ( mpImplRegion
== &aImplNullRegion
)
2101 else if ( mpImplRegion
->mnRectCount
== 1 )
2102 return REGION_RECTANGLE
;
2104 return REGION_COMPLEX
;
2107 // -----------------------------------------------------------------------
2109 BOOL
Region::IsInside( const Point
& rPoint
) const
2111 DBG_CHKTHIS( Region
, ImplDbgTestRegion
);
2113 // PolyPolygon data im Imp structure?
2114 ((Region
*)this)->ImplPolyPolyRegionToBandRegion();
2116 if ( mpImplRegion->mpPolyPoly )
2117 return mpImplRegion->mpPolyPoly->IsInside( rPoint );
2120 // no instance data? -> not inside
2121 if ( (mpImplRegion
== &aImplEmptyRegion
) || (mpImplRegion
== &aImplNullRegion
) )
2125 ImplRegionBand
* pBand
= mpImplRegion
->mpFirstBand
;
2128 // is point within band?
2129 if ( (pBand
->mnYTop
<= rPoint
.Y()) &&
2130 (pBand
->mnYBottom
>= rPoint
.Y()) )
2132 // is point within separation of the band?
2133 if ( pBand
->IsInside( rPoint
.X() ) )
2139 pBand
= pBand
->mpNextBand
;
2145 // -----------------------------------------------------------------------
2147 BOOL
Region::IsInside( const Rectangle
& rRect
) const
2149 DBG_CHKTHIS( Region
, ImplDbgTestRegion
);
2151 // is rectangle empty? -> not inside
2152 if ( rRect
.IsEmpty() )
2155 // no instance data? -> not inside
2156 if ( (mpImplRegion
== &aImplEmptyRegion
) || (mpImplRegion
== &aImplNullRegion
) )
2159 // create region from rectangle and intersect own region
2160 Region aRegion
= rRect
;
2161 aRegion
.Exclude( *this );
2163 // rectangle is inside if exclusion is empty
2164 return aRegion
.IsEmpty();
2167 // -----------------------------------------------------------------------
2169 BOOL
Region::IsOver( const Rectangle
& rRect
) const
2171 DBG_CHKTHIS( Region
, ImplDbgTestRegion
);
2173 if ( (mpImplRegion
== &aImplEmptyRegion
) || (mpImplRegion
== &aImplNullRegion
) )
2176 // Can we optimize this ??? - is used in StarDraw for brushes pointers
2177 // Why we have no IsOver for Regions ???
2178 // create region from rectangle and intersect own region
2179 Region aRegion
= rRect
;
2180 aRegion
.Intersect( *this );
2182 // rectangle is over if include is not empty
2183 return !aRegion
.IsEmpty();
2186 // -----------------------------------------------------------------------
2188 void Region::SetNull()
2190 DBG_CHKTHIS( Region
, ImplDbgTestRegion
);
2192 // statische Object haben RefCount von 0
2193 if ( mpImplRegion
->mnRefCount
)
2195 if ( mpImplRegion
->mnRefCount
> 1 )
2196 mpImplRegion
->mnRefCount
--;
2198 delete mpImplRegion
;
2202 mpImplRegion
= (ImplRegion
*)(&aImplNullRegion
);
2205 // -----------------------------------------------------------------------
2207 void Region::SetEmpty()
2209 DBG_CHKTHIS( Region
, ImplDbgTestRegion
);
2211 // statische Object haben RefCount von 0
2212 if ( mpImplRegion
->mnRefCount
)
2214 if ( mpImplRegion
->mnRefCount
> 1 )
2215 mpImplRegion
->mnRefCount
--;
2217 delete mpImplRegion
;
2221 mpImplRegion
= (ImplRegion
*)(&aImplEmptyRegion
);
2224 // -----------------------------------------------------------------------
2226 Region
& Region::operator=( const Region
& rRegion
)
2228 DBG_CHKTHIS( Region
, ImplDbgTestRegion
);
2229 DBG_CHKOBJ( &rRegion
, Region
, ImplDbgTestRegion
);
2230 DBG_ASSERT( rRegion
.mpImplRegion
->mnRefCount
< 0xFFFFFFFE, "Region: RefCount overflow" );
2232 // Zuerst Referenzcounter erhoehen, damit man sich selbst zuweisen kann
2233 // RefCount == 0 fuer statische Objekte
2234 if ( rRegion
.mpImplRegion
->mnRefCount
)
2235 rRegion
.mpImplRegion
->mnRefCount
++;
2237 // statische Object haben RefCount von 0
2238 if ( mpImplRegion
->mnRefCount
)
2240 if ( mpImplRegion
->mnRefCount
> 1 )
2241 mpImplRegion
->mnRefCount
--;
2243 delete mpImplRegion
;
2246 mpImplRegion
= rRegion
.mpImplRegion
;
2250 // -----------------------------------------------------------------------
2252 Region
& Region::operator=( const Rectangle
& rRect
)
2254 DBG_CHKTHIS( Region
, ImplDbgTestRegion
);
2256 // statische Object haben RefCount von 0
2257 if ( mpImplRegion
->mnRefCount
)
2259 if ( mpImplRegion
->mnRefCount
> 1 )
2260 mpImplRegion
->mnRefCount
--;
2262 delete mpImplRegion
;
2265 ImplCreateRectRegion( rRect
);
2269 // -----------------------------------------------------------------------
2271 BOOL
Region::operator==( const Region
& rRegion
) const
2273 DBG_CHKTHIS( Region
, ImplDbgTestRegion
);
2274 DBG_CHKOBJ( &rRegion
, Region
, ImplDbgTestRegion
);
2276 // reference to same object? -> equal!
2277 if ( mpImplRegion
== rRegion
.mpImplRegion
)
2280 if ( (mpImplRegion
== &aImplEmptyRegion
) || (mpImplRegion
== &aImplNullRegion
) )
2283 if ( (rRegion
.mpImplRegion
== &aImplEmptyRegion
) || (rRegion
.mpImplRegion
== &aImplNullRegion
) )
2286 if ( rRegion
.mpImplRegion
->mpPolyPoly
&& mpImplRegion
->mpPolyPoly
)
2287 return *rRegion
.mpImplRegion
->mpPolyPoly
== *mpImplRegion
->mpPolyPoly
;
2290 ((Region
*)this)->ImplPolyPolyRegionToBandRegion();
2291 ((Region
*)&rRegion
)->ImplPolyPolyRegionToBandRegion();
2293 // Eine der beiden Regions kann jetzt Empty sein
2294 if ( mpImplRegion
== rRegion
.mpImplRegion
)
2297 if ( mpImplRegion
== &aImplEmptyRegion
)
2300 if ( rRegion
.mpImplRegion
== &aImplEmptyRegion
)
2304 // initialise pointers
2305 ImplRegionBand
* pOwnRectBand
= mpImplRegion
->mpFirstBand
;
2306 ImplRegionBandSep
* pOwnRectBandSep
= pOwnRectBand
->mpFirstSep
;
2307 ImplRegionBand
* pSecondRectBand
= rRegion
.mpImplRegion
->mpFirstBand
;
2308 ImplRegionBandSep
* pSecondRectBandSep
= pSecondRectBand
->mpFirstSep
;
2309 while ( pOwnRectBandSep
&& pSecondRectBandSep
)
2311 // get boundaries of current rectangle
2312 long nOwnXLeft
= pOwnRectBandSep
->mnXLeft
;
2313 long nSecondXLeft
= pSecondRectBandSep
->mnXLeft
;
2314 if ( nOwnXLeft
!= nSecondXLeft
)
2317 long nOwnYTop
= pOwnRectBand
->mnYTop
;
2318 long nSecondYTop
= pSecondRectBand
->mnYTop
;
2319 if ( nOwnYTop
!= nSecondYTop
)
2322 long nOwnXRight
= pOwnRectBandSep
->mnXRight
;
2323 long nSecondXRight
= pSecondRectBandSep
->mnXRight
;
2324 if ( nOwnXRight
!= nSecondXRight
)
2327 long nOwnYBottom
= pOwnRectBand
->mnYBottom
;
2328 long nSecondYBottom
= pSecondRectBand
->mnYBottom
;
2329 if ( nOwnYBottom
!= nSecondYBottom
)
2332 // get next separation from current band
2333 pOwnRectBandSep
= pOwnRectBandSep
->mpNextSep
;
2335 // no separation found? -> go to next band!
2336 if ( !pOwnRectBandSep
)
2339 pOwnRectBand
= pOwnRectBand
->mpNextBand
;
2341 // get first separation in current band
2343 pOwnRectBandSep
= pOwnRectBand
->mpFirstSep
;
2346 // get next separation from current band
2347 pSecondRectBandSep
= pSecondRectBandSep
->mpNextSep
;
2349 // no separation found? -> go to next band!
2350 if ( !pSecondRectBandSep
)
2353 pSecondRectBand
= pSecondRectBand
->mpNextBand
;
2355 // get first separation in current band
2356 if( pSecondRectBand
)
2357 pSecondRectBandSep
= pSecondRectBand
->mpFirstSep
;
2360 if ( pOwnRectBandSep
&& !pSecondRectBandSep
)
2363 if ( !pOwnRectBandSep
&& pSecondRectBandSep
)
2370 // -----------------------------------------------------------------------
2372 enum StreamEntryType
{ STREAMENTRY_BANDHEADER
, STREAMENTRY_SEPARATION
, STREAMENTRY_END
};
2374 SvStream
& operator>>( SvStream
& rIStrm
, Region
& rRegion
)
2376 DBG_CHKOBJ( &rRegion
, Region
, ImplDbgTestRegion
);
2378 VersionCompat
aCompat( rIStrm
, STREAM_READ
);
2382 // statische Object haben RefCount von 0
2383 if ( rRegion
.mpImplRegion
->mnRefCount
)
2385 if ( rRegion
.mpImplRegion
->mnRefCount
> 1 )
2386 rRegion
.mpImplRegion
->mnRefCount
--;
2388 delete rRegion
.mpImplRegion
;
2391 // get version of streamed region
2394 // get type of region
2397 RegionType meStreamedType
= (RegionType
)nTmp16
;
2399 switch( meStreamedType
)
2402 rRegion
.mpImplRegion
= (ImplRegion
*)&aImplNullRegion
;
2406 rRegion
.mpImplRegion
= (ImplRegion
*)&aImplEmptyRegion
;
2411 // create instance of implementation class
2412 rRegion
.mpImplRegion
= new ImplRegion();
2414 // get header from first element
2418 rRegion
.mpImplRegion
->mnRectCount
= 0;
2419 ImplRegionBand
* pCurrBand
= NULL
;
2420 while ( (StreamEntryType
)nTmp16
!= STREAMENTRY_END
)
2422 // insert new band or new separation?
2423 if ( (StreamEntryType
)nTmp16
== STREAMENTRY_BANDHEADER
)
2432 ImplRegionBand
* pNewBand
= new ImplRegionBand( nYTop
, nYBottom
);
2434 // first element? -> set as first into the list
2436 rRegion
.mpImplRegion
->mpFirstBand
= pNewBand
;
2438 pCurrBand
->mpNextBand
= pNewBand
;
2440 // save pointer for next creation
2441 pCurrBand
= pNewBand
;
2454 pCurrBand
->Union( nXLeft
, nXRight
);
2455 rRegion
.mpImplRegion
->mnRectCount
++;
2463 if( aCompat
.GetVersion() >= 2 )
2465 BOOL bHasPolyPolygon
;
2467 rIStrm
>> bHasPolyPolygon
;
2469 if( bHasPolyPolygon
)
2471 delete rRegion
.mpImplRegion
->mpPolyPoly
;
2472 rRegion
.mpImplRegion
->mpPolyPoly
= new PolyPolygon
;
2473 rIStrm
>> *( rRegion
.mpImplRegion
->mpPolyPoly
);
2483 // -----------------------------------------------------------------------
2485 SvStream
& operator<<( SvStream
& rOStrm
, const Region
& rRegion
)
2487 DBG_CHKOBJ( &rRegion
, Region
, ImplDbgTestRegion
);
2489 UINT16 nVersion
= 2;
2490 VersionCompat
aCompat( rOStrm
, STREAM_WRITE
, nVersion
);
2491 Region
aTmpRegion( rRegion
);
2493 // use tmp region to avoid destruction of internal region (polypolygon) of rRegion
2494 aTmpRegion
.ImplPolyPolyRegionToBandRegion();
2500 rOStrm
<< (UINT16
)aTmpRegion
.GetType();
2502 // put all bands if not null or empty
2503 if ( (aTmpRegion
.mpImplRegion
!= &aImplEmptyRegion
) && (aTmpRegion
.mpImplRegion
!= &aImplNullRegion
) )
2505 ImplRegionBand
* pBand
= aTmpRegion
.mpImplRegion
->mpFirstBand
;
2509 rOStrm
<< (UINT16
) STREAMENTRY_BANDHEADER
;
2510 rOStrm
<< pBand
->mnYTop
;
2511 rOStrm
<< pBand
->mnYBottom
;
2513 // put separations of current band
2514 ImplRegionBandSep
* pSep
= pBand
->mpFirstSep
;
2518 rOStrm
<< (UINT16
) STREAMENTRY_SEPARATION
;
2519 rOStrm
<< pSep
->mnXLeft
;
2520 rOStrm
<< pSep
->mnXRight
;
2522 // next separation from current band
2523 pSep
= pSep
->mpNextSep
;
2526 pBand
= pBand
->mpNextBand
;
2530 rOStrm
<< (UINT16
) STREAMENTRY_END
;
2532 // write polypolygon if available
2533 const BOOL bHasPolyPolygon
= rRegion
.HasPolyPolygon();
2534 rOStrm
<< bHasPolyPolygon
;
2536 if( bHasPolyPolygon
)
2537 rOStrm
<< rRegion
.GetPolyPolygon();
2543 // -----------------------------------------------------------------------
2545 void Region::ImplBeginAddRect()
2547 DBG_CHKTHIS( Region
, ImplDbgTestRegion
);
2549 // statische Object haben RefCount von 0
2550 if ( mpImplRegion
->mnRefCount
)
2552 if ( mpImplRegion
->mnRefCount
> 1 )
2553 mpImplRegion
->mnRefCount
--;
2555 delete mpImplRegion
;
2558 // create fresh region
2559 mpImplRegion
= new ImplRegion();
2562 // -----------------------------------------------------------------------
2564 BOOL
Region::ImplAddRect( const Rectangle
& rRect
)
2566 // Hier kein CheckThis, da nicht alle Daten auf Stand
2568 if ( rRect
.IsEmpty() )
2571 // get justified rectangle
2576 if ( rRect
.Top() <= rRect
.Bottom() )
2579 nBottom
= rRect
.Bottom();
2583 nTop
= rRect
.Bottom();
2584 nBottom
= rRect
.Top();
2586 if ( rRect
.Left() <= rRect
.Right() )
2588 nLeft
= rRect
.Left();
2589 nRight
= rRect
.Right();
2593 nLeft
= rRect
.Right();
2594 nRight
= rRect
.Left();
2597 if ( !mpImplRegion
->mpLastCheckedBand
)
2600 mpImplRegion
->mpLastCheckedBand
= new ImplRegionBand( nTop
, nBottom
);
2602 // set band as current
2603 mpImplRegion
->mpFirstBand
= mpImplRegion
->mpLastCheckedBand
;
2604 mpImplRegion
->mpLastCheckedBand
->Union( nLeft
, nRight
);
2608 DBG_ASSERT( nTop
>= mpImplRegion
->mpLastCheckedBand
->mnYTop
,
2609 "Region::ImplAddRect() - nTopY < nLastTopY" );
2611 // new band? create it!
2612 if ( (nTop
!= mpImplRegion
->mpLastCheckedBand
->mnYTop
) ||
2613 (nBottom
!= mpImplRegion
->mpLastCheckedBand
->mnYBottom
) )
2616 ImplRegionBand
* pNewRegionBand
= new ImplRegionBand( nTop
, nBottom
);
2618 // append band to the end
2619 mpImplRegion
->mpLastCheckedBand
->mpNextBand
= pNewRegionBand
;
2621 // skip to the new band
2622 mpImplRegion
->mpLastCheckedBand
= mpImplRegion
->mpLastCheckedBand
->mpNextBand
;
2626 mpImplRegion
->mpLastCheckedBand
->Union( nLeft
, nRight
);
2632 // -----------------------------------------------------------------------
2634 void Region::ImplEndAddRect()
2636 // check if we are empty
2637 if ( !mpImplRegion
->mpFirstBand
)
2639 delete mpImplRegion
;
2640 mpImplRegion
= (ImplRegion
*)(&aImplEmptyRegion
);
2644 // check if we have somthing to optimize
2645 if ( !mpImplRegion
->mpFirstBand
->mpNextBand
)
2647 // update mpImplRegion->mnRectCount, because no OptimizeBandList is called
2648 ImplRegionBandSep
* pSep
= mpImplRegion
->mpFirstBand
->mpFirstSep
;
2649 mpImplRegion
->mnRectCount
= 0;
2652 mpImplRegion
->mnRectCount
++;
2653 pSep
= pSep
->mpNextSep
;
2656 // Erst hier testen, da hier die Daten wieder stimmen
2657 DBG_CHKTHIS( Region
, ImplDbgTestRegion
);
2661 // have to revert list? -> do it now!
2662 if ( mpImplRegion
->mpFirstBand
->mnYTop
>
2663 mpImplRegion
->mpFirstBand
->mpNextBand
->mnYTop
)
2665 ImplRegionBand
* pNewFirstRegionBand
;
2667 // initialize temp list with first element
2668 pNewFirstRegionBand
= mpImplRegion
->mpFirstBand
;
2669 mpImplRegion
->mpFirstBand
= mpImplRegion
->mpFirstBand
->mpNextBand
;
2670 pNewFirstRegionBand
->mpNextBand
= NULL
;
2672 // insert elements to the temp list
2673 while ( mpImplRegion
->mpFirstBand
)
2675 ImplRegionBand
* pSavedRegionBand
= pNewFirstRegionBand
;
2676 pNewFirstRegionBand
= mpImplRegion
->mpFirstBand
;
2677 mpImplRegion
->mpFirstBand
= mpImplRegion
->mpFirstBand
->mpNextBand
;
2678 pNewFirstRegionBand
->mpNextBand
= pSavedRegionBand
;
2681 // set temp list as new list
2682 mpImplRegion
->mpFirstBand
= pNewFirstRegionBand
;
2686 if ( !mpImplRegion
->OptimizeBandList() )
2688 delete mpImplRegion
;
2689 mpImplRegion
= (ImplRegion
*)(&aImplEmptyRegion
);
2692 // Erst hier testen, da hier die Daten wieder stimmen
2693 DBG_CHKTHIS( Region
, ImplDbgTestRegion
);
2696 // -----------------------------------------------------------------------
2698 ULONG
Region::GetRectCount() const
2700 DBG_CHKTHIS( Region
, ImplDbgTestRegion
);
2702 ((Region
*)this)->ImplPolyPolyRegionToBandRegion();
2707 // all bands if not null or empty
2708 if ( (mpImplRegion
!= &aImplEmptyRegion
) && (mpImplRegion
!= &aImplNullRegion
) )
2710 ImplRegionBand
* pBand
= mpImplRegion
->mpFirstBand
;
2713 ImplRegionBandSep
* pSep
= pBand
->mpFirstSep
;
2717 pSep
= pSep
->mpNextSep
;
2720 pBand
= pBand
->mpNextBand
;
2724 DBG_ASSERT( mpImplRegion
->mnRectCount
== nCount
, "Region: invalid mnRectCount!" );
2727 return mpImplRegion
->mnRectCount
;
2730 // -----------------------------------------------------------------------
2732 RegionHandle
Region::BeginEnumRects()
2734 DBG_CHKTHIS( Region
, ImplDbgTestRegion
);
2736 ImplPolyPolyRegionToBandRegion();
2738 // no internal data? -> region is empty!
2739 if ( (mpImplRegion
== &aImplEmptyRegion
) || (mpImplRegion
== &aImplNullRegion
) )
2742 // no band in the list? -> region is empty!
2743 if ( mpImplRegion
->mpFirstBand
== NULL
)
2745 DBG_ASSERT( mpImplRegion
->mpFirstBand
, "Region::BeginEnumRects() First Band is Empty!" );
2749 ImplRegionHandle
* pData
= new ImplRegionHandle
;
2750 pData
->mpRegion
= new Region( *this );
2751 pData
->mbFirst
= TRUE
;
2754 pData
->mpCurrRectBand
= pData
->mpRegion
->mpImplRegion
->mpFirstBand
;
2755 pData
->mpCurrRectBandSep
= pData
->mpCurrRectBand
->mpFirstSep
;
2757 return (RegionHandle
)pData
;
2760 // -----------------------------------------------------------------------
2762 BOOL
Region::GetEnumRects( RegionHandle pVoidData
, Rectangle
& rRect
)
2764 DBG_CHKTHIS( Region
, ImplDbgTestRegion
);
2766 ImplRegionHandle
* pData
= (ImplRegionHandle
*)pVoidData
;
2770 if ( pData
->mbFirst
)
2771 pData
->mbFirst
= FALSE
;
2774 // get next separation from current band
2775 pData
->mpCurrRectBandSep
= pData
->mpCurrRectBandSep
->mpNextSep
;
2777 // no separation found? -> go to next band!
2778 if ( !pData
->mpCurrRectBandSep
)
2781 pData
->mpCurrRectBand
= pData
->mpCurrRectBand
->mpNextBand
;
2783 // no band found? -> not further rectangles!
2784 if ( !pData
->mpCurrRectBand
)
2787 // get first separation in current band
2788 pData
->mpCurrRectBandSep
= pData
->mpCurrRectBand
->mpFirstSep
;
2792 // get boundaries of current rectangle
2793 rRect
.Top() = pData
->mpCurrRectBand
->mnYTop
;
2794 rRect
.Bottom() = pData
->mpCurrRectBand
->mnYBottom
;
2795 rRect
.Left() = pData
->mpCurrRectBandSep
->mnXLeft
;
2796 rRect
.Right() = pData
->mpCurrRectBandSep
->mnXRight
;
2800 // -----------------------------------------------------------------------
2802 void Region::EndEnumRects( RegionHandle pVoidData
)
2804 DBG_CHKTHIS( Region
, ImplDbgTestRegion
);
2806 ImplRegionHandle
* pData
= (ImplRegionHandle
*)pVoidData
;
2811 delete pData
->mpRegion
;
2815 // -----------------------------------------------------------------------
2817 static inline bool ImplPolygonRectTest( const Polygon
& rPoly
, Rectangle
* pRectOut
= NULL
)
2819 bool bIsRect
= false;
2820 const Point
* pPoints
= rPoly
.GetConstPointAry();
2821 USHORT nPoints
= rPoly
.GetSize();
2822 if( nPoints
== 4 || (nPoints
== 5 && pPoints
[0] == pPoints
[4]) )
2824 long nX1
= pPoints
[0].X(), nX2
= pPoints
[2].X(),
2825 nY1
= pPoints
[0].Y(), nY2
= pPoints
[2].Y();
2826 if( ( (pPoints
[1].X() == nX1
&& pPoints
[3].X() == nX2
) &&
2827 (pPoints
[1].Y() == nY2
&& pPoints
[3].Y() == nY1
) )
2829 ( (pPoints
[1].X() == nX2
&& pPoints
[3].X() == nX1
) &&
2830 (pPoints
[1].Y() == nY1
&& pPoints
[3].Y() == nY2
) ) )
2852 pRectOut
->Left() = nX1
;
2853 pRectOut
->Right() = nX2
;
2854 pRectOut
->Top() = nY1
;
2855 pRectOut
->Bottom() = nY2
;
2862 Region
Region::GetRegionFromPolyPolygon( const PolyPolygon
& rPolyPoly
)
2864 //return Region( rPolyPoly );
2866 // check if it's worth extracting the XOr'ing the Rectangles
2867 // empiricism shows that break even between XOr'ing rectangles separately
2868 // and ImplPolyPolyRegionToBandRegion is at half rectangles/half polygons
2869 int nPolygonRects
= 0, nPolygonPolygons
= 0;
2870 int nPolygons
= rPolyPoly
.Count();
2872 for( USHORT i
= 0; i
< nPolygons
; i
++ )
2874 const Polygon
& rPoly
= rPolyPoly
[i
];
2875 if( ImplPolygonRectTest( rPoly
) )
2880 if( nPolygonPolygons
> nPolygonRects
)
2881 return Region( rPolyPoly
);
2885 for( USHORT i
= 0; i
< nPolygons
; i
++ )
2887 const Polygon
& rPoly
= rPolyPoly
[i
];
2888 if( ImplPolygonRectTest( rPoly
, &aRect
) )
2889 aResult
.XOr( aRect
);
2891 aResult
.XOr( Region(rPoly
) );