OpenCPN Partial API docs
Loading...
Searching...
No Matches
OCPNRegion.cpp
1/***************************************************************************
2 *
3 * Project: OpenCPN
4 *
5 ***************************************************************************
6 * Portins Copyright (C) 2010 by David S. Register *
7 * *
8 * This program is free software; you can redistribute it and/or modify *
9 * it under the terms of the GNU General Public License as published by *
10 * the Free Software Foundation; either version 2 of the License, or *
11 * (at your option) any later version. *
12 * *
13 * This program is distributed in the hope that it will be useful, *
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
16 * GNU General Public License for more details. *
17 * *
18 * You should have received a copy of the GNU General Public License *
19 * along with this program; if not, write to the *
20 * Free Software Foundation, Inc., *
21 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
22 ***************************************************************************
23 */
24
26// Name: src/gtk/region.cpp
27// Purpose:
28// Author: Robert Roebling
29// Modified: VZ at 05.10.00: use AllocExclusive(), comparison fixed
30// Id: $Id: region.cpp 42903 2006-11-01 12:56:38Z RR $
31// Copyright: (c) 1998 Robert Roebling
32// Licence: wxWindows licence
34
35// ============================================================================
36// declarations
37// ============================================================================
38
39// ----------------------------------------------------------------------------
40// headers
41// ----------------------------------------------------------------------------
42
43// For compilers that support precompilation, includes "wx.h".
44#include <wx/wxprec.h>
45
46#include <wx/region.h>
47#include "OCPNRegion.h"
48
49#ifndef WX_PRECOMP
50#include <wx/log.h>
51#endif
52
53typedef enum { OGDK_EVEN_ODD_RULE, OGDK_WINDING_RULE } OGdkFillRule;
54
55typedef enum {
56 OGDK_OVERLAP_RECTANGLE_IN,
57 OGDK_OVERLAP_RECTANGLE_OUT,
58 OGDK_OVERLAP_RECTANGLE_PART
59} OGdkOverlapType;
60
61#define EMPTY_REGION(pReg) pReg->numRects = 0
62#define REGION_NOT_EMPTY(pReg) pReg->numRects
63
64typedef struct _OGdkPoint OGdkPoint;
65struct _OGdkPoint {
66 int x;
67 int y;
68};
69
70typedef struct _OGdkRectangle OGdkRectangle;
72 int x;
73 int y;
74 int width;
75 int height;
76};
77
78// #define gboolean bool;
79
80typedef struct _OGdkSegment OGdkSegment;
82 int x1;
83 int y1;
84 int x2;
85 int y2;
86};
87
89
90typedef struct _OGdkRegion OGdkRegion;
92 long size;
93 long numRects;
94 OGdkRegionBox *rects;
95 OGdkRegionBox extents;
96};
97
98/*
99 * number of points to buffer before sending them off
100 * to scanlines() : Must be an even number
101 */
102#define NUMPTSTOBUFFER 200
103
104/*
105 * used to allocate buffers for points and link
106 * the buffers together
107 */
108typedef struct _OPOINTBLOCK {
109 OGdkPoint pts[NUMPTSTOBUFFER];
110 struct _OPOINTBLOCK *next;
112
113#define INBOX(r, x, y) \
114 ((((r).x2 > x)) && (((r).x1 <= x)) && (((r).y2 > y)) && (((r).y1 <= y)))
115
116/* 1 if two BOXs overlap.
117 * 0 if two BOXs do not overlap.
118 * Remember, x2 and y2 are not in the region
119 */
120#define EXTENTCHECK(r1, r2) \
121 ((r1)->x2 > (r2)->x1 && (r1)->x1 < (r2)->x2 && (r1)->y2 > (r2)->y1 && \
122 (r1)->y1 < (r2)->y2)
123
124/*
125 * #define _OG_NEW(struct_type, n_structs, func) \
126 * ((struct_type *) malloc ((n_structs), sizeof (struct_type)))
127 * #define _OG_RENEW(struct_type, mem, n_structs, func) \
128 * ((struct_type *) realloc (mem, (n_structs), sizeof (struct_type)))
129 *
130 * #define og_new(struct_type, n_structs) _OG_NEW
131 * (struct_type, n_structs, malloc) #define og_renew(struct_type, mem,
132 * n_structs) _OG_RENEW (struct_type, mem, n_structs, realloc)
133 */
134
135#define OGROWREGION(reg, nRects) \
136 { \
137 if ((nRects) == 0) { \
138 if ((reg)->rects != &(reg)->extents) { \
139 free((reg)->rects); \
140 (reg)->rects = &(reg)->extents; \
141 } \
142 } else if ((reg)->rects == &(reg)->extents) { \
143 (reg)->rects = (OGdkRegionBox *)malloc(nRects * sizeof(OGdkRegionBox)); \
144 (reg)->rects[0] = (reg)->extents; \
145 } else \
146 (reg)->rects = (OGdkRegionBox *)realloc((reg)->rects, \
147 sizeof(OGdkRegionBox) * nRects); \
148 (reg)->size = (nRects); \
149 }
150
151/*
152 * Check to see if there is enough memory in the present region.
153 */
154#define OMEMCHECK(reg, rect, firstrect) \
155 { \
156 if ((reg)->numRects >= ((reg)->size - 1)) { \
157 OGROWREGION(reg, 2 * (reg)->size); \
158 (rect) = &(firstrect)[(reg)->numRects]; \
159 } \
160 }
161
162#ifndef MIN
163#define MIN(a, b) wxMin(a, b)
164#endif
165
166#ifndef MAX
167#define MAX(a, b) wxMax(a, b)
168#endif
169
170/*
171 * In scan converting polygons, we want to choose those pixels
172 * which are inside the polygon. Thus, we add .5 to the starting
173 * x coordinate for both left and right edges. Now we choose the
174 * first pixel which is inside the pgon for the left edge and the
175 * first pixel which is outside the pgon for the right edge.
176 * Draw the left pixel, but not the right.
177 *
178 * How to add .5 to the starting x coordinate:
179 * If the edge is moving to the right, then subtract dy from the
180 * error term from the general form of the algorithm.
181 * If the edge is moving to the left, then add dy to the error term.
182 *
183 * The reason for the difference between edges moving to the left
184 * and edges moving to the right is simple: If an edge is moving
185 * to the right, then we want the algorithm to flip immediately.
186 * If it is moving to the left, then we don't want it to flip until
187 * we traverse an entire pixel.
188 */
189#define OBRESINITPGON(dy, x1, x2, xStart, d, m, m1, incr1, incr2) \
190 { \
191 int dx; /* local storage */ \
192 \
193 /* \
194 * if the edge is horizontal, then it is ignored \
195 * and assumed not to be processed. Otherwise, do this stuff. \
196 */ \
197 if ((dy) != 0) { \
198 xStart = (x1); \
199 dx = (x2) - xStart; \
200 if (dx < 0) { \
201 m = dx / (dy); \
202 m1 = m - 1; \
203 incr1 = -2 * dx + 2 * (dy) * m1; \
204 incr2 = -2 * dx + 2 * (dy) * m; \
205 d = 2 * m * (dy) - 2 * dx - 2 * (dy); \
206 } else { \
207 m = dx / (dy); \
208 m1 = m + 1; \
209 incr1 = 2 * dx - 2 * (dy) * m1; \
210 incr2 = 2 * dx - 2 * (dy) * m; \
211 d = -2 * m * (dy) + 2 * dx; \
212 } \
213 } \
214 }
215
216#define OBRESINCRPGON(d, minval, m, m1, incr1, incr2) \
217 { \
218 if (m1 > 0) { \
219 if (d > 0) { \
220 minval += m1; \
221 d += incr1; \
222 } else { \
223 minval += m; \
224 d += incr2; \
225 } \
226 } else { \
227 if (d >= 0) { \
228 minval += m1; \
229 d += incr1; \
230 } else { \
231 minval += m; \
232 d += incr2; \
233 } \
234 } \
235 }
236
237/*
238 * This structure contains all of the information needed
239 * to run the bresenham algorithm.
240 * The variables may be hardcoded into the declarations
241 * instead of using this structure to make use of
242 * register declarations.
243 */
244typedef struct {
245 int minor_axis; /* minor axis */
246 int d; /* decision variable */
247 int m, m1; /* slope and slope+1 */
248 int incr1, incr2; /* error increments */
249} OBRESINFO;
250
251#define OBRESINITPGONSTRUCT(dmaj, min1, min2, bres) \
252 OBRESINITPGON(dmaj, min1, min2, bres.minor_axis, bres.d, bres.m, bres.m1, \
253 bres.incr1, bres.incr2)
254
255#define OBRESINCRPGONSTRUCT(bres) \
256 OBRESINCRPGON(bres.d, bres.minor_axis, bres.m, bres.m1, bres.incr1, \
257 bres.incr2)
258
259/*
260 * for the winding number rule
261 */
262#define CLOCKWISE 1
263#define COUNTERCLOCKWISE -1
264
265typedef struct _OEdgeTableEntry {
266 int ymax; /* ycoord at which we exit this edge. */
267 OBRESINFO bres; /* Bresenham info to run the edge */
268 struct _OEdgeTableEntry *next; /* next in the list */
269 struct _OEdgeTableEntry *back; /* for insertion sort */
270 struct _OEdgeTableEntry *nextWETE; /* for winding num rule */
271 int ClockWise; /* flag for winding number rule */
273
274typedef struct _OScanLineList {
275 int scanline; /* the scanline represented */
276 OEdgeTableEntry *edgelist; /* header node */
277 struct _OScanLineList *next; /* next in the list */
279
280typedef struct {
281 int ymax; /* ymax for the polygon */
282 int ymin; /* ymin for the polygon */
283 OScanLineList scanlines; /* header node */
284} OEdgeTable;
285
286/*
287 * Here is a struct to help with storage allocation
288 * so we can allocate a big chunk at a time, and then take
289 * pieces from this heap when we need to.
290 */
291#define SLLSPERBLOCK 25
292
293typedef struct _OScanLineListBlock {
294 OScanLineList SLLs[SLLSPERBLOCK];
295 struct _OScanLineListBlock *next;
297
298/*
299 *
300 * a few macros for the inner loops of the fill code where
301 * performance considerations don't allow a procedure call.
302 *
303 * Evaluate the given edge at the given scanline.
304 * If the edge has expired, then we leave it and fix up
305 * the active edge table; otherwise, we increment the
306 * x value to be ready for the next scanline.
307 * The winding number rule is in effect, so we must notify
308 * the caller when the edge has been removed so he
309 * can reorder the Winding Active Edge Table.
310 */
311#define OEVALUATEEDGEWINDING(pAET, pPrevAET, y, fixWAET) \
312 { \
313 if (pAET->ymax == y) { /* leaving this edge */ \
314 pPrevAET->next = pAET->next; \
315 pAET = pPrevAET->next; \
316 fixWAET = 1; \
317 if (pAET) pAET->back = pPrevAET; \
318 } else { \
319 OBRESINCRPGONSTRUCT(pAET->bres); \
320 pPrevAET = pAET; \
321 pAET = pAET->next; \
322 } \
323 }
324
325/*
326 * Evaluate the given edge at the given scanline.
327 * If the edge has expired, then we leave it and fix up
328 * the active edge table; otherwise, we increment the
329 * x value to be ready for the next scanline.
330 * The even-odd rule is in effect.
331 */
332#define OEVALUATEEDGEEVENODD(pAET, pPrevAET, y) \
333 { \
334 if (pAET->ymax == y) { /* leaving this edge */ \
335 pPrevAET->next = pAET->next; \
336 pAET = pPrevAET->next; \
337 if (pAET) pAET->back = pPrevAET; \
338 } else { \
339 OBRESINCRPGONSTRUCT(pAET->bres); \
340 pPrevAET = pAET; \
341 pAET = pAET->next; \
342 } \
343 }
344
345OGdkRegion *gdk_region_copy(const OGdkRegion *region);
346void gdk_region_destroy(OGdkRegion *region);
347OGdkRegion *gdk_region_rectangle(const OGdkRectangle *rectangle);
348bool ogdk_region_equal(const OGdkRegion *region1, const OGdkRegion *region2);
349bool gdk_region_point_in(const OGdkRegion *region, int x, int y);
350OGdkOverlapType gdk_region_rect_in(const OGdkRegion *region,
351 const OGdkRectangle *rectangle);
352void gdk_region_offset(OGdkRegion *region, int dx, int dy);
353void gdk_region_union_with_rect(OGdkRegion *region, const OGdkRectangle *rect);
354void gdk_region_union(OGdkRegion *source1, const OGdkRegion *source2);
355void gdk_region_intersect(OGdkRegion *source1, const OGdkRegion *source2);
356OGdkRegion *gdk_region_polygon(const OGdkPoint *points, int n_points,
357 OGdkFillRule fill_rule);
358
359OGdkRegion *gdk_region_new(void);
360void gdk_region_subtract(OGdkRegion *source1, const OGdkRegion *source2);
361bool gdk_region_empty(const OGdkRegion *region);
362
363void gdk_region_get_rectangles(const OGdkRegion *region,
364 OGdkRectangle **rectangles, int *n_rectangles);
365void gdk_region_get_clipbox(const OGdkRegion *region, OGdkRectangle *rectangle);
366
367// ----------------------------------------------------------------------------
368// OCPNRegionRefData: private class containing the information about the region
369// ----------------------------------------------------------------------------
370
371class OCPNRegionRefData : public wxObjectRefData {
372public:
373 OCPNRegionRefData() { m_region = NULL; }
374
375 OCPNRegionRefData(const OCPNRegionRefData &refData) : wxObjectRefData() {
376 m_region = gdk_region_copy(refData.m_region);
377 }
378
379 virtual ~OCPNRegionRefData() {
380 if (m_region) gdk_region_destroy(m_region);
381 free(m_region);
382 }
383
384 OGdkRegion *m_region;
385};
386
387// ----------------------------------------------------------------------------
388// macros
389// ----------------------------------------------------------------------------
390
391#define M_REGIONDATA ((OCPNRegionRefData *)m_refData)
392#define M_REGIONDATA_OF(rgn) ((OCPNRegionRefData *)(rgn.m_refData))
393
394// ----------------------------------------------------------------------------
395// OCPNRegion construction
396// ----------------------------------------------------------------------------
397
398#define M_REGIONDATA ((OCPNRegionRefData *)m_refData)
399
400#ifndef USE_NEW_REGION
401
402OCPNRegion::OCPNRegion(wxCoord x, wxCoord y, wxCoord w, wxCoord h)
403 : wxRegion(x, y, w, h)
404
405{}
406
407OCPNRegion::OCPNRegion(const wxPoint &topLeft, const wxPoint &bottomRight)
408 : wxRegion(topLeft.x, topLeft.y, bottomRight.x - topLeft.x,
409 bottomRight.y - topLeft.y) {}
410
411OCPNRegion::OCPNRegion(const wxRect &rect)
412 : wxRegion(rect.x, rect.y, rect.width, rect.height) {}
413
414OCPNRegion::OCPNRegion(const wxRegion &region) : wxRegion(region) {}
415
416OCPNRegion::OCPNRegion(size_t n, const wxPoint *points, int fillStyle)
417 : wxRegion(n, points,
418#if wxCHECK_VERSION(2, 9, 0)
419 (wxPolygonFillMode)
420#endif
421 fillStyle) {
422}
423
424wxRegion *OCPNRegion::GetNew_wxRegion() const { return new wxRegion(this); }
425
426#endif
427
428#ifdef USE_NEW_REGION
429
430OCPNRegion::OCPNRegion(wxCoord x, wxCoord y, wxCoord w, wxCoord h) {
431 InitRect(x, y, w, h);
432}
433
434OCPNRegion::OCPNRegion(const wxPoint &topLeft, const wxPoint &bottomRight) {
435 InitRect(topLeft.x, topLeft.y, bottomRight.x - topLeft.x,
436 bottomRight.y - topLeft.y);
437}
438
439OCPNRegion::OCPNRegion(const wxRect &rect) {
440 InitRect(rect.x, rect.y, rect.width, rect.height);
441}
442
443OCPNRegion::OCPNRegion(const wxRegion &region) {
444 wxRegionIterator ri(region);
445 if (!ri.HaveRects()) return;
446
447 wxRect rect = ri.GetRect();
448 InitRect(rect.x, rect.y, rect.width, rect.height);
449 ri++;
450
451 while (ri.HaveRects()) {
452 Union(ri.GetRect());
453 ri++;
454 }
455}
456
457OCPNRegion::~OCPNRegion() {}
458
459void OCPNRegion::InitRect(wxCoord x, wxCoord y, wxCoord w, wxCoord h) {
460 OGdkRectangle rect;
461 rect.x = x;
462 rect.y = y;
463 rect.width = w;
464 rect.height = h;
465
466 m_refData = new OCPNRegionRefData();
467
468 M_REGIONDATA->m_region = gdk_region_rectangle(&rect);
469}
470
471// OCPNRegion::OCPNRegion( GdkRegion *region )
472//{
473// m_refData = new OCPNRegionRefData();
474// M_REGIONDATA->m_region = gdk_region_copy( region );
475//}
476
477OCPNRegion::OCPNRegion(size_t n, const wxPoint *points, int fillStyle) {
478 OGdkPoint *gdkpoints = new OGdkPoint[n];
479 for (size_t i = 0; i < n; i++) {
480 gdkpoints[i].x = points[i].x;
481 gdkpoints[i].y = points[i].y;
482 }
483
484 m_refData = new OCPNRegionRefData();
485
486 OGdkRegion *reg = gdk_region_polygon(
487 gdkpoints, n,
488 fillStyle == wxWINDING_RULE ? OGDK_WINDING_RULE : OGDK_EVEN_ODD_RULE);
489
490 M_REGIONDATA->m_region = reg;
491
492 delete[] gdkpoints;
493}
494
495// OCPNRegion::~OCPNRegion()
496//{
497// m_refData unrefed in ~wxObject
498//}
499
500wxObjectRefData *OCPNRegion::CreateRefData() const {
501 return new OCPNRegionRefData;
502}
503
504wxObjectRefData *OCPNRegion::CloneRefData(const wxObjectRefData *data) const {
505 return new OCPNRegionRefData(*(OCPNRegionRefData *)data);
506}
507
508// ----------------------------------------------------------------------------
509// OCPNRegion comparison
510// ----------------------------------------------------------------------------
511
512bool OCPNRegion::ODoIsEqual(const OCPNRegion &region) const {
513 if (!region.m_refData) return false;
514
515 return ogdk_region_equal(M_REGIONDATA->m_region,
516 M_REGIONDATA_OF(region)->m_region);
517}
518
519// ----------------------------------------------------------------------------
520// OCPNRegion operations
521// ----------------------------------------------------------------------------
522
523void OCPNRegion::Clear() { UnRef(); }
524
525bool OCPNRegion::ODoUnionWithRect(const wxRect &r) {
526 // workaround for a strange GTK/X11 bug: taking union with an empty
527 // rectangle results in an empty region which is definitely not what we
528 // want
529 if (r.IsEmpty()) return true;
530
531 if (!m_refData) {
532 InitRect(r.x, r.y, r.width, r.height);
533 } else {
534 AllocExclusive();
535
536 OGdkRectangle rect;
537 rect.x = r.x;
538 rect.y = r.y;
539 rect.width = r.width;
540 rect.height = r.height;
541
542 gdk_region_union_with_rect(M_REGIONDATA->m_region, &rect);
543 }
544
545 return true;
546}
547
548bool OCPNRegion::ODoUnionWithRegion(const OCPNRegion &region) {
549 wxCHECK_MSG(region.Ok(), false, _T("invalid region"));
550
551 if (!m_refData) {
552 m_refData = new OCPNRegionRefData();
553 M_REGIONDATA->m_region = gdk_region_new();
554 } else {
555 AllocExclusive();
556 }
557
558 gdk_region_union(M_REGIONDATA->m_region, (OGdkRegion *)region.GetRegion());
559
560 return true;
561}
562
563bool OCPNRegion::ODoIntersect(const OCPNRegion &region) {
564 wxCHECK_MSG(region.Ok(), false, _T("invalid region"));
565
566 if (!m_refData) {
567 // intersecting with invalid region doesn't make sense
568 return false;
569 }
570
571 AllocExclusive();
572
573 gdk_region_intersect(M_REGIONDATA->m_region,
574 (OGdkRegion *)region.GetRegion());
575
576 return true;
577}
578
579bool OCPNRegion::ODoSubtract(const OCPNRegion &region) {
580 wxCHECK_MSG(region.Ok(), false, _T("invalid region"));
581 if (!m_refData) {
582 // subtracting from an invalid region doesn't make sense
583 return false;
584 }
585
586 AllocExclusive();
587
588 gdk_region_subtract(M_REGIONDATA->m_region, (OGdkRegion *)region.GetRegion());
589
590 return true;
591}
592
593#if 0
594bool OCPNRegion::DoXor( const OCPNRegion& region )
595{
596 wxCHECK_MSG( region.Ok(), false, _T("invalid region") );
597
598 if (!m_refData)
599 {
600 return false;
601 }
602
603 AllocExclusive();
604
606
607 return true;
608}
609#endif
610
611bool OCPNRegion::ODoOffset(wxCoord x, wxCoord y) {
612 if (!m_refData) return false;
613
614 AllocExclusive();
615
616 gdk_region_offset(M_REGIONDATA->m_region, x, y);
617
618 return true;
619}
620
621// ----------------------------------------------------------------------------
622// OCPNRegion tests
623// ----------------------------------------------------------------------------
624
625bool OCPNRegion::ODoGetBox(wxCoord &x, wxCoord &y, wxCoord &w,
626 wxCoord &h) const {
627 if (m_refData) {
628 OGdkRectangle rect;
629 gdk_region_get_clipbox(M_REGIONDATA->m_region, &rect);
630 x = rect.x;
631 y = rect.y;
632 w = rect.width;
633 h = rect.height;
634
635 return true;
636 } else {
637 x = 0;
638 y = 0;
639 w = -1;
640 h = -1;
641
642 return false;
643 }
644}
645
646bool OCPNRegion::IsEmpty() const {
647 if (!m_refData) return true;
648
649 return gdk_region_empty(M_REGIONDATA->m_region);
650}
651
652wxRegionContain OCPNRegion::ODoContainsPoint(wxCoord x, wxCoord y) const {
653 if (!m_refData) return wxOutRegion;
654
655 if (gdk_region_point_in(M_REGIONDATA->m_region, x, y))
656 return wxInRegion;
657 else
658 return wxOutRegion;
659}
660
661wxRegionContain OCPNRegion::ODoContainsRect(const wxRect &r) const {
662 if (!m_refData) return wxOutRegion;
663
664 OGdkRectangle rect;
665 rect.x = r.x;
666 rect.y = r.y;
667 rect.width = r.width;
668 rect.height = r.height;
669 OGdkOverlapType res = gdk_region_rect_in(M_REGIONDATA->m_region, &rect);
670 switch (res) {
671 case OGDK_OVERLAP_RECTANGLE_IN:
672 return wxInRegion;
673 case OGDK_OVERLAP_RECTANGLE_OUT:
674 return wxOutRegion;
675 case OGDK_OVERLAP_RECTANGLE_PART:
676 return wxPartRegion;
677 }
678
679 return wxOutRegion;
680}
681
682void *OCPNRegion::GetRegion() const {
683 if (!m_refData) return NULL;
684
685 return M_REGIONDATA->m_region;
686}
687
688wxRegion *OCPNRegion::GetNew_wxRegion() const {
689 wxRegion *r = new wxRegion;
690 r->Clear();
691
692 OGdkRectangle *gdkrects = NULL;
693 int numRects = 0;
694 gdk_region_get_rectangles((OGdkRegion *)GetRegion(), &gdkrects, &numRects);
695
696 if (numRects) {
697 for (int i = 0; i < numRects; ++i) {
698 OGdkRectangle &gr = gdkrects[i];
699
700 wxRect wr;
701 wr.x = gr.x;
702 wr.y = gr.y;
703 wr.width = gr.width;
704 wr.height = gr.height;
705
706 r->Union(wr);
707 }
708 }
709 free(gdkrects);
710
711 return r;
712}
713
714#endif
715// ----------------------------------------------------------------------------
716// OCPNRegionIterator
717// ----------------------------------------------------------------------------
718
719#ifndef USE_NEW_REGION
720
721OCPNRegionIterator::OCPNRegionIterator(const OCPNRegion &region) {
722 m_ri = new wxRegionIterator(region);
723}
724
725OCPNRegionIterator::~OCPNRegionIterator() { delete m_ri; }
726
727void OCPNRegionIterator::Reset() { m_ri->Reset(); }
728
729void OCPNRegionIterator::Reset(const OCPNRegion &region) {
730 m_ri->Reset(region);
731}
732
733wxRect OCPNRegionIterator::GetRect() const { return m_ri->GetRect(); }
734
735bool OCPNRegionIterator::HaveRects() const { return m_ri->HaveRects(); }
736
737void OCPNRegionIterator::NextRect() { ++(*m_ri); }
738
739#endif
740
741#ifdef USE_NEW_REGION
742
743OCPNRegionIterator::OCPNRegionIterator() {
744 Init();
745 Reset();
746}
747
748OCPNRegionIterator::OCPNRegionIterator(const OCPNRegion &region) {
749 Init();
750 Reset(region);
751}
752
753void OCPNRegionIterator::Init() {
754 m_rects = NULL;
755 m_numRects = 0;
756}
757
758OCPNRegionIterator::~OCPNRegionIterator() { wxDELETEA(m_rects); }
759
760void OCPNRegionIterator::Reset() { m_current = 0u; }
761
762void OCPNRegionIterator::NextRect() {
763 if (HaveRects()) ++m_current;
764}
765
766void OCPNRegionIterator::CreateRects(const OCPNRegion &region) {
767 wxDELETEA(m_rects);
768 m_numRects = 0;
769
770 OGdkRegion *gdkregion = (OGdkRegion *)region.GetRegion();
771 if (!gdkregion) return;
772
773 OGdkRectangle *gdkrects = NULL;
774 int numRects = 0;
775 gdk_region_get_rectangles(gdkregion, &gdkrects, &numRects);
776
777 m_numRects = numRects;
778 if (numRects) {
779 m_rects = new wxRect[m_numRects];
780 for (size_t i = 0; i < m_numRects; ++i) {
781 OGdkRectangle &gr = gdkrects[i];
782 wxRect &wr = m_rects[i];
783 wr.x = gr.x;
784 wr.y = gr.y;
785 wr.width = gr.width;
786 wr.height = gr.height;
787 }
788 }
789 free(gdkrects);
790}
791
792void OCPNRegionIterator::Reset(const OCPNRegion &region) {
793 m_region = region;
794 CreateRects(region);
795 Reset();
796}
797
798bool OCPNRegionIterator::HaveRects() const { return m_current < m_numRects; }
799
800wxRect OCPNRegionIterator::GetRect() const {
801 wxRect r;
802 if (HaveRects()) r = m_rects[m_current];
803
804 return r;
805}
806
807#endif
808
809#ifdef USE_NEW_REGION
810
811/* $TOG: Region.c /main/31 1998/02/06 17:50:22 kaleb $ */
812/************************************************************************
813 *
814 * Copyright 1987, 1988, 1998 The Open Group
815 *
816 * All Rights Reserved.
817 *
818 * The above copyright notice and this permission notice shall be included in
819 * all copies or substantial portions of the Software.
820 *
821 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
822 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
823 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
824 * OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
825 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
826 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
827 *
828 * Except as contained in this notice, the name of The Open Group shall not be
829 * used in advertising or otherwise to promote the sale, use or other dealings
830 * in this Software without prior written authorization from The Open Group.
831 *
832 *
833 * Copyright 1987, 1988 by Digital Equipment Corporation, Maynard,
834 *Massachusetts.
835 *
836 * All Rights Reserved
837 *
838 * Permission to use, copy, modify, and distribute this software and its
839 * documentation for any purpose and without fee is hereby granted,
840 * provided that the above copyright notice appear in all copies and that
841 * both that copyright notice and this permission notice appear in
842 * supporting documentation, and that the name of Digital not be
843 * used in advertising or publicity pertaining to distribution of the
844 * software without specific, written prior permission.
845 *
846 * DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
847 * ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
848 * DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
849 * ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
850 * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
851 * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
852 * SOFTWARE.
853 *
854 ************************************************************************/
855/* $XFree86: xc/lib/X11/Region.c,v 1.5 1999/05/09 10:50:01 dawes Exp $ */
856/*
857 * The functions in this file implement the Region abstraction, similar to one
858 * used in the X11 sample server. A Region is simply an area, as the name
859 * implies, and is implemented as a "y-x-banded" array of rectangles. To
860 * explain: Each Region is made up of a certain number of rectangles sorted
861 * by y coordinate first, and then by x coordinate.
862 *
863 * Furthermore, the rectangles are banded such that every rectangle with a
864 * given upper-left y coordinate (y1) will have the same lower-right y
865 * coordinate (y2) and vice versa. If a rectangle has scanlines in a band, it
866 * will span the entire vertical distance of the band. This means that some
867 * areas that could be merged into a taller rectangle will be represented as
868 * several shorter rectangles to account for shorter rectangles to its left
869 * or right but within its "vertical scope".
870 *
871 * An added constraint on the rectangles is that they must cover as much
872 * horizontal area as possible. E.g. no two rectangles in a band are allowed
873 * to touch.
874 *
875 * Whenever possible, bands will be merged together to cover a greater vertical
876 * distance (and thus reduce the number of rectangles). Two bands can be merged
877 * only if the bottom of one touches the top of the other and they have
878 * rectangles in the same places (of the same width, of course). This maintains
879 * the y-x-banding that's so nice to have...
880 */
881
882// #include "config.h"
883// #include <stdlib.h>
884// #include <string.h>
885// #include <gdkregion.h>
886// #include "gdkregion-generic.h"
887// #include "gdkalias.h"
888
889typedef void (*overlapFunc)(OGdkRegion *pReg, OGdkRegionBox *r1,
890 OGdkRegionBox *r1End, OGdkRegionBox *r2,
891 OGdkRegionBox *r2End, int y1, int y2);
892typedef void (*nonOverlapFunc)(OGdkRegion *pReg, OGdkRegionBox *r,
893 OGdkRegionBox *rEnd, int y1, int y2);
894
895static void miRegionCopy(OGdkRegion *dstrgn, const OGdkRegion *rgn);
896static void miRegionOp(OGdkRegion *newReg, OGdkRegion *reg1,
897 const OGdkRegion *reg2, overlapFunc overlapFn,
898 nonOverlapFunc nonOverlap1Fn,
899 nonOverlapFunc nonOverlap2Fn);
900
908OGdkRegion *gdk_region_new(void) {
909 OGdkRegion *temp;
910
911 temp = (OGdkRegion *)malloc(sizeof(OGdkRegion));
912
913 temp->numRects = 0;
914 temp->rects = &temp->extents;
915 temp->extents.x1 = 0;
916 temp->extents.y1 = 0;
917 temp->extents.x2 = 0;
918 temp->extents.y2 = 0;
919 temp->size = 1;
920
921 return temp;
922}
923
932OGdkRegion *gdk_region_rectangle(const OGdkRectangle *rectangle) {
933 OGdkRegion *temp;
934
936
937 if (rectangle->width <= 0 || rectangle->height <= 0) return gdk_region_new();
938
939 temp = gdk_region_new();
940
941 temp->numRects = 1;
942 temp->rects = &temp->extents;
943 temp->extents.x1 = rectangle->x;
944 temp->extents.y1 = rectangle->y;
945 temp->extents.x2 = rectangle->x + rectangle->width;
946 temp->extents.y2 = rectangle->y + rectangle->height;
947 temp->size = 1;
948
949 return temp;
950}
951
960OGdkRegion *gdk_region_copy(const OGdkRegion *region) {
961 OGdkRegion *temp;
962
964
965 temp = gdk_region_new();
966
967 miRegionCopy(temp, region);
968
969 return temp;
970}
971
980void gdk_region_get_clipbox(const OGdkRegion *region,
981 OGdkRectangle *rectangle) {
984
985 rectangle->x = region->extents.x1;
986 rectangle->y = region->extents.y1;
987 rectangle->width = region->extents.x2 - region->extents.x1;
988 rectangle->height = region->extents.y2 - region->extents.y1;
989}
990
1000void gdk_region_get_rectangles(const OGdkRegion *region,
1001 OGdkRectangle **rectangles, int *n_rectangles) {
1002 int i;
1003
1007
1008 *n_rectangles = region->numRects;
1009 *rectangles =
1010 (OGdkRectangle *)malloc(sizeof(OGdkRectangle) * region->numRects);
1011
1012 for (i = 0; i < region->numRects; i++) {
1013 OGdkRegionBox rect;
1014 rect = region->rects[i];
1015 (*rectangles)[i].x = rect.x1;
1016 (*rectangles)[i].y = rect.y1;
1017 (*rectangles)[i].width = rect.x2 - rect.x1;
1018 (*rectangles)[i].height = rect.y2 - rect.y1;
1019 }
1020}
1021
1031void gdk_region_union_with_rect(OGdkRegion *region, const OGdkRectangle *rect) {
1032 OGdkRegion tmp_region;
1033
1034 // g_return_if_fail (region != NULL);
1035 // g_return_if_fail (rect != NULL);
1036
1037 if (rect->width <= 0 || rect->height <= 0) return;
1038
1039 tmp_region.rects = &tmp_region.extents;
1040 tmp_region.numRects = 1;
1041 tmp_region.extents.x1 = rect->x;
1042 tmp_region.extents.y1 = rect->y;
1043 tmp_region.extents.x2 = rect->x + rect->width;
1044 tmp_region.extents.y2 = rect->y + rect->height;
1045 tmp_region.size = 1;
1046
1047 gdk_region_union(region, &tmp_region);
1048}
1049
1050/*-
1051 * -----------------------------------------------------------------------
1052 * miSetExtents --
1053 * Reset the extents of a region to what they should be. Called by
1054 * miSubtract and miIntersect b/c they can't figure it out along the
1055 * way or do so easily, as miUnion can.
1056 *
1057 * Results:
1058 * None.
1059 *
1060 * Side Effects:
1061 * The region's 'extents' structure is overwritten.
1062 *
1063 *-----------------------------------------------------------------------
1064 */
1065static void miSetExtents(OGdkRegion *pReg) {
1066 OGdkRegionBox *pBox, *pBoxEnd, *pExtents;
1067
1068 if (pReg->numRects == 0) {
1069 pReg->extents.x1 = 0;
1070 pReg->extents.y1 = 0;
1071 pReg->extents.x2 = 0;
1072 pReg->extents.y2 = 0;
1073 return;
1074 }
1075
1076 pExtents = &pReg->extents;
1077 pBox = pReg->rects;
1078 pBoxEnd = &pBox[pReg->numRects - 1];
1079
1080 /*
1081 * Since pBox is the first rectangle in the region, it must have the
1082 * smallest y1 and since pBoxEnd is the last rectangle in the region,
1083 * it must have the largest y2, because of banding. Initialize x1 and
1084 * x2 from pBox and pBoxEnd, resp., as good things to initialize them
1085 * to...
1086 */
1087 pExtents->x1 = pBox->x1;
1088 pExtents->y1 = pBox->y1;
1089 pExtents->x2 = pBoxEnd->x2;
1090 pExtents->y2 = pBoxEnd->y2;
1091
1093 while (pBox <= pBoxEnd) {
1094 if (pBox->x1 < pExtents->x1) {
1095 pExtents->x1 = pBox->x1;
1096 }
1097 if (pBox->x2 > pExtents->x2) {
1098 pExtents->x2 = pBox->x2;
1099 }
1100 pBox++;
1101 }
1103}
1104
1111void gdk_region_destroy(OGdkRegion *region) {
1113
1114 if (region->rects != &region->extents) free(region->rects);
1116}
1117
1126void gdk_region_offset(OGdkRegion *region, int x, int y) {
1127 int nbox;
1128 OGdkRegionBox *pbox;
1129
1131
1132 pbox = region->rects;
1133 nbox = region->numRects;
1134
1135 while (nbox--) {
1136 pbox->x1 += x;
1137 pbox->x2 += x;
1138 pbox->y1 += y;
1139 pbox->y2 += y;
1140 pbox++;
1141 }
1142 if (region->rects != &region->extents) {
1143 region->extents.x1 += x;
1144 region->extents.x2 += x;
1145 region->extents.y1 += y;
1146 region->extents.y2 += y;
1147 }
1148}
1149
1150/*
1151 * Utility procedure Compress:
1152 * Replace r by the region r', where
1153 * p in r' iff (Quantifer m <= dx) (p + m in r), and
1154 * Quantifier is Exists if grow is TRUE, For all if grow is FALSE, and
1155 * (x,y) + m = (x+m,y) if xdir is TRUE; (x,y+m) if xdir is FALSE.
1156 *
1157 * Thus, if xdir is TRUE and grow is FALSE, r is replaced by the region
1158 * of all points p such that p and the next dx points on the same
1159 * horizontal scan line are all in r. We do this using by noting
1160 * that p is the head of a run of length 2^i + k iff p is the head
1161 * of a run of length 2^i and p+2^i is the head of a run of length
1162 * k. Thus, the loop invariant: s contains the region corresponding
1163 * to the runs of length shift. r contains the region corresponding
1164 * to the runs of length 1 + dxo & (shift-1), where dxo is the original
1165 * value of dx. dx = dxo & ~(shift-1). As parameters, s and t are
1166 * scratch regions, so that we don't have to allocate them on every
1167 * call.
1168 */
1169
1170#define ZOpRegion(a, b) \
1171 if (grow) \
1172 gdk_region_union(a, b); \
1173 else \
1174 gdk_region_intersect(a, b)
1175#define ZShiftRegion(a, b) \
1176 if (xdir) \
1177 gdk_region_offset(a, b, 0); \
1178 else \
1179 gdk_region_offset(a, 0, b)
1180
1181static void Compress(OGdkRegion *r, OGdkRegion *s, OGdkRegion *t,
1182 unsigned int dx, int xdir, int grow) {
1183 unsigned int shift = 1;
1184
1185 miRegionCopy(s, r);
1186 while (dx) {
1187 if (dx & shift) {
1188 ZShiftRegion(r, -(int)shift);
1189 ZOpRegion(r, s);
1190 dx -= shift;
1191 if (!dx) break;
1192 }
1193 miRegionCopy(t, s);
1194 ZShiftRegion(s, -(int)shift);
1195 ZOpRegion(s, t);
1196 shift <<= 1;
1197 }
1198}
1199
1200#undef ZOpRegion
1201#undef ZShiftRegion
1202#undef ZCopyRegion
1203
1213void gdk_region_shrink(OGdkRegion *region, int dx, int dy) {
1214 OGdkRegion *s, *t;
1215 int grow;
1216
1218
1219 if (!dx && !dy) return;
1220
1221 s = gdk_region_new();
1222 t = gdk_region_new();
1223
1224 grow = (dx < 0);
1225 if (grow) dx = -dx;
1226 if (dx) Compress(region, s, t, (unsigned)2 * dx, TRUE, grow);
1227
1228 grow = (dy < 0);
1229 if (grow) dy = -dy;
1230 if (dy) Compress(region, s, t, (unsigned)2 * dy, FALSE, grow);
1231
1232 gdk_region_offset(region, dx, dy);
1233 gdk_region_destroy(s);
1234 gdk_region_destroy(t);
1235}
1236
1237/*======================================================================
1238 * Region Intersection
1239 *====================================================================*/
1240/*-
1241 * -----------------------------------------------------------------------
1242 * miIntersectO --
1243 * Handle an overlapping band for miIntersect.
1244 *
1245 * Results:
1246 * None.
1247 *
1248 * Side Effects:
1249 * Rectangles may be added to the region.
1250 *
1251 *-----------------------------------------------------------------------
1252 */
1253/* static void*/
1254static void miIntersectO(OGdkRegion *pReg, OGdkRegionBox *r1,
1255 OGdkRegionBox *r1End, OGdkRegionBox *r2,
1256 OGdkRegionBox *r2End, int y1, int y2) {
1257 int x1;
1258 int x2;
1259 OGdkRegionBox *pNextRect;
1260
1261 pNextRect = &pReg->rects[pReg->numRects];
1262
1263 while ((r1 != r1End) && (r2 != r2End)) {
1264 x1 = MAX(r1->x1, r2->x1);
1265 x2 = MIN(r1->x2, r2->x2);
1266
1267 /*
1268 * If there's any overlap between the two rectangles, add that
1269 * overlap to the new region.
1270 * There's no need to check for subsumption because the only way
1271 * such a need could arise is if some region has two rectangles
1272 * right next to each other. Since that should never happen...
1273 */
1274 if (x1 < x2) {
1276
1277 OMEMCHECK(pReg, pNextRect, pReg->rects);
1278 pNextRect->x1 = x1;
1279 pNextRect->y1 = y1;
1280 pNextRect->x2 = x2;
1281 pNextRect->y2 = y2;
1282 pReg->numRects += 1;
1283 pNextRect++;
1284 // g_assert (pReg->numRects <= pReg->size);
1285 }
1286
1287 /*
1288 * Need to advance the pointers. Shift the one that extends
1289 * to the right the least, since the other still has a chance to
1290 * overlap with that region's next rectangle, if you see what I mean.
1291 */
1292 if (r1->x2 < r2->x2) {
1293 r1++;
1294 } else if (r2->x2 < r1->x2) {
1295 r2++;
1296 } else {
1297 r1++;
1298 r2++;
1299 }
1300 }
1301}
1302
1312void gdk_region_intersect(OGdkRegion *source1, const OGdkRegion *source2) {
1315
1316 /* check for trivial reject */
1317 if ((!(source1->numRects)) || (!(source2->numRects)) ||
1318 (!EXTENTCHECK(&source1->extents, &source2->extents)))
1319 source1->numRects = 0;
1320 else
1321 miRegionOp(source1, source1, source2, miIntersectO, (nonOverlapFunc)NULL,
1322 (nonOverlapFunc)NULL);
1323
1324 /*
1325 * Can't alter source1's extents before miRegionOp depends on the
1326 * extents of the regions being unchanged. Besides, this way there's
1327 * no checking against rectangles that will be nuked due to
1328 * coalescing, so we have to examine fewer rectangles.
1329 */
1330 miSetExtents(source1);
1331}
1332
1333static void miRegionCopy(OGdkRegion *dstrgn, const OGdkRegion *rgn) {
1334 if (dstrgn != rgn) /* don't want to copy to itself */
1335 {
1336 if (dstrgn->size < rgn->numRects) {
1337 if (dstrgn->rects != &dstrgn->extents) free(dstrgn->rects);
1338
1339 dstrgn->rects =
1340 (OGdkRegionBox *)malloc(sizeof(OGdkRegionBox) * rgn->numRects);
1341 dstrgn->size = rgn->numRects;
1342 }
1343
1344 dstrgn->numRects = rgn->numRects;
1345 dstrgn->extents = rgn->extents;
1346
1347 memcpy(dstrgn->rects, rgn->rects, rgn->numRects * sizeof(OGdkRegionBox));
1348 }
1349}
1350
1351/*======================================================================
1352 * Generic Region Operator
1353 *====================================================================*/
1354
1355/*-
1356 * -----------------------------------------------------------------------
1357 * miCoalesce --
1358 * Attempt to merge the boxes in the current band with those in the
1359 * previous one. Used only by miRegionOp.
1360 *
1361 * Results:
1362 * The new index for the previous band.
1363 *
1364 * Side Effects:
1365 * If coalescing takes place:
1366 * - rectangles in the previous band will have their y2 fields
1367 * altered.
1368 * - pReg->numRects will be decreased.
1369 *
1370 *-----------------------------------------------------------------------
1371 */
1372/* static int*/
1373static int miCoalesce(OGdkRegion *pReg, /* Region to coalesce */
1374 int prevStart, /* Index of start of previous band */
1375 int curStart) /* Index of start of current band */
1376{
1377 OGdkRegionBox *pPrevBox; /* Current box in previous band */
1378 OGdkRegionBox *pCurBox; /* Current box in current band */
1379 OGdkRegionBox *pRegEnd; /* End of region */
1380 int curNumRects; /* Number of rectangles in current
1381 * band */
1382 int prevNumRects; /* Number of rectangles in previous
1383 * band */
1384 int bandY1; /* Y1 coordinate for current band */
1385
1386 pRegEnd = &pReg->rects[pReg->numRects];
1387
1388 pPrevBox = &pReg->rects[prevStart];
1389 prevNumRects = curStart - prevStart;
1390
1391 /*
1392 * Figure out how many rectangles are in the current band. Have to do
1393 * this because multiple bands could have been added in miRegionOp
1394 * at the end when one region has been exhausted.
1395 */
1396 pCurBox = &pReg->rects[curStart];
1397 bandY1 = pCurBox->y1;
1398 for (curNumRects = 0; (pCurBox != pRegEnd) && (pCurBox->y1 == bandY1);
1399 curNumRects++) {
1400 pCurBox++;
1401 }
1402
1403 if (pCurBox != pRegEnd) {
1404 /*
1405 * If more than one band was added, we have to find the start
1406 * of the last band added so the next coalescing job can start
1407 * at the right place... (given when multiple bands are added,
1408 * this may be pointless -- see above).
1409 */
1410 pRegEnd--;
1411 while (pRegEnd[-1].y1 == pRegEnd->y1) {
1412 pRegEnd--;
1413 }
1414 curStart = pRegEnd - pReg->rects;
1415 pRegEnd = pReg->rects + pReg->numRects;
1416 }
1417
1418 if ((curNumRects == prevNumRects) && (curNumRects != 0)) {
1419 pCurBox -= curNumRects;
1420 /*
1421 * The bands may only be coalesced if the bottom of the previous
1422 * matches the top scanline of the current.
1423 */
1424 if (pPrevBox->y2 == pCurBox->y1) {
1425 /*
1426 * Make sure the bands have boxes in the same places. This
1427 * assumes that boxes have been added in such a way that they
1428 * cover the most area possible. I.e. two boxes in a band must
1429 * have some horizontal space between them.
1430 */
1431 do {
1432 if ((pPrevBox->x1 != pCurBox->x1) || (pPrevBox->x2 != pCurBox->x2)) {
1433 /*
1434 * The bands don't line up so they can't be coalesced.
1435 */
1436 return (curStart);
1437 }
1438 pPrevBox++;
1439 pCurBox++;
1440 prevNumRects -= 1;
1441 } while (prevNumRects != 0);
1442
1443 pReg->numRects -= curNumRects;
1444 pCurBox -= curNumRects;
1445 pPrevBox -= curNumRects;
1446
1447 /*
1448 * The bands may be merged, so set the bottom y of each box
1449 * in the previous band to that of the corresponding box in
1450 * the current band.
1451 */
1452 do {
1453 pPrevBox->y2 = pCurBox->y2;
1454 pPrevBox++;
1455 pCurBox++;
1456 curNumRects -= 1;
1457 } while (curNumRects != 0);
1458
1459 /*
1460 * If only one band was added to the region, we have to backup
1461 * curStart to the start of the previous band.
1462 *
1463 * If more than one band was added to the region, copy the
1464 * other bands down. The assumption here is that the other bands
1465 * came from the same region as the current one and no further
1466 * coalescing can be done on them since it's all been done
1467 * already... curStart is already in the right place.
1468 */
1469 if (pCurBox == pRegEnd) {
1470 curStart = prevStart;
1471 } else {
1472 do {
1473 *pPrevBox++ = *pCurBox++;
1474 } while (pCurBox != pRegEnd);
1475 }
1476 }
1477 }
1478 return curStart;
1479}
1480
1481/*-
1482 * -----------------------------------------------------------------------
1483 * miRegionOp --
1484 * Apply an operation to two regions. Called by miUnion, miInverse,
1485 * miSubtract, miIntersect...
1486 *
1487 * Results:
1488 * None.
1489 *
1490 * Side Effects:
1491 * The new region is overwritten.
1492 *
1493 * Notes:
1494 * The idea behind this function is to view the two regions as sets.
1495 * Together they cover a rectangle of area that this function divides
1496 * into horizontal bands where points are covered only by one region
1497 * or by both. For the first case, the nonOverlapFunc is called with
1498 * each the band and the band's upper and lower extents. For the
1499 * second, the overlapFunc is called to process the entire band. It
1500 * is responsible for clipping the rectangles in the band, though
1501 * this function provides the boundaries.
1502 * At the end of each band, the new region is coalesced, if possible,
1503 * to reduce the number of rectangles in the region.
1504 *
1505 *-----------------------------------------------------------------------
1506 */
1507/* static void*/
1508static void miRegionOp(
1509 OGdkRegion *newReg, OGdkRegion *reg1, const OGdkRegion *reg2,
1510 overlapFunc overlapFn, /* Function to call for over-
1511 * lapping bands */
1512 nonOverlapFunc nonOverlap1Fn, /* Function to call for non-
1513 * overlapping bands in region
1514 * 1 */
1515 nonOverlapFunc nonOverlap2Fn) /* Function to call for non-
1516 * overlapping bands in region
1517 * 2 */
1518{
1519 OGdkRegionBox *r1; /* Pointer into first region */
1520 OGdkRegionBox *r2; /* Pointer into 2d region */
1521 OGdkRegionBox *r1End; /* End of 1st region */
1522 OGdkRegionBox *r2End; /* End of 2d region */
1523 int ybot; /* Bottom of intersection */
1524 int ytop; /* Top of intersection */
1525 OGdkRegionBox *oldRects; /* Old rects for newReg */
1526 int prevBand; /* Index of start of
1527 * previous band in newReg */
1528 int curBand; /* Index of start of current
1529 * band in newReg */
1530 OGdkRegionBox *r1BandEnd; /* End of current band in r1 */
1531 OGdkRegionBox *r2BandEnd; /* End of current band in r2 */
1532 int top; /* Top of non-overlapping
1533 * band */
1534 int bot; /* Bottom of non-overlapping
1535 * band */
1536
1537 /*
1538 * Initialization:
1539 * set r1, r2, r1End and r2End appropriately, preserve the important
1540 * parts of the destination region until the end in case it's one of
1541 * the two source regions, then mark the "new" region empty, allocating
1542 * another array of rectangles for it to use.
1543 */
1544 r1 = reg1->rects;
1545 r2 = reg2->rects;
1546 r1End = r1 + reg1->numRects;
1547 r2End = r2 + reg2->numRects;
1548
1549 oldRects = newReg->rects;
1550
1551 EMPTY_REGION(newReg);
1552
1553 /*
1554 * Allocate a reasonable number of rectangles for the new region. The idea
1555 * is to allocate enough so the individual functions don't need to
1556 * reallocate and copy the array, which is time consuming, yet we don't
1557 * have to worry about using too much memory. I hope to be able to
1558 * nuke the Xrealloc() at the end of this function eventually.
1559 */
1560 newReg->size = MAX(reg1->numRects, reg2->numRects) * 2;
1561 newReg->rects = (OGdkRegionBox *)malloc(sizeof(OGdkRegionBox) * newReg->size);
1562
1563 /*
1564 * Initialize ybot and ytop.
1565 * In the upcoming loop, ybot and ytop serve different functions depending
1566 * on whether the band being handled is an overlapping or non-overlapping
1567 * band.
1568 * In the case of a non-overlapping band (only one of the regions
1569 * has points in the band), ybot is the bottom of the most recent
1570 * intersection and thus clips the top of the rectangles in that band.
1571 * ytop is the top of the next intersection between the two regions and
1572 * serves to clip the bottom of the rectangles in the current band.
1573 * For an overlapping band (where the two regions intersect), ytop clips
1574 * the top of the rectangles of both regions and ybot clips the bottoms.
1575 */
1576 if (reg1->extents.y1 < reg2->extents.y1)
1577 ybot = reg1->extents.y1;
1578 else
1579 ybot = reg2->extents.y1;
1580
1581 /*
1582 * prevBand serves to mark the start of the previous band so rectangles
1583 * can be coalesced into larger rectangles. qv. miCoalesce, above.
1584 * In the beginning, there is no previous band, so prevBand == curBand
1585 * (curBand is set later on, of course, but the first band will always
1586 * start at index 0). prevBand and curBand must be indices because of
1587 * the possible expansion, and resultant moving, of the new region's
1588 * array of rectangles.
1589 */
1590 prevBand = 0;
1591
1592 do {
1593 curBand = newReg->numRects;
1594
1595 /*
1596 * This algorithm proceeds one source-band (as opposed to a
1597 * destination band, which is determined by where the two regions
1598 * intersect) at a time. r1BandEnd and r2BandEnd serve to mark the
1599 * rectangle after the last one in the current band for their
1600 * respective regions.
1601 */
1602 r1BandEnd = r1;
1603 while ((r1BandEnd != r1End) && (r1BandEnd->y1 == r1->y1)) {
1604 r1BandEnd++;
1605 }
1606
1607 r2BandEnd = r2;
1608 while ((r2BandEnd != r2End) && (r2BandEnd->y1 == r2->y1)) {
1609 r2BandEnd++;
1610 }
1611
1612 /*
1613 * First handle the band that doesn't intersect, if any.
1614 *
1615 * Note that attention is restricted to one band in the
1616 * non-intersecting region at once, so if a region has n
1617 * bands between the current position and the next place it overlaps
1618 * the other, this entire loop will be passed through n times.
1619 */
1620 if (r1->y1 < r2->y1) {
1621 top = MAX(r1->y1, ybot);
1622 bot = MIN(r1->y2, r2->y1);
1623
1624 if ((top != bot) &&
1625 (nonOverlap1Fn != (void (*)(OGdkRegion *, OGdkRegionBox *,
1626 OGdkRegionBox *, int, int))NULL)) {
1627 (*nonOverlap1Fn)(newReg, r1, r1BandEnd, top, bot);
1628 }
1629
1630 ytop = r2->y1;
1631 } else if (r2->y1 < r1->y1) {
1632 top = MAX(r2->y1, ybot);
1633 bot = MIN(r2->y2, r1->y1);
1634
1635 if ((top != bot) &&
1636 (nonOverlap2Fn != (void (*)(OGdkRegion *, OGdkRegionBox *,
1637 OGdkRegionBox *, int, int))NULL)) {
1638 (*nonOverlap2Fn)(newReg, r2, r2BandEnd, top, bot);
1639 }
1640
1641 ytop = r1->y1;
1642 } else {
1643 ytop = r1->y1;
1644 }
1645
1646 /*
1647 * If any rectangles got added to the region, try and coalesce them
1648 * with rectangles from the previous band. Note we could just do
1649 * this test in miCoalesce, but some machines incur a not
1650 * inconsiderable cost for function calls, so...
1651 */
1652 if (newReg->numRects != curBand) {
1653 prevBand = miCoalesce(newReg, prevBand, curBand);
1654 }
1655
1656 /*
1657 * Now see if we've hit an intersecting band. The two bands only
1658 * intersect if ybot > ytop
1659 */
1660 ybot = MIN(r1->y2, r2->y2);
1661 curBand = newReg->numRects;
1662 if (ybot > ytop) {
1663 (*overlapFn)(newReg, r1, r1BandEnd, r2, r2BandEnd, ytop, ybot);
1664 }
1665
1666 if (newReg->numRects != curBand) {
1667 prevBand = miCoalesce(newReg, prevBand, curBand);
1668 }
1669
1670 /*
1671 * If we've finished with a band (y2 == ybot) we skip forward
1672 * in the region to the next band.
1673 */
1674 if (r1->y2 == ybot) {
1675 r1 = r1BandEnd;
1676 }
1677 if (r2->y2 == ybot) {
1678 r2 = r2BandEnd;
1679 }
1680 } while ((r1 != r1End) && (r2 != r2End));
1681
1682 /*
1683 * Deal with whichever region still has rectangles left.
1684 */
1685 curBand = newReg->numRects;
1686 if (r1 != r1End) {
1687 if (nonOverlap1Fn != (nonOverlapFunc)NULL) {
1688 do {
1689 r1BandEnd = r1;
1690 while ((r1BandEnd < r1End) && (r1BandEnd->y1 == r1->y1)) {
1691 r1BandEnd++;
1692 }
1693 (*nonOverlap1Fn)(newReg, r1, r1BandEnd, MAX(r1->y1, ybot), r1->y2);
1694 r1 = r1BandEnd;
1695 } while (r1 != r1End);
1696 }
1697 } else if ((r2 != r2End) && (nonOverlap2Fn != (nonOverlapFunc)NULL)) {
1698 do {
1699 r2BandEnd = r2;
1700 while ((r2BandEnd < r2End) && (r2BandEnd->y1 == r2->y1)) {
1701 r2BandEnd++;
1702 }
1703 (*nonOverlap2Fn)(newReg, r2, r2BandEnd, MAX(r2->y1, ybot), r2->y2);
1704 r2 = r2BandEnd;
1705 } while (r2 != r2End);
1706 }
1707
1708 if (newReg->numRects != curBand) {
1709 (void)miCoalesce(newReg, prevBand, curBand);
1710 }
1711
1712 /*
1713 * A bit of cleanup. To keep regions from growing without bound,
1714 * we shrink the array of rectangles to match the new number of
1715 * rectangles in the region. This never goes to 0, however...
1716 *
1717 * Only do this stuff if the number of rectangles allocated is more than
1718 * twice the number of rectangles in the region (a simple optimization...).
1719 */
1720 if (newReg->numRects < (newReg->size >> 1)) {
1721 if (REGION_NOT_EMPTY(newReg)) {
1722 newReg->size = newReg->numRects;
1723 // newReg->rects = g_renew (GdkRegionBox,
1724 // newReg->rects, newReg->size);
1725 newReg->rects = (OGdkRegionBox *)realloc(
1726 newReg->rects, sizeof(OGdkRegionBox) * newReg->size);
1727 } else {
1728 /*
1729 * No point in doing the extra work involved in an Xrealloc if
1730 * the region is empty
1731 */
1732 newReg->size = 1;
1733 free(newReg->rects);
1734 newReg->rects = &newReg->extents;
1735 }
1736 }
1737
1738 if (oldRects != &newReg->extents) free(oldRects);
1739}
1740
1741/*======================================================================
1742 * Region Union
1743 *====================================================================*/
1744
1745/*-
1746 * -----------------------------------------------------------------------
1747 * miUnionNonO --
1748 * Handle a non-overlapping band for the union operation. Just
1749 * Adds the rectangles into the region. Doesn't have to check for
1750 * subsumption or anything.
1751 *
1752 * Results:
1753 * None.
1754 *
1755 * Side Effects:
1756 * pReg->numRects is incremented and the final rectangles overwritten
1757 * with the rectangles we're passed.
1758 *
1759 *-----------------------------------------------------------------------
1760 */
1761static void miUnionNonO(OGdkRegion *pReg, OGdkRegionBox *r, OGdkRegionBox *rEnd,
1762 int y1, int y2) {
1763 OGdkRegionBox *pNextRect;
1764
1765 pNextRect = &pReg->rects[pReg->numRects];
1766
1768
1769 while (r != rEnd) {
1771 OMEMCHECK(pReg, pNextRect, pReg->rects);
1772 pNextRect->x1 = r->x1;
1773 pNextRect->y1 = y1;
1774 pNextRect->x2 = r->x2;
1775 pNextRect->y2 = y2;
1776 pReg->numRects += 1;
1777 pNextRect++;
1778
1780 r++;
1781 }
1782}
1783
1784/*-
1785 * -----------------------------------------------------------------------
1786 * miUnionO --
1787 * Handle an overlapping band for the union operation. Picks the
1788 * left-most rectangle each time and merges it into the region.
1789 *
1790 * Results:
1791 * None.
1792 *
1793 * Side Effects:
1794 * Rectangles are overwritten in pReg->rects and pReg->numRects will
1795 * be changed.
1796 *
1797 *-----------------------------------------------------------------------
1798 */
1799
1800/* static void*/
1801static void miUnionO(OGdkRegion *pReg, OGdkRegionBox *r1, OGdkRegionBox *r1End,
1802 OGdkRegionBox *r2, OGdkRegionBox *r2End, int y1, int y2) {
1803 OGdkRegionBox *pNextRect;
1804
1805 pNextRect = &pReg->rects[pReg->numRects];
1806
1807#define MERGERECT(r) \
1808 if ((pReg->numRects != 0) && (pNextRect[-1].y1 == y1) && \
1809 (pNextRect[-1].y2 == y2) && (pNextRect[-1].x2 >= r->x1)) { \
1810 if (pNextRect[-1].x2 < r->x2) { \
1811 pNextRect[-1].x2 = r->x2; \
1812 /*g_assert(pNextRect[-1].x1<pNextRect[-1].x2);*/ \
1813 } \
1814 } else { \
1815 OMEMCHECK(pReg, pNextRect, pReg->rects); \
1816 pNextRect->y1 = y1; \
1817 pNextRect->y2 = y2; \
1818 pNextRect->x1 = r->x1; \
1819 pNextRect->x2 = r->x2; \
1820 pReg->numRects += 1; \
1821 pNextRect += 1; \
1822 } \
1823 /*g_assert(pReg->numRects<=pReg->size);*/ \
1824 r++;
1825
1827 while ((r1 != r1End) && (r2 != r2End)) {
1828 if (r1->x1 < r2->x1) {
1829 MERGERECT(r1);
1830 } else {
1831 MERGERECT(r2);
1832 }
1833 }
1834
1835 if (r1 != r1End) {
1836 do {
1837 MERGERECT(r1);
1838 } while (r1 != r1End);
1839 } else
1840 while (r2 != r2End) {
1841 MERGERECT(r2);
1842 }
1843}
1844
1854void gdk_region_union(OGdkRegion *source1, const OGdkRegion *source2) {
1857
1858 /* checks all the simple cases */
1859
1860 /*
1861 * source1 and source2 are the same or source2 is empty
1862 */
1863 if ((source1 == source2) || (!(source2->numRects))) return;
1864
1865 /*
1866 * source1 is empty
1867 */
1868 if (!(source1->numRects)) {
1869 miRegionCopy(source1, source2);
1870 return;
1871 }
1872
1873 /*
1874 * source1 completely subsumes source2
1875 */
1876 if ((source1->numRects == 1) &&
1877 (source1->extents.x1 <= source2->extents.x1) &&
1878 (source1->extents.y1 <= source2->extents.y1) &&
1879 (source1->extents.x2 >= source2->extents.x2) &&
1880 (source1->extents.y2 >= source2->extents.y2))
1881 return;
1882
1883 /*
1884 * source2 completely subsumes source1
1885 */
1886 if ((source2->numRects == 1) &&
1887 (source2->extents.x1 <= source1->extents.x1) &&
1888 (source2->extents.y1 <= source1->extents.y1) &&
1889 (source2->extents.x2 >= source1->extents.x2) &&
1890 (source2->extents.y2 >= source1->extents.y2)) {
1891 miRegionCopy(source1, source2);
1892 return;
1893 }
1894
1895 miRegionOp(source1, source1, source2, miUnionO, miUnionNonO, miUnionNonO);
1896
1897 source1->extents.x1 = MIN(source1->extents.x1, source2->extents.x1);
1898 source1->extents.y1 = MIN(source1->extents.y1, source2->extents.y1);
1899 source1->extents.x2 = MAX(source1->extents.x2, source2->extents.x2);
1900 source1->extents.y2 = MAX(source1->extents.y2, source2->extents.y2);
1901}
1902
1903/*======================================================================
1904 * Region Subtraction
1905 *====================================================================*/
1906
1907/*-
1908 * -----------------------------------------------------------------------
1909 * miSubtractNonO --
1910 * Deal with non-overlapping band for subtraction. Any parts from
1911 * region 2 we discard. Anything from region 1 we add to the region.
1912 *
1913 * Results:
1914 * None.
1915 *
1916 * Side Effects:
1917 * pReg may be affected.
1918 *
1919 *-----------------------------------------------------------------------
1920 */
1921/* static void*/
1922static void miSubtractNonO1(OGdkRegion *pReg, OGdkRegionBox *r,
1923 OGdkRegionBox *rEnd, int y1, int y2) {
1924 OGdkRegionBox *pNextRect;
1925
1926 pNextRect = &pReg->rects[pReg->numRects];
1927
1929
1930 while (r != rEnd) {
1932 OMEMCHECK(pReg, pNextRect, pReg->rects);
1933 pNextRect->x1 = r->x1;
1934 pNextRect->y1 = y1;
1935 pNextRect->x2 = r->x2;
1936 pNextRect->y2 = y2;
1937 pReg->numRects += 1;
1938 pNextRect++;
1939
1941
1942 r++;
1943 }
1944}
1945
1946/*-
1947 * -----------------------------------------------------------------------
1948 * miSubtractO --
1949 * Overlapping band subtraction. x1 is the left-most point not yet
1950 * checked.
1951 *
1952 * Results:
1953 * None.
1954 *
1955 * Side Effects:
1956 * pReg may have rectangles added to it.
1957 *
1958 *-----------------------------------------------------------------------
1959 */
1960/* static void*/
1961static void miSubtractO(OGdkRegion *pReg, OGdkRegionBox *r1,
1962 OGdkRegionBox *r1End, OGdkRegionBox *r2,
1963 OGdkRegionBox *r2End, int y1, int y2) {
1964 OGdkRegionBox *pNextRect;
1965 int x1;
1966
1967 x1 = r1->x1;
1968
1970 pNextRect = &pReg->rects[pReg->numRects];
1971
1972 while ((r1 != r1End) && (r2 != r2End)) {
1973 if (r2->x2 <= x1) {
1974 /*
1975 * Subtrahend missed the boat: go to next subtrahend.
1976 */
1977 r2++;
1978 } else if (r2->x1 <= x1) {
1979 /*
1980 * Subtrahend preceeds minuend: nuke left edge of minuend.
1981 */
1982 x1 = r2->x2;
1983 if (x1 >= r1->x2) {
1984 /*
1985 * Minuend completely covered: advance to next minuend and
1986 * reset left fence to edge of new minuend.
1987 */
1988 r1++;
1989 if (r1 != r1End) x1 = r1->x1;
1990 } else {
1991 /*
1992 * Subtrahend now used up since it doesn't extend beyond
1993 * minuend
1994 */
1995 r2++;
1996 }
1997 } else if (r2->x1 < r1->x2) {
1998 /*
1999 * Left part of subtrahend covers part of minuend: add uncovered
2000 * part of minuend to region and skip to next subtrahend.
2001 */
2003 OMEMCHECK(pReg, pNextRect, pReg->rects);
2004 pNextRect->x1 = x1;
2005 pNextRect->y1 = y1;
2006 pNextRect->x2 = r2->x1;
2007 pNextRect->y2 = y2;
2008 pReg->numRects += 1;
2009 pNextRect++;
2010
2012
2013 x1 = r2->x2;
2014 if (x1 >= r1->x2) {
2015 /*
2016 * Minuend used up: advance to new...
2017 */
2018 r1++;
2019 if (r1 != r1End) x1 = r1->x1;
2020 } else {
2021 /*
2022 * Subtrahend used up
2023 */
2024 r2++;
2025 }
2026 } else {
2027 /*
2028 * Minuend used up: add any remaining piece before advancing.
2029 */
2030 if (r1->x2 > x1) {
2031 OMEMCHECK(pReg, pNextRect, pReg->rects);
2032 pNextRect->x1 = x1;
2033 pNextRect->y1 = y1;
2034 pNextRect->x2 = r1->x2;
2035 pNextRect->y2 = y2;
2036 pReg->numRects += 1;
2037 pNextRect++;
2039 }
2040 r1++;
2041 if (r1 != r1End) x1 = r1->x1;
2042 }
2043 }
2044
2045 /*
2046 * Add remaining minuend rectangles to region.
2047 */
2048 while (r1 != r1End) {
2050 OMEMCHECK(pReg, pNextRect, pReg->rects);
2051 pNextRect->x1 = x1;
2052 pNextRect->y1 = y1;
2053 pNextRect->x2 = r1->x2;
2054 pNextRect->y2 = y2;
2055 pReg->numRects += 1;
2056 pNextRect++;
2057
2059
2060 r1++;
2061 if (r1 != r1End) {
2062 x1 = r1->x1;
2063 }
2064 }
2065}
2066
2075void gdk_region_subtract(OGdkRegion *source1, const OGdkRegion *source2) {
2076 // g_return_if_fail (source1 != NULL);
2077 // g_return_if_fail (source2 != NULL);
2078
2079 /* check for trivial reject */
2080 if ((!(source1->numRects)) || (!(source2->numRects)) ||
2081 (!EXTENTCHECK(&source1->extents, &source2->extents)))
2082 return;
2083
2084 miRegionOp(source1, source1, source2, miSubtractO, miSubtractNonO1,
2085 (nonOverlapFunc)NULL);
2086
2087 /*
2088 * Can't alter source1's extents before we call miRegionOp because miRegionOp
2089 * depends on the extents of those regions being the unaltered. Besides, this
2090 * way there's no checking against rectangles that will be nuked
2091 * due to coalescing, so we have to examine fewer rectangles.
2092 */
2093 miSetExtents(source1);
2094}
2095
2105void gdk_region_xor(OGdkRegion *source1, const OGdkRegion *source2) {
2106 OGdkRegion *trb;
2107
2108 // g_return_if_fail (source1 != NULL);
2109 // g_return_if_fail (source2 != NULL);
2110
2111 trb = gdk_region_copy(source2);
2112
2113 gdk_region_subtract(trb, source1);
2114 gdk_region_subtract(source1, source2);
2115
2116 gdk_region_union(source1, trb);
2117
2118 gdk_region_destroy(trb);
2119}
2120
2129bool gdk_region_empty(const OGdkRegion *region) {
2130 // g_return_val_if_fail (region != NULL, FALSE);
2131
2132 if (region->numRects == 0)
2133 return TRUE;
2134 else
2135 return FALSE;
2136}
2137
2147bool ogdk_region_equal(const OGdkRegion *region1, const OGdkRegion *region2) {
2148 int i;
2149
2150 // g_return_val_if_fail (region1 != NULL, FALSE);
2151 // g_return_val_if_fail (region2 != NULL, FALSE);
2152
2153 if (region1->numRects != region2->numRects) return FALSE;
2154 if (region1->numRects == 0) return TRUE;
2155 if (region1->extents.x1 != region2->extents.x1) return FALSE;
2156 if (region1->extents.x2 != region2->extents.x2) return FALSE;
2157 if (region1->extents.y1 != region2->extents.y1) return FALSE;
2158 if (region1->extents.y2 != region2->extents.y2) return FALSE;
2159 for (i = 0; i < region1->numRects; i++) {
2160 if (region1->rects[i].x1 != region2->rects[i].x1) return FALSE;
2161 if (region1->rects[i].x2 != region2->rects[i].x2) return FALSE;
2162 if (region1->rects[i].y1 != region2->rects[i].y1) return FALSE;
2163 if (region1->rects[i].y2 != region2->rects[i].y2) return FALSE;
2164 }
2165 return TRUE;
2166}
2167
2178bool gdk_region_point_in(const OGdkRegion *region, int x, int y) {
2179 int i;
2180
2181 // g_return_val_if_fail (region != NULL, FALSE);
2182
2183 if (region->numRects == 0) return FALSE;
2184 if (!INBOX(region->extents, x, y)) return FALSE;
2185 for (i = 0; i < region->numRects; i++) {
2186 if (INBOX(region->rects[i], x, y)) return TRUE;
2187 }
2188 return FALSE;
2189}
2190
2202OGdkOverlapType gdk_region_rect_in(const OGdkRegion *region,
2203 const OGdkRectangle *rectangle) {
2204 OGdkRegionBox *pbox;
2205 OGdkRegionBox *pboxEnd;
2206 OGdkRegionBox rect;
2207 OGdkRegionBox *prect = &rect;
2208 bool partIn, partOut;
2209 int rx, ry;
2210
2211 // g_return_val_if_fail (region != NULL,
2212 // GDK_OVERLAP_RECTANGLE_OUT); g_return_val_if_fail
2213 // (rectangle != NULL, GDK_OVERLAP_RECTANGLE_OUT);
2214
2215 rx = rectangle->x;
2216 ry = rectangle->y;
2217
2218 prect->x1 = rx;
2219 prect->y1 = ry;
2220 prect->x2 = rx + rectangle->width;
2221 prect->y2 = ry + rectangle->height;
2222
2223 /* this is (just) a useful optimization */
2224 if ((region->numRects == 0) || !EXTENTCHECK(&region->extents, prect))
2225 return OGDK_OVERLAP_RECTANGLE_OUT;
2226
2227 partOut = FALSE;
2228 partIn = FALSE;
2229
2230 /* can stop when both partOut and partIn are TRUE, or we reach prect->y2 */
2231 for (pbox = region->rects, pboxEnd = pbox + region->numRects; pbox < pboxEnd;
2232 pbox++) {
2233 if (pbox->y2 <= ry)
2234 continue; /* getting up to speed or skipping remainder of band */
2235
2236 if (pbox->y1 > ry) {
2237 partOut = TRUE; /* missed part of rectangle above */
2238 if (partIn || (pbox->y1 >= prect->y2)) break;
2239 ry = pbox->y1; /* x guaranteed to be == prect->x1 */
2240 }
2241
2242 if (pbox->x2 <= rx) continue; /* not far enough over yet */
2243
2244 if (pbox->x1 > rx) {
2245 partOut = TRUE; /* missed part of rectangle to left */
2246 if (partIn) break;
2247 }
2248
2249 if (pbox->x1 < prect->x2) {
2250 partIn = TRUE; /* definitely overlap */
2251 if (partOut) break;
2252 }
2253
2254 if (pbox->x2 >= prect->x2) {
2255 ry = pbox->y2; /* finished with this band */
2256 if (ry >= prect->y2) break;
2257 rx = prect->x1; /* reset x out to left again */
2258 } else {
2259 /*
2260 * Because boxes in a band are maximal width, if the first box
2261 * to overlap the rectangle doesn't completely cover it in that
2262 * band, the rectangle must be partially out, since some of it
2263 * will be uncovered in that band. partIn will have been set true
2264 * by now...
2265 */
2266 break;
2267 }
2268 }
2269
2270 return (partIn ? ((ry < prect->y2) ? OGDK_OVERLAP_RECTANGLE_PART
2271 : OGDK_OVERLAP_RECTANGLE_IN)
2272 : OGDK_OVERLAP_RECTANGLE_OUT);
2273}
2274
2275#if 0
2276 static void
2277 gdk_region_unsorted_spans_intersect_foreach (GdkRegion *region,
2278 const GdkSpan *spans,
2279 int n_spans,
2280 GdkSpanFunc function,
2281 gpointer data)
2282 {
2283 gint i, left, right, y;
2284 gint clipped_left, clipped_right;
2285 GdkRegionBox *pbox;
2286 GdkRegionBox *pboxEnd;
2287
2288 if (!region->numRects)
2289 return;
2290
2291 for (i=0;i<n_spans;i++)
2292 {
2293 y = spans[i].y;
2294 left = spans[i].x;
2295 right = left + spans[i].width; /* right is not in the span! */
2296
2297 if (! ((region->extents.y1 <= y) &&
2298 (region->extents.y2 > y) &&
2299 (region->extents.x1 < right) &&
2300 (region->extents.x2 > left)) )
2301 continue;
2302
2303 /* can stop when we passed y */
2304 for (pbox = region->rects, pboxEnd = pbox + region->numRects;
2305 pbox < pboxEnd;
2306 pbox++)
2307 {
2308 if (pbox->y2 <= y)
2309 continue; /* Not quite there yet */
2310
2311 if (pbox->y1 > y)
2312 break; /* passed the spanline */
2313
2314 if ((right > pbox->x1) && (left < pbox->x2))
2315 {
2316 GdkSpan out_span;
2317
2318 clipped_left = MAX (left, pbox->x1);
2319 clipped_right = MIN (right, pbox->x2);
2320
2321 out_span.y = y;
2322 out_span.x = clipped_left;
2323 out_span.width = clipped_right - clipped_left;
2324 (*function) (&out_span, data);
2325 }
2326 }
2327 }
2328 }
2329#endif
2330
2331#if 0
2343 void
2344 gdk_region_spans_intersect_foreach (GdkRegion *region,
2345 const GdkSpan *spans,
2346 int n_spans,
2347 gboolean sorted,
2348 GdkSpanFunc function,
2349 gpointer data)
2350 {
2351 gint left, right, y;
2352 gint clipped_left, clipped_right;
2353 GdkRegionBox *pbox;
2354 GdkRegionBox *pboxEnd;
2355 const GdkSpan *span, *tmpspan;
2356 const GdkSpan *end_span;
2357
2358 g_return_if_fail (region != NULL);
2359 g_return_if_fail (spans != NULL);
2360
2361 if (!sorted)
2362 {
2363 gdk_region_unsorted_spans_intersect_foreach (region,
2364 spans,
2365 n_spans,
2366 function,
2367 data);
2368 return;
2369 }
2370
2371 if ((!region->numRects) || (n_spans == 0))
2372 return;
2373
2374 /* The main method here is to step along the
2375 * sorted rectangles and spans in lock step, and
2376 * clipping the spans that are in the current
2377 * rectangle before going on to the next rectangle.
2378 */
2379
2380 span = spans;
2381 end_span = spans + n_spans;
2382 pbox = region->rects;
2383 pboxEnd = pbox + region->numRects;
2384 while (pbox < pboxEnd)
2385 {
2386 while ((pbox->y2 < span->y) || (span->y < pbox->y1))
2387 {
2388 /* Skip any rectangles that are above the current span */
2389 if (pbox->y2 < span->y)
2390 {
2391 pbox++;
2392 if (pbox == pboxEnd)
2393 return;
2394 }
2395 /* Skip any spans that are above the current rectangle */
2396 if (span->y < pbox->y1)
2397 {
2398 span++;
2399 if (span == end_span)
2400 return;
2401 }
2402 }
2403
2404 /* Ok, we got at least one span that might intersect this rectangle. */
2405 tmpspan = span;
2406 while ((tmpspan < end_span) &&
2407 (tmpspan->y < pbox->y2))
2408 {
2409 y = tmpspan->y;
2410 left = tmpspan->x;
2411 right = left + tmpspan->width; /* right is not in the span! */
2412
2413 if ((right > pbox->x1) && (left < pbox->x2))
2414 {
2415 GdkSpan out_span;
2416
2417 clipped_left = MAX (left, pbox->x1);
2418 clipped_right = MIN (right, pbox->x2);
2419
2420 out_span.y = y;
2421 out_span.x = clipped_left;
2422 out_span.width = clipped_right - clipped_left;
2423 (*function) (&out_span, data);
2424 }
2425
2426 tmpspan++;
2427 }
2428
2429 /* Finished this rectangle.
2430 * The spans could still intersect the next one
2431 */
2432 pbox++;
2433 }
2434 }
2435#endif
2436
2437/* $TOG: PolyReg.c /main/15 1998/02/06 17:47:08 kaleb $ */
2438/************************************************************************
2439 *
2440 * Copyright 1987, 1998 The Open Group
2441 *
2442 * All Rights Reserved.
2443 *
2444 * The above copyright notice and this permission notice shall be included in
2445 * all copies or substantial portions of the Software.
2446 *
2447 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
2448 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
2449 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
2450 * OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
2451 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
2452 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
2453 *
2454 * Except as contained in this notice, the name of The Open Group shall not be
2455 * used in advertising or otherwise to promote the sale, use or other dealings
2456 * in this Software without prior written authorization from The Open Group.
2457 *
2458 *
2459 * Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts.
2460 *
2461 * All Rights Reserved
2462 *
2463 * Permission to use, copy, modify, and distribute this software and its
2464 * documentation for any purpose and without fee is hereby granted,
2465 * provided that the above copyright notice appear in all copies and that
2466 * both that copyright notice and this permission notice appear in
2467 * supporting documentation, and that the name of Digital not be
2468 * used in advertising or publicity pertaining to distribution of the
2469 * software without specific, written prior permission.
2470 *
2471 * DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
2472 * ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
2473 * DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
2474 * ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
2475 * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
2476 * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
2477 * SOFTWARE.
2478 *
2479 ************************************************************************/
2480/* $XFree86: xc/lib/X11/PolyReg.c,v 1.4 1998/10/03 08:41:21 dawes Exp $ */
2481
2482#define LARGE_COORDINATE 1000000
2483#define SMALL_COORDINATE -LARGE_COORDINATE
2484
2485// #include "config.h"
2486// #include <gdkregion.h>
2487// #include "gdkregion-generic.h"
2488// #include "gdkpoly-generic.h"
2489// #include "gdkalias.h"
2490
2491/*
2492 * InsertEdgeInET
2493 *
2494 * Insert the given edge into the edge table.
2495 * First we must find the correct bucket in the
2496 * Edge table, then find the right slot in the
2497 * bucket. Finally, we can insert it.
2498 *
2499 */
2500static void InsertEdgeInET(OEdgeTable *ET, OEdgeTableEntry *ETE, int scanline,
2501 OScanLineListBlock **SLLBlock, int *iSLLBlock) {
2502 OEdgeTableEntry *start, *prev;
2503 OScanLineList *pSLL, *pPrevSLL;
2504 OScanLineListBlock *tmpSLLBlock;
2505
2506 /*
2507 * find the right bucket to put the edge into
2508 */
2509 pPrevSLL = &ET->scanlines;
2510 pSLL = pPrevSLL->next;
2511 while (pSLL && (pSLL->scanline < scanline)) {
2512 pPrevSLL = pSLL;
2513 pSLL = pSLL->next;
2514 }
2515
2516 /*
2517 * reassign pSLL (pointer to ScanLineList) if necessary
2518 */
2519 if ((!pSLL) || (pSLL->scanline > scanline)) {
2520 if (*iSLLBlock > SLLSPERBLOCK - 1) {
2521 tmpSLLBlock = (OScanLineListBlock *)malloc(sizeof(OScanLineListBlock));
2522 (*SLLBlock)->next = tmpSLLBlock;
2523 tmpSLLBlock->next = (OScanLineListBlock *)NULL;
2524 *SLLBlock = tmpSLLBlock;
2525 *iSLLBlock = 0;
2526 }
2527 pSLL = &((*SLLBlock)->SLLs[(*iSLLBlock)++]);
2528
2529 pSLL->next = pPrevSLL->next;
2530 pSLL->edgelist = (OEdgeTableEntry *)NULL;
2531 pPrevSLL->next = pSLL;
2532 }
2533 pSLL->scanline = scanline;
2534
2535 /*
2536 * now insert the edge in the right bucket
2537 */
2538 prev = (OEdgeTableEntry *)NULL;
2539 start = pSLL->edgelist;
2540 while (start && (start->bres.minor_axis < ETE->bres.minor_axis)) {
2541 prev = start;
2542 start = start->next;
2543 }
2544 ETE->next = start;
2545
2546 if (prev)
2547 prev->next = ETE;
2548 else
2549 pSLL->edgelist = ETE;
2550}
2551
2552/*
2553 * CreateEdgeTable
2554 *
2555 * This routine creates the edge table for
2556 * scan converting polygons.
2557 * The Edge Table (ET) looks like:
2558 *
2559 * EdgeTable
2560 * --------
2561 * | ymax | ScanLineLists
2562 * |scanline|-->------------>-------------->...
2563 * -------- |scanline| |scanline|
2564 * |edgelist| |edgelist|
2565 * --------- ---------
2566 * | |
2567 * | |
2568 * V V
2569 * list of ETEs list of ETEs
2570 *
2571 * where ETE is an EdgeTableEntry data structure,
2572 * and there is one ScanLineList per scanline at
2573 * which an edge is initially entered.
2574 *
2575 */
2576
2577static void CreateETandAET(int count, const OGdkPoint *pts, OEdgeTable *ET,
2578 OEdgeTableEntry *AET, OEdgeTableEntry *pETEs,
2579 OScanLineListBlock *pSLLBlock) {
2580 const OGdkPoint *top, *bottom;
2581 const OGdkPoint *PrevPt, *CurrPt;
2582 int iSLLBlock = 0;
2583 int dy;
2584
2585 if (count < 2) return;
2586
2587 /*
2588 * initialize the Active Edge Table
2589 */
2590 AET->next = (OEdgeTableEntry *)NULL;
2591 AET->back = (OEdgeTableEntry *)NULL;
2592 AET->nextWETE = (OEdgeTableEntry *)NULL;
2593 AET->bres.minor_axis = SMALL_COORDINATE;
2594
2595 /*
2596 * initialize the Edge Table.
2597 */
2598 ET->scanlines.next = (OScanLineList *)NULL;
2599 ET->ymax = SMALL_COORDINATE;
2600 ET->ymin = LARGE_COORDINATE;
2601 pSLLBlock->next = (OScanLineListBlock *)NULL;
2602
2603 PrevPt = &pts[count - 1];
2604
2605 /*
2606 * for each vertex in the array of points.
2607 * In this loop we are dealing with two vertices at
2608 * a time -- these make up one edge of the polygon.
2609 */
2610 while (count--) {
2611 CurrPt = pts++;
2612
2613 /*
2614 * find out which point is above and which is below.
2615 */
2616 if (PrevPt->y > CurrPt->y) {
2617 bottom = PrevPt, top = CurrPt;
2618 pETEs->ClockWise = 0;
2619 } else {
2620 bottom = CurrPt, top = PrevPt;
2621 pETEs->ClockWise = 1;
2622 }
2623
2624 /*
2625 * don't add horizontal edges to the Edge table.
2626 */
2627 if (bottom->y != top->y) {
2628 pETEs->ymax = bottom->y - 1; /* -1 so we don't get last scanline */
2629
2630 /*
2631 * initialize integer edge algorithm
2632 */
2633 dy = bottom->y - top->y;
2634 OBRESINITPGONSTRUCT(dy, top->x, bottom->x, pETEs->bres);
2635
2636 InsertEdgeInET(ET, pETEs, top->y, &pSLLBlock, &iSLLBlock);
2637
2638 if (PrevPt->y > ET->ymax) ET->ymax = PrevPt->y;
2639 if (PrevPt->y < ET->ymin) ET->ymin = PrevPt->y;
2640 pETEs++;
2641 }
2642
2643 PrevPt = CurrPt;
2644 }
2645}
2646
2647/*
2648 * loadAET
2649 *
2650 * This routine moves EdgeTableEntries from the
2651 * EdgeTable into the Active Edge Table,
2652 * leaving them sorted by smaller x coordinate.
2653 *
2654 */
2655
2656static void loadAET(OEdgeTableEntry *AET, OEdgeTableEntry *ETEs) {
2657 OEdgeTableEntry *pPrevAET;
2658 OEdgeTableEntry *tmp;
2659
2660 pPrevAET = AET;
2661 AET = AET->next;
2662 while (ETEs) {
2663 while (AET && (AET->bres.minor_axis < ETEs->bres.minor_axis)) {
2664 pPrevAET = AET;
2665 AET = AET->next;
2666 }
2667 tmp = ETEs->next;
2668 ETEs->next = AET;
2669 if (AET) AET->back = ETEs;
2670 ETEs->back = pPrevAET;
2671 pPrevAET->next = ETEs;
2672 pPrevAET = ETEs;
2673
2674 ETEs = tmp;
2675 }
2676}
2677
2678/*
2679 * computeWAET
2680 *
2681 * This routine links the AET by the
2682 * nextWETE (winding EdgeTableEntry) link for
2683 * use by the winding number rule. The final
2684 * Active Edge Table (AET) might look something
2685 * like:
2686 *
2687 * AET
2688 * ---------- --------- ---------
2689 * |ymax | |ymax | |ymax |
2690 * | ... | |... | |... |
2691 * |next |->|next |->|next |->...
2692 * |nextWETE| |nextWETE| |nextWETE|
2693 * --------- --------- ^--------
2694 * | | |
2695 * V-------------------> V---> ...
2696 *
2697 */
2698static void computeWAET(OEdgeTableEntry *AET) {
2699 OEdgeTableEntry *pWETE;
2700 int inside = 1;
2701 int isInside = 0;
2702
2703 AET->nextWETE = (OEdgeTableEntry *)NULL;
2704 pWETE = AET;
2705 AET = AET->next;
2706 while (AET) {
2707 if (AET->ClockWise)
2708 isInside++;
2709 else
2710 isInside--;
2711
2712 if ((!inside && !isInside) || (inside && isInside)) {
2713 pWETE->nextWETE = AET;
2714 pWETE = AET;
2715 inside = !inside;
2716 }
2717 AET = AET->next;
2718 }
2719 pWETE->nextWETE = (OEdgeTableEntry *)NULL;
2720}
2721
2722/*
2723 * InsertionSort
2724 *
2725 * Just a simple insertion sort using
2726 * pointers and back pointers to sort the Active
2727 * Edge Table.
2728 *
2729 */
2730
2731static int InsertionSort(OEdgeTableEntry *AET) {
2732 OEdgeTableEntry *pETEchase;
2733 OEdgeTableEntry *pETEinsert;
2734 OEdgeTableEntry *pETEchaseBackTMP;
2735 int changed = 0;
2736
2737 AET = AET->next;
2738 while (AET) {
2739 pETEinsert = AET;
2740 pETEchase = AET;
2741 while (pETEchase->back->bres.minor_axis > AET->bres.minor_axis)
2742 pETEchase = pETEchase->back;
2743
2744 AET = AET->next;
2745 if (pETEchase != pETEinsert) {
2746 pETEchaseBackTMP = pETEchase->back;
2747 pETEinsert->back->next = AET;
2748 if (AET) AET->back = pETEinsert->back;
2749 pETEinsert->next = pETEchase;
2750 pETEchase->back->next = pETEinsert;
2751 pETEchase->back = pETEinsert;
2752 pETEinsert->back = pETEchaseBackTMP;
2753 changed = 1;
2754 }
2755 }
2756 return (changed);
2757}
2758
2759/*
2760 * Clean up our act.
2761 */
2762static void FreeStorage(OScanLineListBlock *pSLLBlock) {
2763 OScanLineListBlock *tmpSLLBlock;
2764
2765 while (pSLLBlock) {
2766 tmpSLLBlock = pSLLBlock->next;
2767 free(pSLLBlock);
2768 pSLLBlock = tmpSLLBlock;
2769 }
2770}
2771
2772/*
2773 * Create an array of rectangles from a list of points.
2774 * If indeed these things (POINTS, RECTS) are the same,
2775 * then this proc is still needed, because it allocates
2776 * storage for the array, which was allocated on the
2777 * stack by the calling procedure.
2778 *
2779 */
2780static int PtsToRegion(int numFullPtBlocks, int iCurPtBlock,
2781 OPOINTBLOCK *FirstPtBlock, OGdkRegion *reg) {
2782 OGdkRegionBox *rects;
2783 OGdkPoint *pts;
2784 OPOINTBLOCK *CurPtBlock;
2785 int i;
2786 OGdkRegionBox *extents;
2787 int numRects;
2788
2789 extents = &reg->extents;
2790
2791 numRects = ((numFullPtBlocks * NUMPTSTOBUFFER) + iCurPtBlock) >> 1;
2792
2793 OGROWREGION(reg, numRects);
2794
2795 CurPtBlock = FirstPtBlock;
2796 rects = reg->rects - 1;
2797 numRects = 0;
2798 extents->x1 = 1000000 /*G_MAXSHORT*/, extents->x2 = -1000000 /*G_MINSHORT*/;
2799
2800 for (; numFullPtBlocks >= 0; numFullPtBlocks--) {
2801 /* the loop uses 2 points per iteration */
2802 i = NUMPTSTOBUFFER >> 1;
2803 if (!numFullPtBlocks) i = iCurPtBlock >> 1;
2804 for (pts = CurPtBlock->pts; i--; pts += 2) {
2805 if (pts->x == pts[1].x) continue;
2806 if (numRects && pts->x == rects->x1 && pts->y == rects->y2 &&
2807 pts[1].x == rects->x2 &&
2808 (numRects == 1 || rects[-1].y1 != rects->y1) &&
2809 (i && pts[2].y > pts[1].y)) {
2810 rects->y2 = pts[1].y + 1;
2811 continue;
2812 }
2813 numRects++;
2814 rects++;
2815 rects->x1 = pts->x;
2816 rects->y1 = pts->y;
2817 rects->x2 = pts[1].x;
2818 rects->y2 = pts[1].y + 1;
2819 if (rects->x1 < extents->x1) extents->x1 = rects->x1;
2820 if (rects->x2 > extents->x2) extents->x2 = rects->x2;
2821 }
2822 CurPtBlock = CurPtBlock->next;
2823 }
2824
2825 if (numRects) {
2826 extents->y1 = reg->rects->y1;
2827 extents->y2 = rects->y2;
2828 } else {
2829 extents->x1 = 0;
2830 extents->y1 = 0;
2831 extents->x2 = 0;
2832 extents->y2 = 0;
2833 }
2834 reg->numRects = numRects;
2835
2836 return (TRUE);
2837}
2838
2851OGdkRegion *gdk_region_polygon(const OGdkPoint *points, int n_points,
2852 OGdkFillRule fill_rule) {
2853 OGdkRegion *region;
2854 OEdgeTableEntry *pAET; /* Active Edge Table */
2855 int y; /* current scanline */
2856 int iPts = 0; /* number of pts in buffer */
2857 OEdgeTableEntry *pWETE; /* Winding Edge Table Entry*/
2858 OScanLineList *pSLL; /* current scanLineList */
2859 OGdkPoint *pts; /* output buffer */
2860 OEdgeTableEntry *pPrevAET; /* ptr to previous AET */
2861 OEdgeTable ET = {0}; /* header node for ET */
2862 OEdgeTableEntry AET; /* header node for AET */
2863 OEdgeTableEntry *pETEs; /* EdgeTableEntries pool */
2864 OScanLineListBlock SLLBlock; /* header for scanlinelist */
2865 int fixWAET = FALSE;
2866 OPOINTBLOCK FirstPtBlock, *curPtBlock; /* PtBlock buffers */
2867 OPOINTBLOCK *tmpPtBlock;
2868 int numFullPtBlocks = 0;
2869
2870 region = gdk_region_new();
2871
2872 /* special case a rectangle */
2873 if (((n_points == 4) || ((n_points == 5) && (points[4].x == points[0].x) &&
2874 (points[4].y == points[0].y))) &&
2875 (((points[0].y == points[1].y) && (points[1].x == points[2].x) &&
2876 (points[2].y == points[3].y) && (points[3].x == points[0].x)) ||
2877 ((points[0].x == points[1].x) && (points[1].y == points[2].y) &&
2878 (points[2].x == points[3].x) && (points[3].y == points[0].y)))) {
2879 region->extents.x1 = MIN(points[0].x, points[2].x);
2880 region->extents.y1 = MIN(points[0].y, points[2].y);
2881 region->extents.x2 = MAX(points[0].x, points[2].x);
2882 region->extents.y2 = MAX(points[0].y, points[2].y);
2883 if ((region->extents.x1 != region->extents.x2) &&
2884 (region->extents.y1 != region->extents.y2)) {
2885 region->numRects = 1;
2886 *(region->rects) = region->extents;
2887 }
2888 return (region);
2889 }
2890
2891 pETEs = (OEdgeTableEntry *)malloc(sizeof(OEdgeTableEntry) * n_points);
2892
2893 pts = FirstPtBlock.pts;
2894 CreateETandAET(n_points, points, &ET, &AET, pETEs, &SLLBlock);
2895 pSLL = ET.scanlines.next;
2896 curPtBlock = &FirstPtBlock;
2897
2898 if (fill_rule == OGDK_EVEN_ODD_RULE) {
2899 /*
2900 * for each scanline
2901 */
2902 for (y = ET.ymin; y < ET.ymax; y++) {
2903 /*
2904 * Add a new edge to the active edge table when we
2905 * get to the next edge.
2906 */
2907 if (pSLL != NULL && y == pSLL->scanline) {
2908 loadAET(&AET, pSLL->edgelist);
2909 pSLL = pSLL->next;
2910 }
2911 pPrevAET = &AET;
2912 pAET = AET.next;
2913
2914 /*
2915 * for each active edge
2916 */
2917 while (pAET) {
2918 pts->x = pAET->bres.minor_axis, pts->y = y;
2919 pts++, iPts++;
2920
2921 /*
2922 * send out the buffer
2923 */
2924 if (iPts == NUMPTSTOBUFFER) {
2925 tmpPtBlock = (OPOINTBLOCK *)malloc(sizeof(OPOINTBLOCK));
2926 tmpPtBlock->next = NULL;
2927 curPtBlock->next = tmpPtBlock;
2928 curPtBlock = tmpPtBlock;
2929 pts = curPtBlock->pts;
2930 numFullPtBlocks++;
2931 iPts = 0;
2932 }
2933 OEVALUATEEDGEEVENODD(pAET, pPrevAET, y);
2934 }
2935 (void)InsertionSort(&AET);
2936 }
2937 } else {
2938 /*
2939 * for each scanline
2940 */
2941 for (y = ET.ymin; y < ET.ymax; y++) {
2942 /*
2943 * Add a new edge to the active edge table when we
2944 * get to the next edge.
2945 */
2946 if (pSLL != NULL && y == pSLL->scanline) {
2947 loadAET(&AET, pSLL->edgelist);
2948 computeWAET(&AET);
2949 pSLL = pSLL->next;
2950 }
2951 pPrevAET = &AET;
2952 pAET = AET.next;
2953 pWETE = pAET;
2954
2955 /*
2956 * for each active edge
2957 */
2958 while (pAET) {
2959 /*
2960 * add to the buffer only those edges that
2961 * are in the Winding active edge table.
2962 */
2963 if (pWETE == pAET) {
2964 pts->x = pAET->bres.minor_axis, pts->y = y;
2965 pts++, iPts++;
2966
2967 /*
2968 * send out the buffer
2969 */
2970 if (iPts == NUMPTSTOBUFFER) {
2971 tmpPtBlock = (OPOINTBLOCK *)malloc(sizeof(OPOINTBLOCK));
2972 tmpPtBlock->next = NULL;
2973 curPtBlock->next = tmpPtBlock;
2974 curPtBlock = tmpPtBlock;
2975 pts = curPtBlock->pts;
2976 numFullPtBlocks++;
2977 iPts = 0;
2978 }
2979 pWETE = pWETE->nextWETE;
2980 }
2981 OEVALUATEEDGEWINDING(pAET, pPrevAET, y, fixWAET);
2982 }
2983
2984 /*
2985 * recompute the winding active edge table if
2986 * we just resorted or have exited an edge.
2987 */
2988 if (InsertionSort(&AET) || fixWAET) {
2989 computeWAET(&AET);
2990 fixWAET = FALSE;
2991 }
2992 }
2993 }
2994 FreeStorage(SLLBlock.next);
2995 (void)PtsToRegion(numFullPtBlocks, iPts, &FirstPtBlock, region);
2996 for (curPtBlock = FirstPtBlock.next; --numFullPtBlocks >= 0;) {
2997 tmpPtBlock = curPtBlock->next;
2998 free(curPtBlock);
2999 curPtBlock = tmpPtBlock;
3000 }
3001 free(pETEs);
3002 return (region);
3003}
3004
3005// #define __GDK_POLYREG_GENERIC_C__
3006// #include "gdkaliasdef.c"
3007#endif // USE_NEW_REGION
A wrapper class for wxRegion with additional functionality.
Definition OCPNRegion.h:56