47#include "OCPNRegion.h"
53typedef enum { OGDK_EVEN_ODD_RULE, OGDK_WINDING_RULE } OGdkFillRule;
56 OGDK_OVERLAP_RECTANGLE_IN,
57 OGDK_OVERLAP_RECTANGLE_OUT,
58 OGDK_OVERLAP_RECTANGLE_PART
61#define EMPTY_REGION(pReg) pReg->numRects = 0
62#define REGION_NOT_EMPTY(pReg) pReg->numRects
102#define NUMPTSTOBUFFER 200
113#define INBOX(r, x, y) \
114 ((((r).x2 > x)) && (((r).x1 <= x)) && (((r).y2 > y)) && (((r).y1 <= y)))
120#define EXTENTCHECK(r1, r2) \
121 ((r1)->x2 > (r2)->x1 && (r1)->x1 < (r2)->x2 && (r1)->y2 > (r2)->y1 && \
135#define OGROWREGION(reg, nRects) \
137 if ((nRects) == 0) { \
138 if ((reg)->rects != &(reg)->extents) { \
139 free((reg)->rects); \
140 (reg)->rects = &(reg)->extents; \
142 } else if ((reg)->rects == &(reg)->extents) { \
143 (reg)->rects = (OGdkRegionBox *)malloc(nRects * sizeof(OGdkRegionBox)); \
144 (reg)->rects[0] = (reg)->extents; \
146 (reg)->rects = (OGdkRegionBox *)realloc((reg)->rects, \
147 sizeof(OGdkRegionBox) * nRects); \
148 (reg)->size = (nRects); \
154#define OMEMCHECK(reg, rect, firstrect) \
156 if ((reg)->numRects >= ((reg)->size - 1)) { \
157 OGROWREGION(reg, 2 * (reg)->size); \
158 (rect) = &(firstrect)[(reg)->numRects]; \
163#define MIN(a, b) wxMin(a, b)
167#define MAX(a, b) wxMax(a, b)
189#define OBRESINITPGON(dy, x1, x2, xStart, d, m, m1, incr1, incr2) \
199 dx = (x2) - xStart; \
203 incr1 = -2 * dx + 2 * (dy) * m1; \
204 incr2 = -2 * dx + 2 * (dy) * m; \
205 d = 2 * m * (dy) - 2 * dx - 2 * (dy); \
209 incr1 = 2 * dx - 2 * (dy) * m1; \
210 incr2 = 2 * dx - 2 * (dy) * m; \
211 d = -2 * m * (dy) + 2 * dx; \
216#define OBRESINCRPGON(d, minval, m, m1, incr1, incr2) \
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)
255#define OBRESINCRPGONSTRUCT(bres) \
256 OBRESINCRPGON(bres.d, bres.minor_axis, bres.m, bres.m1, bres.incr1, \
263#define COUNTERCLOCKWISE -1
291#define SLLSPERBLOCK 25
311#define OEVALUATEEDGEWINDING(pAET, pPrevAET, y, fixWAET) \
313 if (pAET->ymax == y) { \
314 pPrevAET->next = pAET->next; \
315 pAET = pPrevAET->next; \
317 if (pAET) pAET->back = pPrevAET; \
319 OBRESINCRPGONSTRUCT(pAET->bres); \
332#define OEVALUATEEDGEEVENODD(pAET, pPrevAET, y) \
334 if (pAET->ymax == y) { \
335 pPrevAET->next = pAET->next; \
336 pAET = pPrevAET->next; \
337 if (pAET) pAET->back = pPrevAET; \
339 OBRESINCRPGONSTRUCT(pAET->bres); \
349bool gdk_region_point_in(
const OGdkRegion *region,
int x,
int y);
350OGdkOverlapType gdk_region_rect_in(
const OGdkRegion *region,
352void gdk_region_offset(
OGdkRegion *region,
int dx,
int dy);
357 OGdkFillRule fill_rule);
361bool gdk_region_empty(
const OGdkRegion *region);
363void gdk_region_get_rectangles(
const OGdkRegion *region,
376 m_region = gdk_region_copy(refData.m_region);
380 if (m_region) gdk_region_destroy(m_region);
391#define M_REGIONDATA ((OCPNRegionRefData *)m_refData)
392#define M_REGIONDATA_OF(rgn) ((OCPNRegionRefData *)(rgn.m_refData))
398#define M_REGIONDATA ((OCPNRegionRefData *)m_refData)
400#ifndef USE_NEW_REGION
402OCPNRegion::OCPNRegion(wxCoord x, wxCoord y, wxCoord w, wxCoord h)
403 : wxRegion(x, y, w, h)
407OCPNRegion::OCPNRegion(
const wxPoint &topLeft,
const wxPoint &bottomRight)
408 : wxRegion(topLeft.x, topLeft.y, bottomRight.x - topLeft.x,
409 bottomRight.y - topLeft.y) {}
411OCPNRegion::OCPNRegion(
const wxRect &rect)
412 : wxRegion(rect.x, rect.y, rect.width, rect.height) {}
414OCPNRegion::OCPNRegion(
const wxRegion ®ion) : wxRegion(region) {}
416OCPNRegion::OCPNRegion(
size_t n,
const wxPoint *points,
int fillStyle)
417 : wxRegion(n, points,
418#if wxCHECK_VERSION(2, 9, 0)
424wxRegion *OCPNRegion::GetNew_wxRegion()
const {
return new wxRegion(
this); }
430OCPNRegion::OCPNRegion(wxCoord x, wxCoord y, wxCoord w, wxCoord h) {
431 InitRect(x, y, w, h);
434OCPNRegion::OCPNRegion(
const wxPoint &topLeft,
const wxPoint &bottomRight) {
435 InitRect(topLeft.x, topLeft.y, bottomRight.x - topLeft.x,
436 bottomRight.y - topLeft.y);
439OCPNRegion::OCPNRegion(
const wxRect &rect) {
440 InitRect(rect.x, rect.y, rect.width, rect.height);
443OCPNRegion::OCPNRegion(
const wxRegion ®ion) {
444 wxRegionIterator ri(region);
445 if (!ri.HaveRects())
return;
447 wxRect rect = ri.GetRect();
448 InitRect(rect.x, rect.y, rect.width, rect.height);
451 while (ri.HaveRects()) {
457OCPNRegion::~OCPNRegion() {}
459void OCPNRegion::InitRect(wxCoord x, wxCoord y, wxCoord w, wxCoord h) {
468 M_REGIONDATA->m_region = gdk_region_rectangle(&rect);
477OCPNRegion::OCPNRegion(
size_t n,
const wxPoint *points,
int fillStyle) {
479 for (
size_t i = 0; i < n; i++) {
480 gdkpoints[i].x = points[i].x;
481 gdkpoints[i].y = points[i].y;
488 fillStyle == wxWINDING_RULE ? OGDK_WINDING_RULE : OGDK_EVEN_ODD_RULE);
490 M_REGIONDATA->m_region = reg;
500wxObjectRefData *OCPNRegion::CreateRefData()
const {
504wxObjectRefData *OCPNRegion::CloneRefData(
const wxObjectRefData *data)
const {
512bool OCPNRegion::ODoIsEqual(
const OCPNRegion ®ion)
const {
513 if (!region.m_refData)
return false;
515 return ogdk_region_equal(M_REGIONDATA->m_region,
516 M_REGIONDATA_OF(region)->m_region);
523void OCPNRegion::Clear() { UnRef(); }
525bool OCPNRegion::ODoUnionWithRect(
const wxRect &r) {
529 if (r.IsEmpty())
return true;
532 InitRect(r.x, r.y, r.width, r.height);
539 rect.width = r.width;
540 rect.height = r.height;
542 gdk_region_union_with_rect(M_REGIONDATA->m_region, &rect);
548bool OCPNRegion::ODoUnionWithRegion(
const OCPNRegion ®ion) {
549 wxCHECK_MSG(region.Ok(),
false, _T(
"invalid region"));
553 M_REGIONDATA->m_region = gdk_region_new();
558 gdk_region_union(M_REGIONDATA->m_region, (
OGdkRegion *)region.GetRegion());
563bool OCPNRegion::ODoIntersect(
const OCPNRegion ®ion) {
564 wxCHECK_MSG(region.Ok(),
false, _T(
"invalid region"));
573 gdk_region_intersect(M_REGIONDATA->m_region,
579bool OCPNRegion::ODoSubtract(
const OCPNRegion ®ion) {
580 wxCHECK_MSG(region.Ok(),
false, _T(
"invalid region"));
588 gdk_region_subtract(M_REGIONDATA->m_region, (
OGdkRegion *)region.GetRegion());
594bool OCPNRegion::DoXor(
const OCPNRegion& region )
596 wxCHECK_MSG( region.Ok(),
false, _T(
"invalid region") );
611bool OCPNRegion::ODoOffset(wxCoord x, wxCoord y) {
612 if (!m_refData)
return false;
616 gdk_region_offset(M_REGIONDATA->m_region, x, y);
625bool OCPNRegion::ODoGetBox(wxCoord &x, wxCoord &y, wxCoord &w,
629 gdk_region_get_clipbox(M_REGIONDATA->m_region, &rect);
646bool OCPNRegion::IsEmpty()
const {
647 if (!m_refData)
return true;
649 return gdk_region_empty(M_REGIONDATA->m_region);
652wxRegionContain OCPNRegion::ODoContainsPoint(wxCoord x, wxCoord y)
const {
653 if (!m_refData)
return wxOutRegion;
655 if (gdk_region_point_in(M_REGIONDATA->m_region, x, y))
661wxRegionContain OCPNRegion::ODoContainsRect(
const wxRect &r)
const {
662 if (!m_refData)
return wxOutRegion;
667 rect.width = r.width;
668 rect.height = r.height;
669 OGdkOverlapType res = gdk_region_rect_in(M_REGIONDATA->m_region, &rect);
671 case OGDK_OVERLAP_RECTANGLE_IN:
673 case OGDK_OVERLAP_RECTANGLE_OUT:
675 case OGDK_OVERLAP_RECTANGLE_PART:
682void *OCPNRegion::GetRegion()
const {
683 if (!m_refData)
return NULL;
685 return M_REGIONDATA->m_region;
688wxRegion *OCPNRegion::GetNew_wxRegion()
const {
689 wxRegion *r =
new wxRegion;
694 gdk_region_get_rectangles((
OGdkRegion *)GetRegion(), &gdkrects, &numRects);
697 for (
int i = 0; i < numRects; ++i) {
704 wr.height = gr.height;
719#ifndef USE_NEW_REGION
721OCPNRegionIterator::OCPNRegionIterator(
const OCPNRegion ®ion) {
722 m_ri =
new wxRegionIterator(region);
725OCPNRegionIterator::~OCPNRegionIterator() {
delete m_ri; }
727void OCPNRegionIterator::Reset() { m_ri->Reset(); }
729void OCPNRegionIterator::Reset(
const OCPNRegion ®ion) {
733wxRect OCPNRegionIterator::GetRect()
const {
return m_ri->GetRect(); }
735bool OCPNRegionIterator::HaveRects()
const {
return m_ri->HaveRects(); }
737void OCPNRegionIterator::NextRect() { ++(*m_ri); }
743OCPNRegionIterator::OCPNRegionIterator() {
748OCPNRegionIterator::OCPNRegionIterator(
const OCPNRegion ®ion) {
753void OCPNRegionIterator::Init() {
758OCPNRegionIterator::~OCPNRegionIterator() { wxDELETEA(m_rects); }
760void OCPNRegionIterator::Reset() { m_current = 0u; }
762void OCPNRegionIterator::NextRect() {
763 if (HaveRects()) ++m_current;
766void OCPNRegionIterator::CreateRects(
const OCPNRegion ®ion) {
771 if (!gdkregion)
return;
775 gdk_region_get_rectangles(gdkregion, &gdkrects, &numRects);
777 m_numRects = numRects;
779 m_rects =
new wxRect[m_numRects];
780 for (
size_t i = 0; i < m_numRects; ++i) {
782 wxRect &wr = m_rects[i];
786 wr.height = gr.height;
792void OCPNRegionIterator::Reset(
const OCPNRegion ®ion) {
798bool OCPNRegionIterator::HaveRects()
const {
return m_current < m_numRects; }
800wxRect OCPNRegionIterator::GetRect()
const {
802 if (HaveRects()) r = m_rects[m_current];
897 const OGdkRegion *reg2, overlapFunc overlapFn,
898 nonOverlapFunc nonOverlap1Fn,
899 nonOverlapFunc nonOverlap2Fn);
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;
937 if (rectangle->width <= 0 || rectangle->height <= 0)
return gdk_region_new();
939 temp = gdk_region_new();
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;
965 temp = gdk_region_new();
967 miRegionCopy(temp, region);
980void gdk_region_get_clipbox(
const OGdkRegion *region,
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;
1000void gdk_region_get_rectangles(
const OGdkRegion *region,
1008 *n_rectangles = region->numRects;
1012 for (i = 0; i < region->numRects; i++) {
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;
1037 if (rect->width <= 0 || rect->height <= 0)
return;
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;
1047 gdk_region_union(region, &tmp_region);
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;
1076 pExtents = &pReg->extents;
1078 pBoxEnd = &pBox[pReg->numRects - 1];
1087 pExtents->x1 = pBox->x1;
1088 pExtents->y1 = pBox->y1;
1089 pExtents->x2 = pBoxEnd->x2;
1090 pExtents->y2 = pBoxEnd->y2;
1093 while (pBox <= pBoxEnd) {
1094 if (pBox->x1 < pExtents->x1) {
1095 pExtents->x1 = pBox->x1;
1097 if (pBox->x2 > pExtents->x2) {
1098 pExtents->x2 = pBox->x2;
1114 if (region->rects != ®ion->extents) free(region->rects);
1126void gdk_region_offset(
OGdkRegion *region,
int x,
int y) {
1132 pbox = region->rects;
1133 nbox = region->numRects;
1142 if (region->rects != ®ion->extents) {
1143 region->extents.x1 += x;
1144 region->extents.x2 += x;
1145 region->extents.y1 += y;
1146 region->extents.y2 += y;
1170#define ZOpRegion(a, b) \
1172 gdk_region_union(a, b); \
1174 gdk_region_intersect(a, b)
1175#define ZShiftRegion(a, b) \
1177 gdk_region_offset(a, b, 0); \
1179 gdk_region_offset(a, 0, b)
1182 unsigned int dx,
int xdir,
int grow) {
1183 unsigned int shift = 1;
1188 ZShiftRegion(r, -(
int)shift);
1194 ZShiftRegion(s, -(
int)shift);
1213void gdk_region_shrink(
OGdkRegion *region,
int dx,
int dy) {
1219 if (!dx && !dy)
return;
1221 s = gdk_region_new();
1222 t = gdk_region_new();
1226 if (dx) Compress(region, s, t, (
unsigned)2 * dx, TRUE, grow);
1230 if (dy) Compress(region, s, t, (
unsigned)2 * dy, FALSE, grow);
1232 gdk_region_offset(region, dx, dy);
1233 gdk_region_destroy(s);
1234 gdk_region_destroy(t);
1261 pNextRect = &pReg->rects[pReg->numRects];
1263 while ((r1 != r1End) && (r2 != r2End)) {
1264 x1 = MAX(r1->x1, r2->x1);
1265 x2 = MIN(r1->x2, r2->x2);
1277 OMEMCHECK(pReg, pNextRect, pReg->rects);
1282 pReg->numRects += 1;
1292 if (r1->x2 < r2->x2) {
1294 }
else if (r2->x2 < r1->x2) {
1317 if ((!(source1->numRects)) || (!(source2->numRects)) ||
1318 (!EXTENTCHECK(&source1->extents, &source2->extents)))
1319 source1->numRects = 0;
1321 miRegionOp(source1, source1, source2, miIntersectO, (nonOverlapFunc)NULL,
1322 (nonOverlapFunc)NULL);
1330 miSetExtents(source1);
1336 if (dstrgn->size < rgn->numRects) {
1337 if (dstrgn->rects != &dstrgn->extents) free(dstrgn->rects);
1341 dstrgn->size = rgn->numRects;
1344 dstrgn->numRects = rgn->numRects;
1345 dstrgn->extents = rgn->extents;
1347 memcpy(dstrgn->rects, rgn->rects, rgn->numRects *
sizeof(
OGdkRegionBox));
1386 pRegEnd = &pReg->rects[pReg->numRects];
1388 pPrevBox = &pReg->rects[prevStart];
1389 prevNumRects = curStart - prevStart;
1396 pCurBox = &pReg->rects[curStart];
1397 bandY1 = pCurBox->y1;
1398 for (curNumRects = 0; (pCurBox != pRegEnd) && (pCurBox->y1 == bandY1);
1403 if (pCurBox != pRegEnd) {
1411 while (pRegEnd[-1].y1 == pRegEnd->y1) {
1414 curStart = pRegEnd - pReg->rects;
1415 pRegEnd = pReg->rects + pReg->numRects;
1418 if ((curNumRects == prevNumRects) && (curNumRects != 0)) {
1419 pCurBox -= curNumRects;
1424 if (pPrevBox->y2 == pCurBox->y1) {
1432 if ((pPrevBox->x1 != pCurBox->x1) || (pPrevBox->x2 != pCurBox->x2)) {
1441 }
while (prevNumRects != 0);
1443 pReg->numRects -= curNumRects;
1444 pCurBox -= curNumRects;
1445 pPrevBox -= curNumRects;
1453 pPrevBox->y2 = pCurBox->y2;
1457 }
while (curNumRects != 0);
1469 if (pCurBox == pRegEnd) {
1470 curStart = prevStart;
1473 *pPrevBox++ = *pCurBox++;
1474 }
while (pCurBox != pRegEnd);
1508static void miRegionOp(
1510 overlapFunc overlapFn,
1512 nonOverlapFunc nonOverlap1Fn,
1515 nonOverlapFunc nonOverlap2Fn)
1546 r1End = r1 + reg1->numRects;
1547 r2End = r2 + reg2->numRects;
1549 oldRects = newReg->rects;
1551 EMPTY_REGION(newReg);
1560 newReg->size = MAX(reg1->numRects, reg2->numRects) * 2;
1576 if (reg1->extents.y1 < reg2->extents.y1)
1577 ybot = reg1->extents.y1;
1579 ybot = reg2->extents.y1;
1593 curBand = newReg->numRects;
1603 while ((r1BandEnd != r1End) && (r1BandEnd->y1 == r1->y1)) {
1608 while ((r2BandEnd != r2End) && (r2BandEnd->y1 == r2->y1)) {
1620 if (r1->y1 < r2->y1) {
1621 top = MAX(r1->y1, ybot);
1622 bot = MIN(r1->y2, r2->y1);
1627 (*nonOverlap1Fn)(newReg, r1, r1BandEnd, top, bot);
1631 }
else if (r2->y1 < r1->y1) {
1632 top = MAX(r2->y1, ybot);
1633 bot = MIN(r2->y2, r1->y1);
1638 (*nonOverlap2Fn)(newReg, r2, r2BandEnd, top, bot);
1652 if (newReg->numRects != curBand) {
1653 prevBand = miCoalesce(newReg, prevBand, curBand);
1660 ybot = MIN(r1->y2, r2->y2);
1661 curBand = newReg->numRects;
1663 (*overlapFn)(newReg, r1, r1BandEnd, r2, r2BandEnd, ytop, ybot);
1666 if (newReg->numRects != curBand) {
1667 prevBand = miCoalesce(newReg, prevBand, curBand);
1674 if (r1->y2 == ybot) {
1677 if (r2->y2 == ybot) {
1680 }
while ((r1 != r1End) && (r2 != r2End));
1685 curBand = newReg->numRects;
1687 if (nonOverlap1Fn != (nonOverlapFunc)NULL) {
1690 while ((r1BandEnd < r1End) && (r1BandEnd->y1 == r1->y1)) {
1693 (*nonOverlap1Fn)(newReg, r1, r1BandEnd, MAX(r1->y1, ybot), r1->y2);
1695 }
while (r1 != r1End);
1697 }
else if ((r2 != r2End) && (nonOverlap2Fn != (nonOverlapFunc)NULL)) {
1700 while ((r2BandEnd < r2End) && (r2BandEnd->y1 == r2->y1)) {
1703 (*nonOverlap2Fn)(newReg, r2, r2BandEnd, MAX(r2->y1, ybot), r2->y2);
1705 }
while (r2 != r2End);
1708 if (newReg->numRects != curBand) {
1709 (void)miCoalesce(newReg, prevBand, curBand);
1720 if (newReg->numRects < (newReg->size >> 1)) {
1721 if (REGION_NOT_EMPTY(newReg)) {
1722 newReg->size = newReg->numRects;
1733 free(newReg->rects);
1734 newReg->rects = &newReg->extents;
1738 if (oldRects != &newReg->extents) free(oldRects);
1765 pNextRect = &pReg->rects[pReg->numRects];
1771 OMEMCHECK(pReg, pNextRect, pReg->rects);
1772 pNextRect->x1 = r->x1;
1774 pNextRect->x2 = r->x2;
1776 pReg->numRects += 1;
1805 pNextRect = &pReg->rects[pReg->numRects];
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; \
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; \
1827 while ((r1 != r1End) && (r2 != r2End)) {
1828 if (r1->x1 < r2->x1) {
1838 }
while (r1 != r1End);
1840 while (r2 != r2End) {
1863 if ((source1 == source2) || (!(source2->numRects)))
return;
1868 if (!(source1->numRects)) {
1869 miRegionCopy(source1, source2);
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))
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);
1895 miRegionOp(source1, source1, source2, miUnionO, miUnionNonO, miUnionNonO);
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);
1926 pNextRect = &pReg->rects[pReg->numRects];
1932 OMEMCHECK(pReg, pNextRect, pReg->rects);
1933 pNextRect->x1 = r->x1;
1935 pNextRect->x2 = r->x2;
1937 pReg->numRects += 1;
1970 pNextRect = &pReg->rects[pReg->numRects];
1972 while ((r1 != r1End) && (r2 != r2End)) {
1978 }
else if (r2->x1 <= x1) {
1989 if (r1 != r1End) x1 = r1->x1;
1997 }
else if (r2->x1 < r1->x2) {
2003 OMEMCHECK(pReg, pNextRect, pReg->rects);
2006 pNextRect->x2 = r2->x1;
2008 pReg->numRects += 1;
2019 if (r1 != r1End) x1 = r1->x1;
2031 OMEMCHECK(pReg, pNextRect, pReg->rects);
2034 pNextRect->x2 = r1->x2;
2036 pReg->numRects += 1;
2041 if (r1 != r1End) x1 = r1->x1;
2048 while (r1 != r1End) {
2050 OMEMCHECK(pReg, pNextRect, pReg->rects);
2053 pNextRect->x2 = r1->x2;
2055 pReg->numRects += 1;
2080 if ((!(source1->numRects)) || (!(source2->numRects)) ||
2081 (!EXTENTCHECK(&source1->extents, &source2->extents)))
2084 miRegionOp(source1, source1, source2, miSubtractO, miSubtractNonO1,
2085 (nonOverlapFunc)NULL);
2093 miSetExtents(source1);
2111 trb = gdk_region_copy(source2);
2113 gdk_region_subtract(trb, source1);
2114 gdk_region_subtract(source1, source2);
2116 gdk_region_union(source1, trb);
2118 gdk_region_destroy(trb);
2129bool gdk_region_empty(
const OGdkRegion *region) {
2132 if (region->numRects == 0)
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;
2178bool gdk_region_point_in(
const OGdkRegion *region,
int x,
int y) {
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;
2202OGdkOverlapType gdk_region_rect_in(
const OGdkRegion *region,
2208 bool partIn, partOut;
2220 prect->x2 = rx + rectangle->width;
2221 prect->y2 = ry + rectangle->height;
2224 if ((region->numRects == 0) || !EXTENTCHECK(®ion->extents, prect))
2225 return OGDK_OVERLAP_RECTANGLE_OUT;
2231 for (pbox = region->rects, pboxEnd = pbox + region->numRects; pbox < pboxEnd;
2236 if (pbox->y1 > ry) {
2238 if (partIn || (pbox->y1 >= prect->y2))
break;
2242 if (pbox->x2 <= rx)
continue;
2244 if (pbox->x1 > rx) {
2249 if (pbox->x1 < prect->x2) {
2254 if (pbox->x2 >= prect->x2) {
2256 if (ry >= prect->y2)
break;
2270 return (partIn ? ((ry < prect->y2) ? OGDK_OVERLAP_RECTANGLE_PART
2271 : OGDK_OVERLAP_RECTANGLE_IN)
2272 : OGDK_OVERLAP_RECTANGLE_OUT);
2277 gdk_region_unsorted_spans_intersect_foreach (GdkRegion *region,
2278 const GdkSpan *spans,
2280 GdkSpanFunc function,
2283 gint i, left, right, y;
2284 gint clipped_left, clipped_right;
2286 GdkRegionBox *pboxEnd;
2288 if (!region->numRects)
2291 for (i=0;i<n_spans;i++)
2295 right = left + spans[i].width;
2297 if (! ((region->extents.y1 <= y) &&
2298 (region->extents.y2 > y) &&
2299 (region->extents.x1 < right) &&
2300 (region->extents.x2 > left)) )
2304 for (pbox = region->rects, pboxEnd = pbox + region->numRects;
2314 if ((right > pbox->x1) && (left < pbox->x2))
2318 clipped_left = MAX (left, pbox->x1);
2319 clipped_right = MIN (right, pbox->x2);
2322 out_span.x = clipped_left;
2323 out_span.width = clipped_right - clipped_left;
2324 (*function) (&out_span, data);
2344 gdk_region_spans_intersect_foreach (GdkRegion *region,
2345 const GdkSpan *spans,
2348 GdkSpanFunc function,
2351 gint left, right, y;
2352 gint clipped_left, clipped_right;
2354 GdkRegionBox *pboxEnd;
2355 const GdkSpan *span, *tmpspan;
2356 const GdkSpan *end_span;
2358 g_return_if_fail (region != NULL);
2359 g_return_if_fail (spans != NULL);
2363 gdk_region_unsorted_spans_intersect_foreach (region,
2371 if ((!region->numRects) || (n_spans == 0))
2381 end_span = spans + n_spans;
2382 pbox = region->rects;
2383 pboxEnd = pbox + region->numRects;
2384 while (pbox < pboxEnd)
2386 while ((pbox->y2 < span->y) || (span->y < pbox->y1))
2389 if (pbox->y2 < span->y)
2392 if (pbox == pboxEnd)
2396 if (span->y < pbox->y1)
2399 if (span == end_span)
2406 while ((tmpspan < end_span) &&
2407 (tmpspan->y < pbox->y2))
2411 right = left + tmpspan->width;
2413 if ((right > pbox->x1) && (left < pbox->x2))
2417 clipped_left = MAX (left, pbox->x1);
2418 clipped_right = MIN (right, pbox->x2);
2421 out_span.x = clipped_left;
2422 out_span.width = clipped_right - clipped_left;
2423 (*function) (&out_span, data);
2482#define LARGE_COORDINATE 1000000
2483#define SMALL_COORDINATE -LARGE_COORDINATE
2509 pPrevSLL = &ET->scanlines;
2510 pSLL = pPrevSLL->next;
2511 while (pSLL && (pSLL->scanline < scanline)) {
2519 if ((!pSLL) || (pSLL->scanline > scanline)) {
2520 if (*iSLLBlock > SLLSPERBLOCK - 1) {
2522 (*SLLBlock)->next = tmpSLLBlock;
2524 *SLLBlock = tmpSLLBlock;
2527 pSLL = &((*SLLBlock)->SLLs[(*iSLLBlock)++]);
2529 pSLL->next = pPrevSLL->next;
2531 pPrevSLL->next = pSLL;
2533 pSLL->scanline = scanline;
2539 start = pSLL->edgelist;
2540 while (start && (start->bres.minor_axis < ETE->bres.minor_axis)) {
2542 start = start->next;
2549 pSLL->edgelist = ETE;
2585 if (count < 2)
return;
2593 AET->bres.minor_axis = SMALL_COORDINATE;
2599 ET->ymax = SMALL_COORDINATE;
2600 ET->ymin = LARGE_COORDINATE;
2603 PrevPt = &pts[count - 1];
2616 if (PrevPt->y > CurrPt->y) {
2617 bottom = PrevPt, top = CurrPt;
2618 pETEs->ClockWise = 0;
2620 bottom = CurrPt, top = PrevPt;
2621 pETEs->ClockWise = 1;
2627 if (bottom->y != top->y) {
2628 pETEs->ymax = bottom->y - 1;
2633 dy = bottom->y - top->y;
2634 OBRESINITPGONSTRUCT(dy, top->x, bottom->x, pETEs->bres);
2636 InsertEdgeInET(ET, pETEs, top->y, &pSLLBlock, &iSLLBlock);
2638 if (PrevPt->y > ET->ymax) ET->ymax = PrevPt->y;
2639 if (PrevPt->y < ET->ymin) ET->ymin = PrevPt->y;
2663 while (AET && (AET->bres.minor_axis < ETEs->bres.minor_axis)) {
2669 if (AET) AET->back = ETEs;
2670 ETEs->back = pPrevAET;
2671 pPrevAET->next = ETEs;
2712 if ((!inside && !isInside) || (inside && isInside)) {
2713 pWETE->nextWETE = AET;
2741 while (pETEchase->back->bres.minor_axis > AET->bres.minor_axis)
2742 pETEchase = pETEchase->back;
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;
2766 tmpSLLBlock = pSLLBlock->next;
2768 pSLLBlock = tmpSLLBlock;
2780static int PtsToRegion(
int numFullPtBlocks,
int iCurPtBlock,
2789 extents = ®->extents;
2791 numRects = ((numFullPtBlocks * NUMPTSTOBUFFER) + iCurPtBlock) >> 1;
2793 OGROWREGION(reg, numRects);
2795 CurPtBlock = FirstPtBlock;
2796 rects = reg->rects - 1;
2798 extents->x1 = 1000000 , extents->x2 = -1000000 ;
2800 for (; numFullPtBlocks >= 0; numFullPtBlocks--) {
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;
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;
2822 CurPtBlock = CurPtBlock->next;
2826 extents->y1 = reg->rects->y1;
2827 extents->y2 = rects->y2;
2834 reg->numRects = numRects;
2852 OGdkFillRule fill_rule) {
2865 int fixWAET = FALSE;
2868 int numFullPtBlocks = 0;
2870 region = gdk_region_new();
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;
2893 pts = FirstPtBlock.pts;
2894 CreateETandAET(n_points, points, &ET, &AET, pETEs, &SLLBlock);
2895 pSLL = ET.scanlines.next;
2896 curPtBlock = &FirstPtBlock;
2898 if (fill_rule == OGDK_EVEN_ODD_RULE) {
2902 for (y = ET.ymin; y < ET.ymax; y++) {
2907 if (pSLL != NULL && y == pSLL->scanline) {
2908 loadAET(&AET, pSLL->edgelist);
2918 pts->x = pAET->bres.minor_axis, pts->y = y;
2924 if (iPts == NUMPTSTOBUFFER) {
2926 tmpPtBlock->next = NULL;
2927 curPtBlock->next = tmpPtBlock;
2928 curPtBlock = tmpPtBlock;
2929 pts = curPtBlock->pts;
2933 OEVALUATEEDGEEVENODD(pAET, pPrevAET, y);
2935 (void)InsertionSort(&AET);
2941 for (y = ET.ymin; y < ET.ymax; y++) {
2946 if (pSLL != NULL && y == pSLL->scanline) {
2947 loadAET(&AET, pSLL->edgelist);
2963 if (pWETE == pAET) {
2964 pts->x = pAET->bres.minor_axis, pts->y = y;
2970 if (iPts == NUMPTSTOBUFFER) {
2972 tmpPtBlock->next = NULL;
2973 curPtBlock->next = tmpPtBlock;
2974 curPtBlock = tmpPtBlock;
2975 pts = curPtBlock->pts;
2979 pWETE = pWETE->nextWETE;
2981 OEVALUATEEDGEWINDING(pAET, pPrevAET, y, fixWAET);
2988 if (InsertionSort(&AET) || fixWAET) {
2994 FreeStorage(SLLBlock.next);
2995 (void)PtsToRegion(numFullPtBlocks, iPts, &FirstPtBlock, region);
2996 for (curPtBlock = FirstPtBlock.next; --numFullPtBlocks >= 0;) {
2997 tmpPtBlock = curPtBlock->next;
2999 curPtBlock = tmpPtBlock;
A wrapper class for wxRegion with additional functionality.