Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /*
3 : * This file is part of the LibreOffice project.
4 : *
5 : * This Source Code Form is subject to the terms of the Mozilla Public
6 : * License, v. 2.0. If a copy of the MPL was not distributed with this
7 : * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 : *
9 : * This file incorporates work covered by the following license notice:
10 : *
11 : * Licensed to the Apache Software Foundation (ASF) under one or more
12 : * contributor license agreements. See the NOTICE file distributed
13 : * with this work for additional information regarding copyright
14 : * ownership. The ASF licenses this file to you under the Apache
15 : * License, Version 2.0 (the "License"); you may not use this file
16 : * except in compliance with the License. You may obtain a copy of
17 : * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 : */
19 :
20 : #include <algorithm>
21 :
22 : #include <tools/debug.hxx>
23 : #include <tools/helpers.hxx>
24 : #include <osl/diagnose.hxx>
25 :
26 : #include "regband.hxx"
27 :
28 : // ImplRegionBand
29 :
30 : // Each band contains all rectangles between upper and lower border.
31 : // For Union, Intersect, Xor and Exclude operations rectangles of
32 : // equal height are evaluated. The borders of the bands should always
33 : // be choosen such that this is possible.
34 :
35 : // If possible, rectangles within the bands are condensed.
36 :
37 : // When converting polygons all points of the polygon are registered
38 : // in the individual bands (for each band they are stored as
39 : // points in a list). After registration of these points they are
40 : // converted to rectangles and the points in the list are deleted.
41 :
42 0 : ImplRegionBand::ImplRegionBand( long nTop, long nBottom )
43 : {
44 : // save boundaries
45 0 : mnYTop = nTop;
46 0 : mnYBottom = nBottom;
47 :
48 : // initialize lists
49 0 : mpNextBand = NULL;
50 0 : mpPrevBand = NULL;
51 0 : mpFirstSep = NULL;
52 0 : mpFirstBandPoint = NULL;
53 0 : mbTouched = false;
54 0 : }
55 :
56 0 : ImplRegionBand::ImplRegionBand(
57 : const ImplRegionBand& rRegionBand,
58 : const bool bIgnorePoints)
59 : {
60 : // copy boundaries
61 0 : mnYTop = rRegionBand.mnYTop;
62 0 : mnYBottom = rRegionBand.mnYBottom;
63 0 : mbTouched = rRegionBand.mbTouched;
64 :
65 : // initialisation
66 0 : mpNextBand = NULL;
67 0 : mpPrevBand = NULL;
68 0 : mpFirstSep = NULL;
69 0 : mpFirstBandPoint = NULL;
70 :
71 : // copy all elements of the list with separations
72 : ImplRegionBandSep* pNewSep;
73 0 : ImplRegionBandSep* pPrevSep = 0;
74 0 : ImplRegionBandSep* pSep = rRegionBand.mpFirstSep;
75 0 : while ( pSep )
76 : {
77 : // create new and copy data
78 0 : pNewSep = new ImplRegionBandSep;
79 0 : pNewSep->mnXLeft = pSep->mnXLeft;
80 0 : pNewSep->mnXRight = pSep->mnXRight;
81 0 : pNewSep->mbRemoved = pSep->mbRemoved;
82 0 : pNewSep->mpNextSep = NULL;
83 0 : if ( pSep == rRegionBand.mpFirstSep )
84 0 : mpFirstSep = pNewSep;
85 : else
86 0 : pPrevSep->mpNextSep = pNewSep;
87 :
88 0 : pPrevSep = pNewSep;
89 0 : pSep = pSep->mpNextSep;
90 : }
91 :
92 0 : if ( ! bIgnorePoints)
93 : {
94 : // Copy points.
95 0 : ImplRegionBandPoint* pPoint = rRegionBand.mpFirstBandPoint;
96 0 : ImplRegionBandPoint* pPrevPointCopy = NULL;
97 0 : while (pPoint != NULL)
98 : {
99 0 : ImplRegionBandPoint* pPointCopy = new ImplRegionBandPoint();
100 0 : pPointCopy->mnX = pPoint->mnX;
101 0 : pPointCopy->mnLineId = pPoint->mnLineId;
102 0 : pPointCopy->mbEndPoint = pPoint->mbEndPoint;
103 0 : pPointCopy->meLineType = pPoint->meLineType;
104 :
105 0 : if (pPrevPointCopy != NULL)
106 0 : pPrevPointCopy->mpNextBandPoint = pPointCopy;
107 : else
108 0 : mpFirstBandPoint = pPointCopy;
109 :
110 0 : pPrevPointCopy = pPointCopy;
111 0 : pPoint = pPoint->mpNextBandPoint;
112 : }
113 : }
114 0 : }
115 :
116 0 : ImplRegionBand::~ImplRegionBand()
117 : {
118 : DBG_ASSERT( mpFirstBandPoint == NULL, "ImplRegionBand::~ImplRegionBand -> pointlist not empty" );
119 :
120 : // delete elements of the list
121 0 : ImplRegionBandSep* pSep = mpFirstSep;
122 0 : while ( pSep )
123 : {
124 0 : ImplRegionBandSep* pTempSep = pSep->mpNextSep;
125 0 : delete pSep;
126 0 : pSep = pTempSep;
127 : }
128 :
129 : // delete elements of the list
130 0 : ImplRegionBandPoint* pPoint = mpFirstBandPoint;
131 0 : while ( pPoint )
132 : {
133 0 : ImplRegionBandPoint* pTempPoint = pPoint->mpNextBandPoint;
134 0 : delete pPoint;
135 0 : pPoint = pTempPoint;
136 : }
137 0 : }
138 :
139 : // generate separations from lines and process union with existing
140 : // separations
141 :
142 0 : void ImplRegionBand::ProcessPoints()
143 : {
144 : // check Pointlist
145 0 : ImplRegionBandPoint* pRegionBandPoint = mpFirstBandPoint;
146 0 : while ( pRegionBandPoint )
147 : {
148 : // within list?
149 0 : if ( pRegionBandPoint->mpNextBandPoint )
150 : {
151 : // start/stop?
152 0 : if ( pRegionBandPoint->mbEndPoint && pRegionBandPoint->mpNextBandPoint->mbEndPoint )
153 : {
154 : // same direction? -> remove next point!
155 0 : if ( pRegionBandPoint->meLineType == pRegionBandPoint->mpNextBandPoint->meLineType )
156 : {
157 0 : ImplRegionBandPoint* pSaveRegionBandPoint = pRegionBandPoint->mpNextBandPoint;
158 0 : pRegionBandPoint->mpNextBandPoint = pRegionBandPoint->mpNextBandPoint->mpNextBandPoint;
159 0 : delete pSaveRegionBandPoint;
160 : }
161 : }
162 : }
163 :
164 : // continue with next element in the list
165 0 : pRegionBandPoint = pRegionBandPoint->mpNextBandPoint;
166 : }
167 :
168 0 : pRegionBandPoint = mpFirstBandPoint;
169 0 : while ( pRegionBandPoint && pRegionBandPoint->mpNextBandPoint )
170 : {
171 0 : Union( pRegionBandPoint->mnX, pRegionBandPoint->mpNextBandPoint->mnX );
172 :
173 0 : ImplRegionBandPoint* pNextBandPoint = pRegionBandPoint->mpNextBandPoint->mpNextBandPoint;
174 :
175 : // remove already processed points
176 0 : delete pRegionBandPoint->mpNextBandPoint;
177 0 : delete pRegionBandPoint;
178 :
179 : // continue with next element in the list
180 0 : pRegionBandPoint = pNextBandPoint;
181 : }
182 :
183 : // remove last element if necessary
184 0 : delete pRegionBandPoint;
185 :
186 : // list is now empty
187 0 : mpFirstBandPoint = NULL;
188 0 : }
189 :
190 : // generate separations from lines and process union with existing
191 : // separations
192 :
193 0 : bool ImplRegionBand::InsertPoint( long nX, long nLineId,
194 : bool bEndPoint, LineType eLineType )
195 : {
196 0 : if ( !mpFirstBandPoint )
197 : {
198 0 : mpFirstBandPoint = new ImplRegionBandPoint;
199 0 : mpFirstBandPoint->mnX = nX;
200 0 : mpFirstBandPoint->mnLineId = nLineId;
201 0 : mpFirstBandPoint->mbEndPoint = bEndPoint;
202 0 : mpFirstBandPoint->meLineType = eLineType;
203 0 : mpFirstBandPoint->mpNextBandPoint = NULL;
204 0 : return true;
205 : }
206 :
207 : // look if line already touched the band
208 0 : ImplRegionBandPoint* pRegionBandPoint = mpFirstBandPoint;
209 0 : ImplRegionBandPoint* pLastTestedRegionBandPoint = NULL;
210 0 : while( pRegionBandPoint )
211 : {
212 0 : if ( pRegionBandPoint->mnLineId == nLineId )
213 : {
214 0 : if ( bEndPoint )
215 : {
216 0 : if( !pRegionBandPoint->mbEndPoint )
217 : {
218 : // remove old band point
219 0 : if( !mpFirstBandPoint->mpNextBandPoint )
220 : {
221 : // if we've only got one point => replace first point
222 0 : pRegionBandPoint->mnX = nX;
223 0 : pRegionBandPoint->mbEndPoint = true;
224 0 : return true;
225 : }
226 : else
227 : {
228 : // remove current point
229 0 : if( !pLastTestedRegionBandPoint )
230 : {
231 : // remove and delete old first point
232 0 : ImplRegionBandPoint* pSaveBandPoint = mpFirstBandPoint;
233 0 : mpFirstBandPoint = mpFirstBandPoint->mpNextBandPoint;
234 0 : delete pSaveBandPoint;
235 : }
236 : else
237 : {
238 : // remove and delete current band point
239 0 : pLastTestedRegionBandPoint->mpNextBandPoint = pRegionBandPoint->mpNextBandPoint;
240 0 : delete pRegionBandPoint;
241 : }
242 :
243 0 : break;
244 : }
245 : }
246 : }
247 : else
248 0 : return false;
249 : }
250 :
251 : // use next element
252 0 : pLastTestedRegionBandPoint = pRegionBandPoint;
253 0 : pRegionBandPoint = pRegionBandPoint->mpNextBandPoint;
254 : }
255 :
256 : // search appropriate position and insert point into the list
257 : ImplRegionBandPoint* pNewRegionBandPoint;
258 :
259 0 : pRegionBandPoint = mpFirstBandPoint;
260 0 : pLastTestedRegionBandPoint = NULL;
261 0 : while ( pRegionBandPoint )
262 : {
263 : // new point completely left? -> insert as first point
264 0 : if ( nX <= pRegionBandPoint->mnX )
265 : {
266 0 : pNewRegionBandPoint = new ImplRegionBandPoint;
267 0 : pNewRegionBandPoint->mnX = nX;
268 0 : pNewRegionBandPoint->mnLineId = nLineId;
269 0 : pNewRegionBandPoint->mbEndPoint = bEndPoint;
270 0 : pNewRegionBandPoint->meLineType = eLineType;
271 0 : pNewRegionBandPoint->mpNextBandPoint = pRegionBandPoint;
272 :
273 : // connections to the new point
274 0 : if ( !pLastTestedRegionBandPoint )
275 0 : mpFirstBandPoint = pNewRegionBandPoint;
276 : else
277 0 : pLastTestedRegionBandPoint->mpNextBandPoint = pNewRegionBandPoint;
278 :
279 0 : return true;
280 : }
281 :
282 : // use next element
283 0 : pLastTestedRegionBandPoint = pRegionBandPoint;
284 0 : pRegionBandPoint = pRegionBandPoint->mpNextBandPoint;
285 : }
286 :
287 : // not inserted -> add to the end of the list
288 0 : pNewRegionBandPoint = new ImplRegionBandPoint;
289 0 : pNewRegionBandPoint->mnX = nX;
290 0 : pNewRegionBandPoint->mnLineId = nLineId;
291 0 : pNewRegionBandPoint->mbEndPoint = bEndPoint;
292 0 : pNewRegionBandPoint->meLineType = eLineType;
293 0 : pNewRegionBandPoint->mpNextBandPoint = NULL;
294 :
295 : // connections to the new point
296 0 : pLastTestedRegionBandPoint->mpNextBandPoint = pNewRegionBandPoint;
297 :
298 0 : return true;
299 : }
300 :
301 0 : void ImplRegionBand::MoveX( long nHorzMove )
302 : {
303 : // move all x-separations
304 0 : ImplRegionBandSep* pSep = mpFirstSep;
305 0 : while ( pSep )
306 : {
307 0 : pSep->mnXLeft += nHorzMove;
308 0 : pSep->mnXRight += nHorzMove;
309 0 : pSep = pSep->mpNextSep;
310 : }
311 0 : }
312 :
313 0 : void ImplRegionBand::ScaleX( double fHorzScale )
314 : {
315 0 : ImplRegionBandSep* pSep = mpFirstSep;
316 0 : while ( pSep )
317 : {
318 0 : pSep->mnXLeft = FRound( pSep->mnXLeft * fHorzScale );
319 0 : pSep->mnXRight = FRound( pSep->mnXRight * fHorzScale );
320 0 : pSep = pSep->mpNextSep;
321 : }
322 0 : }
323 :
324 : // combine overlapping separations
325 :
326 0 : bool ImplRegionBand::OptimizeBand()
327 : {
328 0 : ImplRegionBandSep* pPrevSep = 0;
329 0 : ImplRegionBandSep* pSep = mpFirstSep;
330 0 : while ( pSep )
331 : {
332 : // remove?
333 0 : if ( pSep->mbRemoved || (pSep->mnXRight < pSep->mnXLeft) )
334 : {
335 0 : ImplRegionBandSep* pOldSep = pSep;
336 0 : if ( pSep == mpFirstSep )
337 0 : mpFirstSep = pSep->mpNextSep;
338 : else
339 0 : pPrevSep->mpNextSep = pSep->mpNextSep;
340 0 : pSep = pSep->mpNextSep;
341 0 : delete pOldSep;
342 0 : continue;
343 : }
344 :
345 : // overlapping separations? -> combine!
346 0 : if ( pSep->mpNextSep )
347 : {
348 0 : if ( (pSep->mnXRight+1) >= pSep->mpNextSep->mnXLeft )
349 : {
350 0 : if ( pSep->mpNextSep->mnXRight > pSep->mnXRight )
351 0 : pSep->mnXRight = pSep->mpNextSep->mnXRight;
352 :
353 0 : ImplRegionBandSep* pOldSep = pSep->mpNextSep;
354 0 : pSep->mpNextSep = pOldSep->mpNextSep;
355 0 : delete pOldSep;
356 0 : continue;
357 : }
358 : }
359 :
360 0 : pPrevSep = pSep;
361 0 : pSep = pSep->mpNextSep;
362 : }
363 :
364 0 : return true;
365 : }
366 :
367 0 : void ImplRegionBand::Union( long nXLeft, long nXRight )
368 : {
369 : DBG_ASSERT( nXLeft <= nXRight, "ImplRegionBand::Union(): nxLeft > nXRight" );
370 :
371 : // band empty? -> add element
372 0 : if ( !mpFirstSep )
373 : {
374 0 : mpFirstSep = new ImplRegionBandSep;
375 0 : mpFirstSep->mnXLeft = nXLeft;
376 0 : mpFirstSep->mnXRight = nXRight;
377 0 : mpFirstSep->mbRemoved = false;
378 0 : mpFirstSep->mpNextSep = NULL;
379 0 : return;
380 : }
381 :
382 : // process real union
383 : ImplRegionBandSep* pNewSep;
384 0 : ImplRegionBandSep* pPrevSep = 0;
385 0 : ImplRegionBandSep* pSep = mpFirstSep;
386 0 : while ( pSep )
387 : {
388 : // new separation completely inside? nothing to do!
389 0 : if ( (nXLeft >= pSep->mnXLeft) && (nXRight <= pSep->mnXRight) )
390 0 : return;
391 :
392 : // new separation completely left? -> new separation!
393 0 : if ( nXRight < pSep->mnXLeft )
394 : {
395 0 : pNewSep = new ImplRegionBandSep;
396 0 : pNewSep->mnXLeft = nXLeft;
397 0 : pNewSep->mnXRight = nXRight;
398 0 : pNewSep->mbRemoved = false;
399 :
400 0 : pNewSep->mpNextSep = pSep;
401 0 : if ( pSep == mpFirstSep )
402 0 : mpFirstSep = pNewSep;
403 : else
404 0 : pPrevSep->mpNextSep = pNewSep;
405 0 : break;
406 : }
407 :
408 : // new separation overlapping from left? -> extend boundary
409 0 : if ( (nXRight >= pSep->mnXLeft) && (nXLeft <= pSep->mnXLeft) )
410 0 : pSep->mnXLeft = nXLeft;
411 :
412 : // new separation overlapping from right? -> extend boundary
413 0 : if ( (nXLeft <= pSep->mnXRight) && (nXRight > pSep->mnXRight) )
414 : {
415 0 : pSep->mnXRight = nXRight;
416 0 : break;
417 : }
418 :
419 : // not inserted, but last element? -> add to the end of the list
420 0 : if ( !pSep->mpNextSep && (nXLeft > pSep->mnXRight) )
421 : {
422 0 : pNewSep = new ImplRegionBandSep;
423 0 : pNewSep->mnXLeft = nXLeft;
424 0 : pNewSep->mnXRight = nXRight;
425 0 : pNewSep->mbRemoved = false;
426 :
427 0 : pSep->mpNextSep = pNewSep;
428 0 : pNewSep->mpNextSep = NULL;
429 0 : break;
430 : }
431 :
432 0 : pPrevSep = pSep;
433 0 : pSep = pSep->mpNextSep;
434 : }
435 :
436 0 : OptimizeBand();
437 : }
438 :
439 0 : void ImplRegionBand::Intersect( long nXLeft, long nXRight )
440 : {
441 : DBG_ASSERT( nXLeft <= nXRight, "ImplRegionBand::Intersect(): nxLeft > nXRight" );
442 :
443 : // band has been touched
444 0 : mbTouched = true;
445 :
446 : // band empty? -> nothing to do
447 0 : if ( !mpFirstSep )
448 0 : return;
449 :
450 : // process real intersection
451 0 : ImplRegionBandSep* pSep = mpFirstSep;
452 0 : while ( pSep )
453 : {
454 : // new separation completely outside? -> remove separation
455 0 : if ( (nXRight < pSep->mnXLeft) || (nXLeft > pSep->mnXRight) )
456 : // will be removed from the optimizer
457 0 : pSep->mbRemoved = true;
458 :
459 : // new separation overlapping from left? -> reduce right boundary
460 0 : if ( (nXLeft <= pSep->mnXLeft) &&
461 0 : (nXRight <= pSep->mnXRight) &&
462 0 : (nXRight >= pSep->mnXLeft) )
463 0 : pSep->mnXRight = nXRight;
464 :
465 : // new separation overlapping from right? -> reduce right boundary
466 0 : if ( (nXLeft >= pSep->mnXLeft) &&
467 0 : (nXLeft <= pSep->mnXRight) &&
468 0 : (nXRight >= pSep->mnXRight) )
469 0 : pSep->mnXLeft = nXLeft;
470 :
471 : // new separation within the actual one? -> reduce both boundaries
472 0 : if ( (nXLeft >= pSep->mnXLeft) && (nXRight <= pSep->mnXRight) )
473 : {
474 0 : pSep->mnXRight = nXRight;
475 0 : pSep->mnXLeft = nXLeft;
476 : }
477 :
478 0 : pSep = pSep->mpNextSep;
479 : }
480 :
481 0 : OptimizeBand();
482 : }
483 :
484 0 : void ImplRegionBand::Exclude( long nXLeft, long nXRight )
485 : {
486 : DBG_ASSERT( nXLeft <= nXRight, "ImplRegionBand::Exclude(): nxLeft > nXRight" );
487 :
488 : // band has been touched
489 0 : mbTouched = true;
490 :
491 : // band empty? -> nothing to do
492 0 : if ( !mpFirstSep )
493 0 : return;
494 :
495 : // process real exclusion
496 : ImplRegionBandSep* pNewSep;
497 0 : ImplRegionBandSep* pPrevSep = 0;
498 0 : ImplRegionBandSep* pSep = mpFirstSep;
499 0 : while ( pSep )
500 : {
501 0 : bool bSepProcessed = false;
502 :
503 : // new separation completely overlapping? -> remove separation
504 0 : if ( (nXLeft <= pSep->mnXLeft) && (nXRight >= pSep->mnXRight) )
505 : {
506 : // will be removed from the optimizer
507 0 : pSep->mbRemoved = true;
508 0 : bSepProcessed = true;
509 : }
510 :
511 : // new separation overlapping from left? -> reduce boundary
512 0 : if ( !bSepProcessed )
513 : {
514 0 : if ( (nXRight >= pSep->mnXLeft) && (nXLeft <= pSep->mnXLeft) )
515 : {
516 0 : pSep->mnXLeft = nXRight+1;
517 0 : bSepProcessed = true;
518 : }
519 : }
520 :
521 : // new separation overlapping from right? -> reduce boundary
522 0 : if ( !bSepProcessed )
523 : {
524 0 : if ( (nXLeft <= pSep->mnXRight) && (nXRight > pSep->mnXRight) )
525 : {
526 0 : pSep->mnXRight = nXLeft-1;
527 0 : bSepProcessed = true;
528 : }
529 : }
530 :
531 : // new separation within the actual one? -> reduce boundary
532 : // and add new entry for reminder
533 0 : if ( !bSepProcessed )
534 : {
535 0 : if ( (nXLeft >= pSep->mnXLeft) && (nXRight <= pSep->mnXRight) )
536 : {
537 0 : pNewSep = new ImplRegionBandSep;
538 0 : pNewSep->mnXLeft = pSep->mnXLeft;
539 0 : pNewSep->mnXRight = nXLeft-1;
540 0 : pNewSep->mbRemoved = false;
541 :
542 0 : pSep->mnXLeft = nXRight+1;
543 :
544 : // connections from the new separation
545 0 : pNewSep->mpNextSep = pSep;
546 :
547 : // connections to the new separation
548 0 : if ( pSep == mpFirstSep )
549 0 : mpFirstSep = pNewSep;
550 : else
551 0 : pPrevSep->mpNextSep = pNewSep;
552 : }
553 : }
554 :
555 0 : pPrevSep = pSep;
556 0 : pSep = pSep->mpNextSep;
557 : }
558 :
559 0 : OptimizeBand();
560 : }
561 :
562 0 : void ImplRegionBand::XOr( long nXLeft, long nXRight )
563 : {
564 : DBG_ASSERT( nXLeft <= nXRight, "ImplRegionBand::XOr(): nxLeft > nXRight" );
565 :
566 : // #i46602# Reworked rectangle Xor
567 :
568 : // In general, we can distinguish 11 cases of intersection
569 : // (details below). The old implementation explicitly handled 7
570 : // cases (numbered in the order of appearance, use CVS to get your
571 : // hands on the old version), therefore, I've sticked to that
572 : // order, and added four more cases. The code below references
573 : // those numbers via #1, #2, etc.
574 :
575 : // Num Mnem newX:oldX newY:oldY Description Result Can quit?
576 :
577 : // #1 Empty band - - The band is empty, thus, simply add new bandSep just add Yes
578 :
579 : // #2 apart - - The rectangles are disjunct, add new one as is just add Yes
580 :
581 : // #3 atop == == The rectangles are _exactly_ the same, remove existing just remove Yes
582 :
583 : // #4 around < > The new rectangle extends the old to both sides intersect No
584 :
585 : // #5 left < < The new rectangle is left of the old (but intersects) intersect Yes
586 :
587 : // #5b left-atop < == The new is left of the old, and coincides on the right intersect Yes
588 :
589 : // #6 right > > The new is right of the old (but intersects) intersect No
590 :
591 : // #6b right-atop == > The new is right of the old, and coincides on the left intersect No
592 :
593 : // #7 inside > < The new is fully inside the old intersect Yes
594 :
595 : // #8 inside-right > == The new is fully inside the old, coincides on the right intersect Yes
596 :
597 : // #9 inside-left == < The new is fully inside the old, coincides on the left intersect Yes
598 :
599 : // Then, to correctly perform XOr, the segment that's switched off
600 : // (i.e. the overlapping part of the old and the new segment) must
601 : // be extended by one pixel value at each border:
602 : // 1 1
603 : // 0 4 0 4
604 : // 111100000001111
605 :
606 : // Clearly, the leading band sep now goes from 0 to 3, and the
607 : // trailing band sep from 11 to 14. This mimicks the xor look of a
608 : // bitmap operation.
609 :
610 : // band empty? -> add element
611 0 : if ( !mpFirstSep )
612 : {
613 0 : mpFirstSep = new ImplRegionBandSep;
614 0 : mpFirstSep->mnXLeft = nXLeft;
615 0 : mpFirstSep->mnXRight = nXRight;
616 0 : mpFirstSep->mbRemoved = false;
617 0 : mpFirstSep->mpNextSep = NULL;
618 0 : return;
619 : }
620 :
621 : // process real xor
622 : ImplRegionBandSep* pNewSep;
623 0 : ImplRegionBandSep* pPrevSep = 0;
624 0 : ImplRegionBandSep* pSep = mpFirstSep;
625 :
626 0 : while ( pSep )
627 : {
628 0 : long nOldLeft( pSep->mnXLeft );
629 0 : long nOldRight( pSep->mnXRight );
630 :
631 : // did the current segment actually touch the new rect? If
632 : // not, skip all comparisons, go on, loop and try to find
633 : // intersecting bandSep
634 0 : if( nXLeft <= nOldRight )
635 : {
636 0 : if( nXRight < nOldLeft )
637 : {
638 : // #2
639 :
640 : // add _before_ current bandSep
641 0 : pNewSep = new ImplRegionBandSep;
642 0 : pNewSep->mnXLeft = nXLeft;
643 0 : pNewSep->mnXRight = nXRight;
644 0 : pNewSep->mpNextSep = pSep;
645 0 : pNewSep->mbRemoved = false;
646 :
647 : // connections from the new separation
648 0 : pNewSep->mpNextSep = pSep;
649 :
650 : // connections to the new separation
651 0 : if ( pSep == mpFirstSep )
652 0 : mpFirstSep = pNewSep;
653 : else
654 0 : pPrevSep->mpNextSep = pNewSep;
655 0 : pPrevSep = NULL; // do not run accidentally into the "right" case when breaking the loop
656 0 : break;
657 : }
658 0 : else if( nXLeft == nOldLeft && nXRight == nOldRight )
659 : {
660 : // #3
661 0 : pSep->mbRemoved = true;
662 0 : pPrevSep = NULL; // do not run accidentally into the "right" case when breaking the loop
663 0 : break;
664 : }
665 0 : else if( nXLeft != nOldLeft && nXRight == nOldRight )
666 : {
667 : // # 5b, 8
668 0 : if( nXLeft < nOldLeft )
669 : {
670 0 : nXRight = nOldLeft; // 5b
671 : }
672 : else
673 : {
674 0 : nXRight = nXLeft; // 8
675 0 : nXLeft = nOldLeft;
676 : }
677 :
678 0 : pSep->mnXLeft = nXLeft;
679 0 : pSep->mnXRight = nXRight-1;
680 :
681 0 : pPrevSep = NULL; // do not run accidentally into the "right" case when breaking the loop
682 0 : break;
683 : }
684 0 : else if( nXLeft == nOldLeft && nXRight != nOldRight )
685 : {
686 : // # 6b, 9
687 :
688 0 : if( nXRight > nOldRight )
689 : {
690 0 : nXLeft = nOldRight+1; // 6b
691 :
692 : // cannot break here, simply mark segment as removed,
693 : // and go on with adapted nXLeft/nXRight
694 0 : pSep->mbRemoved = true;
695 : }
696 : else
697 : {
698 0 : pSep->mnXLeft = nXRight+1; // 9
699 :
700 0 : pPrevSep = NULL; // do not run accidentally into the "right" case when breaking the loop
701 0 : break;
702 : }
703 : }
704 : else // if( nXLeft != nOldLeft && nXRight != nOldRight ) follows automatically
705 : {
706 : // #4,5,6,7
707 : DBG_ASSERT( nXLeft != nOldLeft && nXRight != nOldRight,
708 : "ImplRegionBand::XOr(): Case 4,5,6,7 expected all coordinates to be not equal!" );
709 :
710 : // The plain-jane check would look like this:
711 :
712 : // if( nXLeft < nOldLeft )
713 : // {
714 : // // #4,5
715 : // if( nXRight > nOldRight )
716 : // {
717 : // // #4
718 : // }
719 : // else
720 : // {
721 : // // #5 done!
722 : // }
723 : // }
724 : // else
725 : // {
726 : // // #6,7
727 : // if( nXRight > nOldRight )
728 : // {
729 : // // #6
730 : // }
731 : // else
732 : // {
733 : // // #7 done!
734 : // }
735 : // }
736 :
737 : // but since we generally don't have to care whether
738 : // it's 4 or 6 (only that we must not stop processing
739 : // here), condensed that in such a way that only the
740 : // coordinates get shuffled into correct ordering.
741 :
742 0 : if( nXLeft < nOldLeft )
743 0 : ::std::swap( nOldLeft, nXLeft );
744 :
745 0 : bool bDone( false );
746 :
747 0 : if( nXRight < nOldRight )
748 : {
749 0 : ::std::swap( nOldRight, nXRight );
750 0 : bDone = true;
751 : }
752 :
753 : // now, nOldLeft<nXLeft<=nOldRight<nXRight always
754 : // holds. Note that we need the nXLeft<=nOldRight here, as
755 : // the intersection part might be only one pixel (original
756 : // nXLeft==nXRight)
757 : DBG_ASSERT( nOldLeft<nXLeft && nXLeft<=nOldRight && nOldRight<nXRight,
758 : "ImplRegionBand::XOr(): Case 4,5,6,7 expected coordinates to be ordered now!" );
759 :
760 0 : pSep->mnXLeft = nOldLeft;
761 0 : pSep->mnXRight = nXLeft-1;
762 :
763 0 : nXLeft = nOldRight+1;
764 : // nxRight is already setup correctly
765 :
766 0 : if( bDone )
767 : {
768 : // add behind current bandSep
769 0 : pNewSep = new ImplRegionBandSep;
770 :
771 0 : pNewSep->mnXLeft = nXLeft;
772 0 : pNewSep->mnXRight = nXRight;
773 0 : pNewSep->mpNextSep = pSep->mpNextSep;
774 0 : pNewSep->mbRemoved = false;
775 :
776 : // connections from the new separation
777 0 : pSep->mpNextSep = pNewSep;
778 :
779 0 : pPrevSep = NULL; // do not run accidentally into the "right" case when breaking the loop
780 0 : break;
781 : }
782 : }
783 : }
784 :
785 0 : pPrevSep = pSep;
786 0 : pSep = pSep->mpNextSep;
787 : }
788 :
789 : // new separation completely right of existing bandSeps ?
790 0 : if( pPrevSep && nXLeft >= pPrevSep->mnXRight )
791 : {
792 0 : pNewSep = new ImplRegionBandSep;
793 0 : pNewSep->mnXLeft = nXLeft;
794 0 : pNewSep->mnXRight = nXRight;
795 0 : pNewSep->mpNextSep = NULL;
796 0 : pNewSep->mbRemoved = false;
797 :
798 : // connections from the new separation
799 0 : pPrevSep->mpNextSep = pNewSep;
800 : }
801 :
802 0 : OptimizeBand();
803 : }
804 :
805 0 : bool ImplRegionBand::IsInside( long nX )
806 : {
807 0 : ImplRegionBandSep* pSep = mpFirstSep;
808 0 : while ( pSep )
809 : {
810 0 : if ( (pSep->mnXLeft <= nX) && (pSep->mnXRight >= nX) )
811 0 : return true;
812 :
813 0 : pSep = pSep->mpNextSep;
814 : }
815 :
816 0 : return false;
817 : }
818 :
819 0 : long ImplRegionBand::GetXLeftBoundary() const
820 : {
821 : DBG_ASSERT( mpFirstSep != NULL, "ImplRegionBand::XLeftBoundary -> no separation in band!" );
822 :
823 0 : return mpFirstSep->mnXLeft;
824 : }
825 :
826 0 : long ImplRegionBand::GetXRightBoundary() const
827 : {
828 : DBG_ASSERT( mpFirstSep != NULL, "ImplRegionBand::XRightBoundary -> no separation in band!" );
829 :
830 : // search last separation
831 0 : ImplRegionBandSep* pSep = mpFirstSep;
832 0 : while ( pSep->mpNextSep )
833 0 : pSep = pSep->mpNextSep;
834 0 : return pSep->mnXRight;
835 : }
836 :
837 0 : bool ImplRegionBand::operator==( const ImplRegionBand& rRegionBand ) const
838 : {
839 0 : ImplRegionBandSep* pOwnRectBandSep = mpFirstSep;
840 0 : ImplRegionBandSep* pSecondRectBandSep = rRegionBand.mpFirstSep;
841 0 : while ( pOwnRectBandSep && pSecondRectBandSep )
842 : {
843 : // get boundaries of current rectangle
844 0 : long nOwnXLeft = pOwnRectBandSep->mnXLeft;
845 0 : long nSecondXLeft = pSecondRectBandSep->mnXLeft;
846 0 : if ( nOwnXLeft != nSecondXLeft )
847 0 : return false;
848 :
849 0 : long nOwnXRight = pOwnRectBandSep->mnXRight;
850 0 : long nSecondXRight = pSecondRectBandSep->mnXRight;
851 0 : if ( nOwnXRight != nSecondXRight )
852 0 : return false;
853 :
854 : // get next separation from current band
855 0 : pOwnRectBandSep = pOwnRectBandSep->mpNextSep;
856 :
857 : // get next separation from current band
858 0 : pSecondRectBandSep = pSecondRectBandSep->mpNextSep;
859 : }
860 :
861 : // different number of separations?
862 0 : if ( pOwnRectBandSep || pSecondRectBandSep )
863 0 : return false;
864 :
865 0 : return true;
866 : }
867 :
868 0 : ImplRegionBand* ImplRegionBand::SplitBand (const sal_Int32 nY)
869 : {
870 : OSL_ASSERT(nY>mnYTop);
871 : OSL_ASSERT(nY<=mnYBottom);
872 :
873 : // Create a copy of the given band (we tell the constructor to copy the points together
874 : // with the seps.)
875 0 : ImplRegionBand* pLowerBand = new ImplRegionBand(*this, false);
876 :
877 : // Adapt vertical coordinates.
878 0 : mnYBottom = nY-1;
879 0 : pLowerBand->mnYTop = nY;
880 :
881 : // Insert new band into list of bands.
882 0 : pLowerBand->mpNextBand = mpNextBand;
883 0 : mpNextBand = pLowerBand;
884 0 : pLowerBand->mpPrevBand = this;
885 0 : if (pLowerBand->mpNextBand != NULL)
886 0 : pLowerBand->mpNextBand->mpPrevBand = pLowerBand;
887 :
888 0 : return pLowerBand;
889 : }
890 :
891 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|