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