44 #include <wx/wxprec.h>
46 #include <wx/region.h>
47 #include "OCPNRegion.h"
53 typedef 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) \
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); \
349 bool gdk_region_point_in(
const OGdkRegion *region,
int x,
int y);
350 OGdkOverlapType gdk_region_rect_in(
const OGdkRegion *region,
352 void gdk_region_offset(
OGdkRegion *region,
int dx,
int dy);
357 OGdkFillRule fill_rule);
361 bool gdk_region_empty(
const OGdkRegion *region);
363 void 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))
394 IMPLEMENT_DYNAMIC_CLASS(
OCPNRegion, wxGDIObject)
400 #define M_REGIONDATA ((OCPNRegionRefData *)m_refData)
402 #ifndef USE_NEW_REGION
404 OCPNRegion::OCPNRegion(wxCoord x, wxCoord y, wxCoord w, wxCoord h)
405 : wxRegion(x, y, w, h)
409 OCPNRegion::OCPNRegion(
const wxPoint &topLeft,
const wxPoint &bottomRight)
410 : wxRegion(topLeft.x, topLeft.y, bottomRight.x - topLeft.x,
411 bottomRight.y - topLeft.y) {}
413 OCPNRegion::OCPNRegion(
const wxRect &rect)
414 : wxRegion(rect.x, rect.y, rect.width, rect.height) {}
416 OCPNRegion::OCPNRegion(
const wxRegion ®ion) : wxRegion(region) {}
418 OCPNRegion::OCPNRegion(
size_t n,
const wxPoint *points,
int fillStyle)
419 : wxRegion(n, points,
420 #if wxCHECK_VERSION(2, 9, 0)
426 wxRegion *OCPNRegion::GetNew_wxRegion()
const {
return new wxRegion(
this); }
430 #ifdef USE_NEW_REGION
432 OCPNRegion::OCPNRegion(wxCoord x, wxCoord y, wxCoord w, wxCoord h) {
433 InitRect(x, y, w, h);
436 OCPNRegion::OCPNRegion(
const wxPoint &topLeft,
const wxPoint &bottomRight) {
437 InitRect(topLeft.x, topLeft.y, bottomRight.x - topLeft.x,
438 bottomRight.y - topLeft.y);
441 OCPNRegion::OCPNRegion(
const wxRect &rect) {
442 InitRect(rect.x, rect.y, rect.width, rect.height);
445 OCPNRegion::OCPNRegion(
const wxRegion ®ion) {
446 wxRegionIterator ri(region);
447 if (!ri.HaveRects())
return;
449 wxRect rect = ri.GetRect();
450 InitRect(rect.x, rect.y, rect.width, rect.height);
453 while (ri.HaveRects()) {
459 OCPNRegion::~OCPNRegion() {}
461 void OCPNRegion::InitRect(wxCoord x, wxCoord y, wxCoord w, wxCoord h) {
470 M_REGIONDATA->m_region = gdk_region_rectangle(&rect);
479 OCPNRegion::OCPNRegion(
size_t n,
const wxPoint *points,
int fillStyle) {
481 for (
size_t i = 0; i < n; i++) {
482 gdkpoints[i].x = points[i].x;
483 gdkpoints[i].y = points[i].y;
490 fillStyle == wxWINDING_RULE ? OGDK_WINDING_RULE : OGDK_EVEN_ODD_RULE);
492 M_REGIONDATA->m_region = reg;
502 wxObjectRefData *OCPNRegion::CreateRefData()
const {
506 wxObjectRefData *OCPNRegion::CloneRefData(
const wxObjectRefData *data)
const {
514 bool OCPNRegion::ODoIsEqual(
const OCPNRegion ®ion)
const {
515 if (!region.m_refData)
return false;
517 return ogdk_region_equal(M_REGIONDATA->m_region,
518 M_REGIONDATA_OF(region)->m_region);
525 void OCPNRegion::Clear() { UnRef(); }
527 bool OCPNRegion::ODoUnionWithRect(
const wxRect &r) {
531 if (r.IsEmpty())
return true;
534 InitRect(r.x, r.y, r.width, r.height);
541 rect.width = r.width;
542 rect.height = r.height;
544 gdk_region_union_with_rect(M_REGIONDATA->m_region, &rect);
550 bool OCPNRegion::ODoUnionWithRegion(
const OCPNRegion ®ion) {
551 wxCHECK_MSG(region.Ok(),
false, _T(
"invalid region"));
555 M_REGIONDATA->m_region = gdk_region_new();
560 gdk_region_union(M_REGIONDATA->m_region, (
OGdkRegion *)region.GetRegion());
565 bool OCPNRegion::ODoIntersect(
const OCPNRegion ®ion) {
566 wxCHECK_MSG(region.Ok(),
false, _T(
"invalid region"));
575 gdk_region_intersect(M_REGIONDATA->m_region,
581 bool OCPNRegion::ODoSubtract(
const OCPNRegion ®ion) {
582 wxCHECK_MSG(region.Ok(),
false, _T(
"invalid region"));
590 gdk_region_subtract(M_REGIONDATA->m_region, (
OGdkRegion *)region.GetRegion());
596 bool OCPNRegion::DoXor(
const OCPNRegion& region )
598 wxCHECK_MSG( region.Ok(),
false, _T(
"invalid region") );
613 bool OCPNRegion::ODoOffset(wxCoord x, wxCoord y) {
614 if (!m_refData)
return false;
618 gdk_region_offset(M_REGIONDATA->m_region, x, y);
627 bool OCPNRegion::ODoGetBox(wxCoord &x, wxCoord &y, wxCoord &w,
631 gdk_region_get_clipbox(M_REGIONDATA->m_region, &rect);
648 bool OCPNRegion::IsEmpty()
const {
649 if (!m_refData)
return true;
651 return gdk_region_empty(M_REGIONDATA->m_region);
654 wxRegionContain OCPNRegion::ODoContainsPoint(wxCoord x, wxCoord y)
const {
655 if (!m_refData)
return wxOutRegion;
657 if (gdk_region_point_in(M_REGIONDATA->m_region, x, y))
663 wxRegionContain OCPNRegion::ODoContainsRect(
const wxRect &r)
const {
664 if (!m_refData)
return wxOutRegion;
669 rect.width = r.width;
670 rect.height = r.height;
671 OGdkOverlapType res = gdk_region_rect_in(M_REGIONDATA->m_region, &rect);
673 case OGDK_OVERLAP_RECTANGLE_IN:
675 case OGDK_OVERLAP_RECTANGLE_OUT:
677 case OGDK_OVERLAP_RECTANGLE_PART:
684 void *OCPNRegion::GetRegion()
const {
685 if (!m_refData)
return NULL;
687 return M_REGIONDATA->m_region;
690 wxRegion *OCPNRegion::GetNew_wxRegion()
const {
691 wxRegion *r =
new wxRegion;
696 gdk_region_get_rectangles((
OGdkRegion *)GetRegion(), &gdkrects, &numRects);
699 for (
int i = 0; i < numRects; ++i) {
706 wr.height = gr.height;
721 #ifndef USE_NEW_REGION
723 OCPNRegionIterator::OCPNRegionIterator(
const OCPNRegion ®ion) {
724 m_ri =
new wxRegionIterator(region);
727 OCPNRegionIterator::~OCPNRegionIterator() {
delete m_ri; }
729 void OCPNRegionIterator::Reset() { m_ri->Reset(); }
731 void OCPNRegionIterator::Reset(
const OCPNRegion ®ion) {
735 wxRect OCPNRegionIterator::GetRect()
const {
return m_ri->GetRect(); }
737 bool OCPNRegionIterator::HaveRects()
const {
return m_ri->HaveRects(); }
739 void OCPNRegionIterator::NextRect() { ++(*m_ri); }
743 #ifdef USE_NEW_REGION
745 OCPNRegionIterator::OCPNRegionIterator() {
750 OCPNRegionIterator::OCPNRegionIterator(
const OCPNRegion ®ion) {
755 void OCPNRegionIterator::Init() {
760 OCPNRegionIterator::~OCPNRegionIterator() { wxDELETEA(m_rects); }
762 void OCPNRegionIterator::Reset() { m_current = 0u; }
764 void OCPNRegionIterator::NextRect() {
765 if (HaveRects()) ++m_current;
768 void OCPNRegionIterator::CreateRects(
const OCPNRegion ®ion) {
773 if (!gdkregion)
return;
777 gdk_region_get_rectangles(gdkregion, &gdkrects, &numRects);
779 m_numRects = numRects;
781 m_rects =
new wxRect[m_numRects];
782 for (
size_t i = 0; i < m_numRects; ++i) {
784 wxRect &wr = m_rects[i];
788 wr.height = gr.height;
794 void OCPNRegionIterator::Reset(
const OCPNRegion ®ion) {
800 bool OCPNRegionIterator::HaveRects()
const {
return m_current < m_numRects; }
802 wxRect OCPNRegionIterator::GetRect()
const {
804 if (HaveRects()) r = m_rects[m_current];
811 #ifdef USE_NEW_REGION
899 const OGdkRegion *reg2, overlapFunc overlapFn,
900 nonOverlapFunc nonOverlap1Fn,
901 nonOverlapFunc nonOverlap2Fn);
916 temp->rects = &temp->extents;
917 temp->extents.x1 = 0;
918 temp->extents.y1 = 0;
919 temp->extents.x2 = 0;
920 temp->extents.y2 = 0;
939 if (rectangle->width <= 0 || rectangle->height <= 0)
return gdk_region_new();
941 temp = gdk_region_new();
944 temp->rects = &temp->extents;
945 temp->extents.x1 = rectangle->x;
946 temp->extents.y1 = rectangle->y;
947 temp->extents.x2 = rectangle->x + rectangle->width;
948 temp->extents.y2 = rectangle->y + rectangle->height;
967 temp = gdk_region_new();
969 miRegionCopy(temp, region);
982 void gdk_region_get_clipbox(
const OGdkRegion *region,
987 rectangle->x = region->extents.x1;
988 rectangle->y = region->extents.y1;
989 rectangle->width = region->extents.x2 - region->extents.x1;
990 rectangle->height = region->extents.y2 - region->extents.y1;
1002 void gdk_region_get_rectangles(
const OGdkRegion *region,
1010 *n_rectangles = region->numRects;
1014 for (i = 0; i < region->numRects; i++) {
1016 rect = region->rects[i];
1017 (*rectangles)[i].x = rect.x1;
1018 (*rectangles)[i].y = rect.y1;
1019 (*rectangles)[i].width = rect.x2 - rect.x1;
1020 (*rectangles)[i].height = rect.y2 - rect.y1;
1039 if (rect->width <= 0 || rect->height <= 0)
return;
1041 tmp_region.rects = &tmp_region.extents;
1042 tmp_region.numRects = 1;
1043 tmp_region.extents.x1 = rect->x;
1044 tmp_region.extents.y1 = rect->y;
1045 tmp_region.extents.x2 = rect->x + rect->width;
1046 tmp_region.extents.y2 = rect->y + rect->height;
1047 tmp_region.size = 1;
1049 gdk_region_union(region, &tmp_region);
1070 if (pReg->numRects == 0) {
1071 pReg->extents.x1 = 0;
1072 pReg->extents.y1 = 0;
1073 pReg->extents.x2 = 0;
1074 pReg->extents.y2 = 0;
1078 pExtents = &pReg->extents;
1080 pBoxEnd = &pBox[pReg->numRects - 1];
1089 pExtents->x1 = pBox->x1;
1090 pExtents->y1 = pBox->y1;
1091 pExtents->x2 = pBoxEnd->x2;
1092 pExtents->y2 = pBoxEnd->y2;
1095 while (pBox <= pBoxEnd) {
1096 if (pBox->x1 < pExtents->x1) {
1097 pExtents->x1 = pBox->x1;
1099 if (pBox->x2 > pExtents->x2) {
1100 pExtents->x2 = pBox->x2;
1113 void gdk_region_destroy(
OGdkRegion *region) {
1116 if (region->rects != ®ion->extents) free(region->rects);
1128 void gdk_region_offset(
OGdkRegion *region,
int x,
int y) {
1134 pbox = region->rects;
1135 nbox = region->numRects;
1144 if (region->rects != ®ion->extents) {
1145 region->extents.x1 += x;
1146 region->extents.x2 += x;
1147 region->extents.y1 += y;
1148 region->extents.y2 += y;
1172 #define ZOpRegion(a, b) \
1174 gdk_region_union(a, b); \
1176 gdk_region_intersect(a, b)
1177 #define ZShiftRegion(a, b) \
1179 gdk_region_offset(a, b, 0); \
1181 gdk_region_offset(a, 0, b)
1184 unsigned int dx,
int xdir,
int grow) {
1185 unsigned int shift = 1;
1190 ZShiftRegion(r, -(
int)shift);
1196 ZShiftRegion(s, -(
int)shift);
1215 void gdk_region_shrink(
OGdkRegion *region,
int dx,
int dy) {
1221 if (!dx && !dy)
return;
1223 s = gdk_region_new();
1224 t = gdk_region_new();
1228 if (dx) Compress(region, s, t, (
unsigned)2 * dx, TRUE, grow);
1232 if (dy) Compress(region, s, t, (
unsigned)2 * dy, FALSE, grow);
1234 gdk_region_offset(region, dx, dy);
1235 gdk_region_destroy(s);
1236 gdk_region_destroy(t);
1263 pNextRect = &pReg->rects[pReg->numRects];
1265 while ((r1 != r1End) && (r2 != r2End)) {
1266 x1 = MAX(r1->x1, r2->x1);
1267 x2 = MIN(r1->x2, r2->x2);
1279 OMEMCHECK(pReg, pNextRect, pReg->rects);
1284 pReg->numRects += 1;
1294 if (r1->x2 < r2->x2) {
1296 }
else if (r2->x2 < r1->x2) {
1319 if ((!(source1->numRects)) || (!(source2->numRects)) ||
1320 (!EXTENTCHECK(&source1->extents, &source2->extents)))
1321 source1->numRects = 0;
1323 miRegionOp(source1, source1, source2, miIntersectO, (nonOverlapFunc)NULL,
1324 (nonOverlapFunc)NULL);
1332 miSetExtents(source1);
1338 if (dstrgn->size < rgn->numRects) {
1339 if (dstrgn->rects != &dstrgn->extents) free(dstrgn->rects);
1343 dstrgn->size = rgn->numRects;
1346 dstrgn->numRects = rgn->numRects;
1347 dstrgn->extents = rgn->extents;
1349 memcpy(dstrgn->rects, rgn->rects, rgn->numRects *
sizeof(
OGdkRegionBox));
1388 pRegEnd = &pReg->rects[pReg->numRects];
1390 pPrevBox = &pReg->rects[prevStart];
1391 prevNumRects = curStart - prevStart;
1398 pCurBox = &pReg->rects[curStart];
1399 bandY1 = pCurBox->y1;
1400 for (curNumRects = 0; (pCurBox != pRegEnd) && (pCurBox->y1 == bandY1);
1405 if (pCurBox != pRegEnd) {
1413 while (pRegEnd[-1].y1 == pRegEnd->y1) {
1416 curStart = pRegEnd - pReg->rects;
1417 pRegEnd = pReg->rects + pReg->numRects;
1420 if ((curNumRects == prevNumRects) && (curNumRects != 0)) {
1421 pCurBox -= curNumRects;
1426 if (pPrevBox->y2 == pCurBox->y1) {
1434 if ((pPrevBox->x1 != pCurBox->x1) || (pPrevBox->x2 != pCurBox->x2)) {
1443 }
while (prevNumRects != 0);
1445 pReg->numRects -= curNumRects;
1446 pCurBox -= curNumRects;
1447 pPrevBox -= curNumRects;
1455 pPrevBox->y2 = pCurBox->y2;
1459 }
while (curNumRects != 0);
1471 if (pCurBox == pRegEnd) {
1472 curStart = prevStart;
1475 *pPrevBox++ = *pCurBox++;
1476 }
while (pCurBox != pRegEnd);
1510 static void miRegionOp(
1512 overlapFunc overlapFn,
1514 nonOverlapFunc nonOverlap1Fn,
1517 nonOverlapFunc nonOverlap2Fn)
1548 r1End = r1 + reg1->numRects;
1549 r2End = r2 + reg2->numRects;
1551 oldRects = newReg->rects;
1553 EMPTY_REGION(newReg);
1562 newReg->size = MAX(reg1->numRects, reg2->numRects) * 2;
1578 if (reg1->extents.y1 < reg2->extents.y1)
1579 ybot = reg1->extents.y1;
1581 ybot = reg2->extents.y1;
1595 curBand = newReg->numRects;
1605 while ((r1BandEnd != r1End) && (r1BandEnd->y1 == r1->y1)) {
1610 while ((r2BandEnd != r2End) && (r2BandEnd->y1 == r2->y1)) {
1622 if (r1->y1 < r2->y1) {
1623 top = MAX(r1->y1, ybot);
1624 bot = MIN(r1->y2, r2->y1);
1629 (*nonOverlap1Fn)(newReg, r1, r1BandEnd, top, bot);
1633 }
else if (r2->y1 < r1->y1) {
1634 top = MAX(r2->y1, ybot);
1635 bot = MIN(r2->y2, r1->y1);
1640 (*nonOverlap2Fn)(newReg, r2, r2BandEnd, top, bot);
1654 if (newReg->numRects != curBand) {
1655 prevBand = miCoalesce(newReg, prevBand, curBand);
1662 ybot = MIN(r1->y2, r2->y2);
1663 curBand = newReg->numRects;
1665 (*overlapFn)(newReg, r1, r1BandEnd, r2, r2BandEnd, ytop, ybot);
1668 if (newReg->numRects != curBand) {
1669 prevBand = miCoalesce(newReg, prevBand, curBand);
1676 if (r1->y2 == ybot) {
1679 if (r2->y2 == ybot) {
1682 }
while ((r1 != r1End) && (r2 != r2End));
1687 curBand = newReg->numRects;
1689 if (nonOverlap1Fn != (nonOverlapFunc)NULL) {
1692 while ((r1BandEnd < r1End) && (r1BandEnd->y1 == r1->y1)) {
1695 (*nonOverlap1Fn)(newReg, r1, r1BandEnd, MAX(r1->y1, ybot), r1->y2);
1697 }
while (r1 != r1End);
1699 }
else if ((r2 != r2End) && (nonOverlap2Fn != (nonOverlapFunc)NULL)) {
1702 while ((r2BandEnd < r2End) && (r2BandEnd->y1 == r2->y1)) {
1705 (*nonOverlap2Fn)(newReg, r2, r2BandEnd, MAX(r2->y1, ybot), r2->y2);
1707 }
while (r2 != r2End);
1710 if (newReg->numRects != curBand) {
1711 (void)miCoalesce(newReg, prevBand, curBand);
1722 if (newReg->numRects < (newReg->size >> 1)) {
1723 if (REGION_NOT_EMPTY(newReg)) {
1724 newReg->size = newReg->numRects;
1735 free(newReg->rects);
1736 newReg->rects = &newReg->extents;
1740 if (oldRects != &newReg->extents) free(oldRects);
1767 pNextRect = &pReg->rects[pReg->numRects];
1773 OMEMCHECK(pReg, pNextRect, pReg->rects);
1774 pNextRect->x1 = r->x1;
1776 pNextRect->x2 = r->x2;
1778 pReg->numRects += 1;
1807 pNextRect = &pReg->rects[pReg->numRects];
1809 #define MERGERECT(r) \
1810 if ((pReg->numRects != 0) && (pNextRect[-1].y1 == y1) && \
1811 (pNextRect[-1].y2 == y2) && (pNextRect[-1].x2 >= r->x1)) { \
1812 if (pNextRect[-1].x2 < r->x2) { \
1813 pNextRect[-1].x2 = r->x2; \
1817 OMEMCHECK(pReg, pNextRect, pReg->rects); \
1818 pNextRect->y1 = y1; \
1819 pNextRect->y2 = y2; \
1820 pNextRect->x1 = r->x1; \
1821 pNextRect->x2 = r->x2; \
1822 pReg->numRects += 1; \
1829 while ((r1 != r1End) && (r2 != r2End)) {
1830 if (r1->x1 < r2->x1) {
1840 }
while (r1 != r1End);
1842 while (r2 != r2End) {
1865 if ((source1 == source2) || (!(source2->numRects)))
return;
1870 if (!(source1->numRects)) {
1871 miRegionCopy(source1, source2);
1878 if ((source1->numRects == 1) &&
1879 (source1->extents.x1 <= source2->extents.x1) &&
1880 (source1->extents.y1 <= source2->extents.y1) &&
1881 (source1->extents.x2 >= source2->extents.x2) &&
1882 (source1->extents.y2 >= source2->extents.y2))
1888 if ((source2->numRects == 1) &&
1889 (source2->extents.x1 <= source1->extents.x1) &&
1890 (source2->extents.y1 <= source1->extents.y1) &&
1891 (source2->extents.x2 >= source1->extents.x2) &&
1892 (source2->extents.y2 >= source1->extents.y2)) {
1893 miRegionCopy(source1, source2);
1897 miRegionOp(source1, source1, source2, miUnionO, miUnionNonO, miUnionNonO);
1899 source1->extents.x1 = MIN(source1->extents.x1, source2->extents.x1);
1900 source1->extents.y1 = MIN(source1->extents.y1, source2->extents.y1);
1901 source1->extents.x2 = MAX(source1->extents.x2, source2->extents.x2);
1902 source1->extents.y2 = MAX(source1->extents.y2, source2->extents.y2);
1928 pNextRect = &pReg->rects[pReg->numRects];
1934 OMEMCHECK(pReg, pNextRect, pReg->rects);
1935 pNextRect->x1 = r->x1;
1937 pNextRect->x2 = r->x2;
1939 pReg->numRects += 1;
1972 pNextRect = &pReg->rects[pReg->numRects];
1974 while ((r1 != r1End) && (r2 != r2End)) {
1980 }
else if (r2->x1 <= x1) {
1991 if (r1 != r1End) x1 = r1->x1;
1999 }
else if (r2->x1 < r1->x2) {
2005 OMEMCHECK(pReg, pNextRect, pReg->rects);
2008 pNextRect->x2 = r2->x1;
2010 pReg->numRects += 1;
2021 if (r1 != r1End) x1 = r1->x1;
2033 OMEMCHECK(pReg, pNextRect, pReg->rects);
2036 pNextRect->x2 = r1->x2;
2038 pReg->numRects += 1;
2043 if (r1 != r1End) x1 = r1->x1;
2050 while (r1 != r1End) {
2052 OMEMCHECK(pReg, pNextRect, pReg->rects);
2055 pNextRect->x2 = r1->x2;
2057 pReg->numRects += 1;
2082 if ((!(source1->numRects)) || (!(source2->numRects)) ||
2083 (!EXTENTCHECK(&source1->extents, &source2->extents)))
2086 miRegionOp(source1, source1, source2, miSubtractO, miSubtractNonO1,
2087 (nonOverlapFunc)NULL);
2095 miSetExtents(source1);
2113 trb = gdk_region_copy(source2);
2115 gdk_region_subtract(trb, source1);
2116 gdk_region_subtract(source1, source2);
2118 gdk_region_union(source1, trb);
2120 gdk_region_destroy(trb);
2131 bool gdk_region_empty(
const OGdkRegion *region) {
2134 if (region->numRects == 0)
2155 if (region1->numRects != region2->numRects)
return FALSE;
2156 if (region1->numRects == 0)
return TRUE;
2157 if (region1->extents.x1 != region2->extents.x1)
return FALSE;
2158 if (region1->extents.x2 != region2->extents.x2)
return FALSE;
2159 if (region1->extents.y1 != region2->extents.y1)
return FALSE;
2160 if (region1->extents.y2 != region2->extents.y2)
return FALSE;
2161 for (i = 0; i < region1->numRects; i++) {
2162 if (region1->rects[i].x1 != region2->rects[i].x1)
return FALSE;
2163 if (region1->rects[i].x2 != region2->rects[i].x2)
return FALSE;
2164 if (region1->rects[i].y1 != region2->rects[i].y1)
return FALSE;
2165 if (region1->rects[i].y2 != region2->rects[i].y2)
return FALSE;
2180 bool gdk_region_point_in(
const OGdkRegion *region,
int x,
int y) {
2185 if (region->numRects == 0)
return FALSE;
2186 if (!INBOX(region->extents, x, y))
return FALSE;
2187 for (i = 0; i < region->numRects; i++) {
2188 if (INBOX(region->rects[i], x, y))
return TRUE;
2204 OGdkOverlapType gdk_region_rect_in(
const OGdkRegion *region,
2210 bool partIn, partOut;
2222 prect->x2 = rx + rectangle->width;
2223 prect->y2 = ry + rectangle->height;
2226 if ((region->numRects == 0) || !EXTENTCHECK(®ion->extents, prect))
2227 return OGDK_OVERLAP_RECTANGLE_OUT;
2233 for (pbox = region->rects, pboxEnd = pbox + region->numRects; pbox < pboxEnd;
2238 if (pbox->y1 > ry) {
2240 if (partIn || (pbox->y1 >= prect->y2))
break;
2244 if (pbox->x2 <= rx)
continue;
2246 if (pbox->x1 > rx) {
2251 if (pbox->x1 < prect->x2) {
2256 if (pbox->x2 >= prect->x2) {
2258 if (ry >= prect->y2)
break;
2272 return (partIn ? ((ry < prect->y2) ? OGDK_OVERLAP_RECTANGLE_PART
2273 : OGDK_OVERLAP_RECTANGLE_IN)
2274 : OGDK_OVERLAP_RECTANGLE_OUT);
2279 gdk_region_unsorted_spans_intersect_foreach (GdkRegion *region,
2280 const GdkSpan *spans,
2282 GdkSpanFunc
function,
2285 gint i, left, right, y;
2286 gint clipped_left, clipped_right;
2288 GdkRegionBox *pboxEnd;
2290 if (!region->numRects)
2293 for (i=0;i<n_spans;i++)
2297 right = left + spans[i].width;
2299 if (! ((region->extents.y1 <= y) &&
2300 (region->extents.y2 > y) &&
2301 (region->extents.x1 < right) &&
2302 (region->extents.x2 > left)) )
2306 for (pbox = region->rects, pboxEnd = pbox + region->numRects;
2316 if ((right > pbox->x1) && (left < pbox->x2))
2320 clipped_left = MAX (left, pbox->x1);
2321 clipped_right = MIN (right, pbox->x2);
2324 out_span.x = clipped_left;
2325 out_span.width = clipped_right - clipped_left;
2326 (*function) (&out_span, data);
2346 gdk_region_spans_intersect_foreach (GdkRegion *region,
2347 const GdkSpan *spans,
2350 GdkSpanFunc
function,
2353 gint left, right, y;
2354 gint clipped_left, clipped_right;
2356 GdkRegionBox *pboxEnd;
2357 const GdkSpan *span, *tmpspan;
2358 const GdkSpan *end_span;
2360 g_return_if_fail (region != NULL);
2361 g_return_if_fail (spans != NULL);
2365 gdk_region_unsorted_spans_intersect_foreach (region,
2373 if ((!region->numRects) || (n_spans == 0))
2383 end_span = spans + n_spans;
2384 pbox = region->rects;
2385 pboxEnd = pbox + region->numRects;
2386 while (pbox < pboxEnd)
2388 while ((pbox->y2 < span->y) || (span->y < pbox->y1))
2391 if (pbox->y2 < span->y)
2394 if (pbox == pboxEnd)
2398 if (span->y < pbox->y1)
2401 if (span == end_span)
2408 while ((tmpspan < end_span) &&
2409 (tmpspan->y < pbox->y2))
2413 right = left + tmpspan->width;
2415 if ((right > pbox->x1) && (left < pbox->x2))
2419 clipped_left = MAX (left, pbox->x1);
2420 clipped_right = MIN (right, pbox->x2);
2423 out_span.x = clipped_left;
2424 out_span.width = clipped_right - clipped_left;
2425 (*function) (&out_span, data);
2484 #define LARGE_COORDINATE 1000000
2485 #define SMALL_COORDINATE -LARGE_COORDINATE
2511 pPrevSLL = &ET->scanlines;
2512 pSLL = pPrevSLL->next;
2513 while (pSLL && (pSLL->scanline < scanline)) {
2521 if ((!pSLL) || (pSLL->scanline > scanline)) {
2522 if (*iSLLBlock > SLLSPERBLOCK - 1) {
2524 (*SLLBlock)->next = tmpSLLBlock;
2526 *SLLBlock = tmpSLLBlock;
2529 pSLL = &((*SLLBlock)->SLLs[(*iSLLBlock)++]);
2531 pSLL->next = pPrevSLL->next;
2533 pPrevSLL->next = pSLL;
2535 pSLL->scanline = scanline;
2541 start = pSLL->edgelist;
2542 while (start && (start->bres.minor_axis < ETE->bres.minor_axis)) {
2544 start = start->next;
2551 pSLL->edgelist = ETE;
2587 if (count < 2)
return;
2595 AET->bres.minor_axis = SMALL_COORDINATE;
2601 ET->ymax = SMALL_COORDINATE;
2602 ET->ymin = LARGE_COORDINATE;
2605 PrevPt = &pts[count - 1];
2618 if (PrevPt->y > CurrPt->y) {
2619 bottom = PrevPt, top = CurrPt;
2620 pETEs->ClockWise = 0;
2622 bottom = CurrPt, top = PrevPt;
2623 pETEs->ClockWise = 1;
2629 if (bottom->y != top->y) {
2630 pETEs->ymax = bottom->y - 1;
2635 dy = bottom->y - top->y;
2636 OBRESINITPGONSTRUCT(dy, top->x, bottom->x, pETEs->bres);
2638 InsertEdgeInET(ET, pETEs, top->y, &pSLLBlock, &iSLLBlock);
2640 if (PrevPt->y > ET->ymax) ET->ymax = PrevPt->y;
2641 if (PrevPt->y < ET->ymin) ET->ymin = PrevPt->y;
2665 while (AET && (AET->bres.minor_axis < ETEs->bres.minor_axis)) {
2671 if (AET) AET->back = ETEs;
2672 ETEs->back = pPrevAET;
2673 pPrevAET->next = ETEs;
2714 if ((!inside && !isInside) || (inside && isInside)) {
2715 pWETE->nextWETE = AET;
2743 while (pETEchase->back->bres.minor_axis > AET->bres.minor_axis)
2744 pETEchase = pETEchase->back;
2747 if (pETEchase != pETEinsert) {
2748 pETEchaseBackTMP = pETEchase->back;
2749 pETEinsert->back->next = AET;
2750 if (AET) AET->back = pETEinsert->back;
2751 pETEinsert->next = pETEchase;
2752 pETEchase->back->next = pETEinsert;
2753 pETEchase->back = pETEinsert;
2754 pETEinsert->back = pETEchaseBackTMP;
2768 tmpSLLBlock = pSLLBlock->next;
2770 pSLLBlock = tmpSLLBlock;
2782 static int PtsToRegion(
int numFullPtBlocks,
int iCurPtBlock,
2791 extents = ®->extents;
2793 numRects = ((numFullPtBlocks * NUMPTSTOBUFFER) + iCurPtBlock) >> 1;
2795 OGROWREGION(reg, numRects);
2797 CurPtBlock = FirstPtBlock;
2798 rects = reg->rects - 1;
2800 extents->x1 = 1000000 , extents->x2 = -1000000 ;
2802 for (; numFullPtBlocks >= 0; numFullPtBlocks--) {
2804 i = NUMPTSTOBUFFER >> 1;
2805 if (!numFullPtBlocks) i = iCurPtBlock >> 1;
2806 for (pts = CurPtBlock->pts; i--; pts += 2) {
2807 if (pts->x == pts[1].x)
continue;
2808 if (numRects && pts->x == rects->x1 && pts->y == rects->y2 &&
2809 pts[1].x == rects->x2 &&
2810 (numRects == 1 || rects[-1].y1 != rects->y1) &&
2811 (i && pts[2].y > pts[1].y)) {
2812 rects->y2 = pts[1].y + 1;
2819 rects->x2 = pts[1].x;
2820 rects->y2 = pts[1].y + 1;
2821 if (rects->x1 < extents->x1) extents->x1 = rects->x1;
2822 if (rects->x2 > extents->x2) extents->x2 = rects->x2;
2824 CurPtBlock = CurPtBlock->next;
2828 extents->y1 = reg->rects->y1;
2829 extents->y2 = rects->y2;
2836 reg->numRects = numRects;
2854 OGdkFillRule fill_rule) {
2867 int fixWAET = FALSE;
2870 int numFullPtBlocks = 0;
2872 region = gdk_region_new();
2875 if (((n_points == 4) || ((n_points == 5) && (points[4].x == points[0].x) &&
2876 (points[4].y == points[0].y))) &&
2877 (((points[0].y == points[1].y) && (points[1].x == points[2].x) &&
2878 (points[2].y == points[3].y) && (points[3].x == points[0].x)) ||
2879 ((points[0].x == points[1].x) && (points[1].y == points[2].y) &&
2880 (points[2].x == points[3].x) && (points[3].y == points[0].y)))) {
2881 region->extents.x1 = MIN(points[0].x, points[2].x);
2882 region->extents.y1 = MIN(points[0].y, points[2].y);
2883 region->extents.x2 = MAX(points[0].x, points[2].x);
2884 region->extents.y2 = MAX(points[0].y, points[2].y);
2885 if ((region->extents.x1 != region->extents.x2) &&
2886 (region->extents.y1 != region->extents.y2)) {
2887 region->numRects = 1;
2888 *(region->rects) = region->extents;
2895 pts = FirstPtBlock.pts;
2896 CreateETandAET(n_points, points, &ET, &AET, pETEs, &SLLBlock);
2897 pSLL = ET.scanlines.next;
2898 curPtBlock = &FirstPtBlock;
2900 if (fill_rule == OGDK_EVEN_ODD_RULE) {
2904 for (y = ET.ymin; y < ET.ymax; y++) {
2909 if (pSLL != NULL && y == pSLL->scanline) {
2910 loadAET(&AET, pSLL->edgelist);
2920 pts->x = pAET->bres.minor_axis, pts->y = y;
2926 if (iPts == NUMPTSTOBUFFER) {
2928 tmpPtBlock->next = NULL;
2929 curPtBlock->next = tmpPtBlock;
2930 curPtBlock = tmpPtBlock;
2931 pts = curPtBlock->pts;
2935 OEVALUATEEDGEEVENODD(pAET, pPrevAET, y);
2937 (void)InsertionSort(&AET);
2943 for (y = ET.ymin; y < ET.ymax; y++) {
2948 if (pSLL != NULL && y == pSLL->scanline) {
2949 loadAET(&AET, pSLL->edgelist);
2965 if (pWETE == pAET) {
2966 pts->x = pAET->bres.minor_axis, pts->y = y;
2972 if (iPts == NUMPTSTOBUFFER) {
2974 tmpPtBlock->next = NULL;
2975 curPtBlock->next = tmpPtBlock;
2976 curPtBlock = tmpPtBlock;
2977 pts = curPtBlock->pts;
2981 pWETE = pWETE->nextWETE;
2983 OEVALUATEEDGEWINDING(pAET, pPrevAET, y, fixWAET);
2990 if (InsertionSort(&AET) || fixWAET) {
2996 FreeStorage(SLLBlock.next);
2997 (void)PtsToRegion(numFullPtBlocks, iPts, &FirstPtBlock, region);
2998 for (curPtBlock = FirstPtBlock.next; --numFullPtBlocks >= 0;) {
2999 tmpPtBlock = curPtBlock->next;
3001 curPtBlock = tmpPtBlock;