#include "tkQTree.h"
#include "tkAlloc.h"
#if !(__STDC_VERSION__ >= 199901L || (defined(_MSC_VER) && _MSC_VER >= 1900))
# define _TK_NEED_IMPLEMENTATION
# include "tkQTreePriv.h"
#endif
#include <tcl.h>
#include <string.h>
#include <assert.h>
#if TK_CHECK_ALLOCS
# define DEBUG_ALLOC(expr) expr
#else
# define DEBUG_ALLOC(expr)
#endif
DEBUG_ALLOC(unsigned tkQTreeCountNewTree = 0);
DEBUG_ALLOC(unsigned tkQTreeCountDestroyTree = 0);
DEBUG_ALLOC(unsigned tkQTreeCountNewNode = 0);
DEBUG_ALLOC(unsigned tkQTreeCountDestroyNode = 0);
DEBUG_ALLOC(unsigned tkQTreeCountNewItem = 0);
DEBUG_ALLOC(unsigned tkQTreeCountDestroyItem = 0);
DEBUG_ALLOC(unsigned tkQTreeCountNewElement = 0);
DEBUG_ALLOC(unsigned tkQTreeCountDestroyElement = 0);
enum { MaxNodeItems = 20 };
typedef struct Element {
struct Element *prev;
struct Element *next;
TkQTreeUid uid;
TkQTreeRect bbox;
TkQTreeState state;
uint32_t epoch;
} Element;
typedef struct Item {
struct Item *next;
Element *elem;
} Item;
typedef struct Node {
Item *spanningItem;
int countSpanning;
Item *partialItem;
int countPartial;
struct Node *ne;
struct Node *nw;
struct Node *se;
struct Node *sw;
} Node;
struct TkQTree {
Node *root;
Element *elem;
TkQTreeRect bbox;
uint32_t epoch;
};
static void InsertElem(const TkQTreeRect *bbox, Node *node, Element *elem);
static Element *
NewElement(
TkQTree tree,
const TkQTreeRect *rect,
const TkQTreeUid uid,
TkQTreeState initialState)
{
Element *elem;
assert(tree);
assert(rect);
DEBUG_ALLOC(tkQTreeCountNewElement++);
elem = malloc(sizeof(Element));
elem->prev = NULL;
if ((elem->next = tree->elem)) {
elem->next->prev = elem;
}
tree->elem = elem;
elem->bbox = *rect;
elem->uid = uid;
elem->state = initialState;
elem->epoch = 0;
return elem;
}
static Node *
NewNode(int initialPartialCount)
{
Node *n;
DEBUG_ALLOC(tkQTreeCountNewNode++);
n = memset(malloc(sizeof(Node)), 0, sizeof(Node));
n->countPartial = initialPartialCount;
return n;
}
static void
FreeItems(
Item *item)
{
while (item) {
Item *next = item->next;
free(item);
item = next;
DEBUG_ALLOC(tkQTreeCountDestroyItem++);
}
}
static void
FreeNode(
Node *node)
{
if (node) {
if (node->countPartial >= 0) {
FreeItems(node->partialItem);
} else {
FreeNode(node->ne);
FreeNode(node->nw);
FreeNode(node->se);
FreeNode(node->sw);
}
FreeItems(node->spanningItem);
free(node);
DEBUG_ALLOC(tkQTreeCountDestroyNode++);
}
}
static void
FreeElements(
Element *elem)
{
while (elem) {
Element *next = elem->next;
free(elem);
elem = next;
DEBUG_ALLOC(tkQTreeCountDestroyElement++);
}
}
static void
AddItem(
Item **itemPtr,
Element *elem)
{
Item *newItem;
assert(itemPtr);
assert(elem);
DEBUG_ALLOC(tkQTreeCountNewItem++);
newItem = malloc(sizeof(Item));
newItem->elem = elem;
newItem->next = *itemPtr;
*itemPtr = newItem;
}
static Node *
FillQuarter(
const TkQTreeRect *bbox,
const Item *partialItem,
Element *newElem)
{
Node *node;
assert(bbox);
assert(newElem);
assert(!TkQTreeRectIsEmpty(&newElem->bbox));
if (TkQTreeRectIsEmpty(bbox)) {
return NULL;
}
node = NULL;
for ( ; partialItem; partialItem = partialItem->next) {
if (TkQTreeRectIntersects(&partialItem->elem->bbox, bbox)) {
if (!node) { node = NewNode(0); }
if (TkQTreeRectContainsRect(&partialItem->elem->bbox, bbox)) {
AddItem(&node->spanningItem, partialItem->elem);
node->countSpanning += 1;
} else {
AddItem(&node->partialItem, partialItem->elem);
node->countPartial += 1;
}
}
}
if (TkQTreeRectIntersects(&newElem->bbox, bbox)) {
if (!node) { node = NewNode(0); }
if (TkQTreeRectContainsRect(&newElem->bbox, bbox)) {
AddItem(&node->spanningItem, newElem);
node->countSpanning += 1;
} else {
InsertElem(bbox, node, newElem);
}
}
return node;
}
static void
Split(
const TkQTreeRect *bbox,
Node *node,
Element *elem)
{
TkQTreeCoord xmin, ymin, xmax, ymax;
TkQTreeCoord xh, yh;
TkQTreeRect quart;
assert(node);
assert(bbox);
assert(elem);
assert(node->countPartial == MaxNodeItems);
assert(!TkQTreeRectIsEmpty(bbox));
assert(!TkQTreeRectIsEmpty(&elem->bbox));
assert(!TkQTreeRectContainsRect(&elem->bbox, bbox));
xmin = bbox->xmin;
ymin = bbox->ymin;
xmax = bbox->xmax;
ymax = bbox->ymax;
xh = (xmax - xmin)/2;
yh = (ymax - ymin)/2;
assert(xh > 0 || yh > 0);
TkQTreeRectSet(&quart, xmin, ymin, xmin + xh, ymin + yh);
node->ne = FillQuarter(&quart, node->partialItem, elem);
TkQTreeRectSet(&quart, xmin + xh, ymin, xmax, ymin + yh);
node->nw = FillQuarter(&quart, node->partialItem, elem);
TkQTreeRectSet(&quart, xmin, ymin + yh, xmin + xh, ymax);
node->se = FillQuarter(&quart, node->partialItem, elem);
TkQTreeRectSet(&quart, xmin + xh, ymin + yh, xmax, ymax);
node->sw = FillQuarter(&quart, node->partialItem, elem);
FreeItems(node->partialItem);
node->partialItem = NULL;
node->countPartial = -1;
}
static void
InsertElem(
const TkQTreeRect *bbox,
Node *node,
Element *elem)
{
assert(node);
assert(elem);
assert(bbox);
assert(!TkQTreeRectIsEmpty(bbox));
assert(!TkQTreeRectIsEmpty(&elem->bbox));
assert(!TkQTreeRectContainsRect(&elem->bbox, bbox));
if (node->countPartial == MaxNodeItems) {
Split(bbox, node, elem);
} else {
AddItem(&node->partialItem, elem);
node->countPartial += 1;
}
}
static void
InsertRect(
const TkQTreeRect *bbox,
Node *node,
Element *elem)
{
assert(node);
assert(bbox);
assert(elem);
assert(!TkQTreeRectIsEmpty(bbox));
assert(!TkQTreeRectIsEmpty(&elem->bbox));
if (TkQTreeRectContainsRect(&elem->bbox, bbox)) {
AddItem(&node->spanningItem, elem);
node->countSpanning += 1;
} else if (node->countPartial >= 0) {
InsertElem(bbox, node, elem);
} else {
TkQTreeRect quart;
TkQTreeCoord xmin = bbox->xmin;
TkQTreeCoord ymin = bbox->ymin;
TkQTreeCoord xmax = bbox->xmax;
TkQTreeCoord ymax = bbox->ymax;
TkQTreeCoord xh = (xmax - xmin)/2;
TkQTreeCoord yh = (ymax - ymin)/2;
TkQTreeRectSet(&quart, xmin, ymin, xmin + xh, ymin + yh);
if (!TkQTreeRectIsEmpty(&quart) && TkQTreeRectIntersects(&quart, &elem->bbox)) {
if (!node->ne) { node->ne = NewNode(-1); }
InsertRect(&quart, node->ne, elem);
}
TkQTreeRectSet(&quart, xmin + xh, ymin, xmax, ymin + yh);
if (!TkQTreeRectIsEmpty(&quart) && TkQTreeRectIntersects(&quart, &elem->bbox)) {
if (!node->nw) { node->nw = NewNode(-1); }
InsertRect(&quart, node->nw, elem);
}
TkQTreeRectSet(&quart, xmin, ymin + yh, xmin + xh, ymax);
if (!TkQTreeRectIsEmpty(&quart) && TkQTreeRectIntersects(&quart, &elem->bbox)) {
if (!node->se) { node->se = NewNode(-1); }
InsertRect(&quart, node->se, elem);
}
TkQTreeRectSet(&quart, xmin + xh, ymin + yh, xmax, ymax);
assert(!TkQTreeRectIsEmpty(&quart));
if (TkQTreeRectIntersects(&quart, &elem->bbox)) {
if (!node->sw) { node->sw = NewNode(-1); }
InsertRect(&quart, node->sw, elem);
}
}
}
static unsigned
CountItems(
const Item *item,
uint32_t epoch)
{
unsigned count = 0;
for ( ; item; item = item->next) {
if (item->elem->epoch != epoch) {
item->elem->epoch = epoch;
if (++count == MaxNodeItems + 1) {
return count;
}
}
}
return count;
}
static unsigned
CountPartialItems(
const Node *node,
uint32_t epoch)
{
unsigned count;
if (!node) {
count = 0;
} else if (node->countPartial == -1) {
count = MaxNodeItems + 1;
} else {
count = CountItems(node->partialItem, epoch);
}
return count;
}
static unsigned
CountSpanningItems(
const Node *node,
uint32_t epoch)
{
return node ? CountItems(node->spanningItem, epoch) : 0;
}
static void
MoveItems(
Item **srcPtr,
Node *dst,
uint32_t epoch)
{
Item *item;
Item *prevItem;
assert(srcPtr);
assert(dst);
item = *srcPtr;
if (!item) {
return;
}
prevItem = NULL;
while (item) {
Item *nextItem = item->next;
if (item->elem->epoch != epoch) {
if (prevItem) {
prevItem->next = item->next;
} else {
*srcPtr = item->next;
}
item->next = dst->partialItem;
dst->partialItem = item;
item->elem->epoch = epoch;
} else {
prevItem = item;
}
item = nextItem;
}
}
static void
TransferItems(
Node *src,
Node *dst,
uint32_t epoch)
{
if (!src) {
return;
}
assert(dst);
MoveItems(&src->partialItem, dst, epoch);
MoveItems(&src->spanningItem, dst, epoch);
FreeNode(src);
}
static void
RemoveItem(
Item **itemPtr,
int *count,
TkQTreeUid uid,
Element **elem)
{
Item *item, *prevItem;
assert(itemPtr);
assert(count);
for (item = *itemPtr, prevItem = NULL; item; prevItem = item, item = item->next) {
if (item->elem->uid == uid) {
*elem = item->elem;
if (prevItem) {
prevItem->next = item->next;
} else {
*itemPtr = item->next;
}
free(item);
*count -= 1;
DEBUG_ALLOC(tkQTreeCountDestroyItem++);
return;
}
}
}
static Element *
DeleteRect(
TkQTree tree,
const TkQTreeRect *bbox,
Node *node,
const TkQTreeRect *rect,
TkQTreeUid uid,
uint32_t *epoch)
{
Element *elem, *e;
assert(tree);
assert(rect);
assert(!TkQTreeRectIsEmpty(rect));
assert(epoch);
if (!node) {
return NULL;
}
elem = NULL;
RemoveItem(&node->spanningItem, &node->countSpanning, uid, &elem);
if (node->countPartial >= 0) {
RemoveItem(&node->partialItem, &node->countPartial, uid, &elem);
} else {
TkQTreeRect quart;
TkQTreeCoord xmin = bbox->xmin;
TkQTreeCoord ymin = bbox->ymin;
TkQTreeCoord xmax = bbox->xmax;
TkQTreeCoord ymax = bbox->ymax;
TkQTreeCoord xh = (xmax - xmin)/2;
TkQTreeCoord yh = (ymax - ymin)/2;
if (node->ne) {
TkQTreeRectSet(&quart, xmin, ymin, xmin + xh, ymin + yh);
if (TkQTreeRectIntersects(&quart, rect)) {
if ((e = DeleteRect(tree, &quart, node->ne, rect, uid, epoch))) {
elem = e;
if (node->ne->countPartial == 0 && node->ne->countSpanning == 0) {
FreeNode(node->ne);
node->ne = NULL;
}
}
}
}
if (node->nw) {
TkQTreeRectSet(&quart, xmin + xh, ymin, xmax, ymin + yh);
if (TkQTreeRectIntersects(&quart, rect)) {
if ((e = DeleteRect(tree, &quart, node->nw, rect, uid, epoch))) {
elem = e;
if (node->nw->countPartial == 0 && node->nw->countSpanning == 0) {
FreeNode(node->nw);
node->nw = NULL;
}
}
}
}
if (node->se) {
TkQTreeRectSet(&quart, xmin, ymin + yh, xmin + xh, ymax);
if (TkQTreeRectIntersects(&quart, rect)) {
if ((e = DeleteRect(tree, &quart, node->se, rect, uid, epoch))) {
elem = e;
if (node->se->countPartial == 0 && node->se->countSpanning == 0) {
FreeNode(node->se);
node->se = NULL;
}
}
}
}
if (node->sw) {
TkQTreeRectSet(&quart, xmin + xh, ymin + yh, xmax, ymax);
if (TkQTreeRectIntersects(&quart, rect)) {
if ((e = DeleteRect(tree, &quart, node->sw, rect, uid, epoch))) {
elem = e;
if (node->sw->countPartial == 0 && node->sw->countSpanning == 0) {
FreeNode(node->sw);
node->sw = NULL;
}
}
}
}
}
if (elem && node->countPartial == -1) {
unsigned total = 0;
*epoch += 1;
total += CountPartialItems(node->ne, *epoch);
total += CountPartialItems(node->nw, *epoch);
total += CountPartialItems(node->se, *epoch);
total += CountPartialItems(node->sw, *epoch);
if (total <= MaxNodeItems) {
total += CountSpanningItems(node->ne, *epoch);
total += CountSpanningItems(node->nw, *epoch);
total += CountSpanningItems(node->se, *epoch);
total += CountSpanningItems(node->sw, *epoch);
if (total <= MaxNodeItems) {
*epoch += 1;
TransferItems(node->ne, node, *epoch);
TransferItems(node->nw, node, *epoch);
TransferItems(node->se, node, *epoch);
TransferItems(node->sw, node, *epoch);
node->ne = node->nw = node->se = node->sw = NULL;
node->countPartial = total;
}
}
}
return elem;
}
static Element *
FindElem(
const TkQTreeRect *bbox,
const Node *node,
const TkQTreeRect *rect,
TkQTreeUid uid)
{
const Item *item;
assert(node);
assert(rect);
assert(!TkQTreeRectIsEmpty(rect));
if ((item = node->spanningItem)) {
for ( ; item; item = item->next) {
if (item->elem->uid == uid) {
return item->elem;
}
}
}
if (node->countPartial >= 0) {
for (item = node->partialItem; item; item = item->next) {
if (item->elem->uid == uid) {
return item->elem;
}
}
} else {
Element *elem;
TkQTreeRect quart;
TkQTreeCoord xmin = bbox->xmin;
TkQTreeCoord ymin = bbox->ymin;
TkQTreeCoord xmax = bbox->xmax;
TkQTreeCoord ymax = bbox->ymax;
TkQTreeCoord xh = (xmax - xmin)/2;
TkQTreeCoord yh = (ymax - ymin)/2;
if (node->ne) {
TkQTreeRectSet(&quart, xmin, ymin, xmin + xh, ymin + yh);
if (TkQTreeRectIntersects(&quart, rect)) {
if ((elem = FindElem(&quart, node->ne, rect, uid))) { return elem; }
}
}
if (node->nw) {
TkQTreeRectSet(&quart, xmin + xh, ymin, xmax, ymin + yh);
if (TkQTreeRectIntersects(&quart, rect)) {
if ((elem = FindElem(&quart, node->nw, rect, uid))) { return elem; }
}
}
if (node->se) {
TkQTreeRectSet(&quart, xmin, ymin + yh, xmin + xh, ymax);
if (TkQTreeRectIntersects(&quart, rect)) {
if ((elem = FindElem(&quart, node->se, rect, uid))) { return elem; }
}
}
if (node->sw) {
TkQTreeRectSet(&quart, xmin + xh, ymin + yh, xmax, ymax);
if (TkQTreeRectIntersects(&quart, rect)) {
if ((elem = FindElem(&quart, node->sw, rect, uid))) { return elem; }
}
}
}
return NULL;
}
static void
RemoveElem(
TkQTree tree,
Element *elem)
{
assert(tree);
assert(elem);
if (elem->prev) {
elem->prev->next = elem->next;
} else {
tree->elem = elem->next;
}
if (elem->next) {
elem->next->prev = elem->prev;
}
free(elem);
DEBUG_ALLOC(tkQTreeCountDestroyElement++);
}
void
TkQTreeTraverse(
TkQTree tree,
TkQTreeCallback cbHit,
TkQTreeClientData cbArg)
{
Element *elem;
assert(tree);
assert(cbHit);
for (elem = tree->elem; elem; elem = elem->next) {
if (!cbHit(elem->uid, &elem->bbox, &elem->state, cbArg)) {
return;
}
}
}
bool
TkQTreeFindState(
const TkQTree tree,
const TkQTreeRect *rect,
TkQTreeUid uid,
TkQTreeState *state)
{
const Element *elem;
assert(tree);
assert(rect);
if (!tree->elem
|| TkQTreeRectIsEmpty(rect)
|| !(elem = FindElem(&tree->bbox, tree->root, rect, uid))) {
return false;
}
if (state) {
*state = elem->state;
}
return true;
}
bool
TkQTreeSetState(
const TkQTree tree,
const TkQTreeRect *rect,
TkQTreeUid uid,
TkQTreeState state)
{
Element *elem;
assert(tree);
assert(rect);
if (!tree->elem
|| TkQTreeRectIsEmpty(rect)
|| !(elem = FindElem(&tree->bbox, tree->root, rect, uid))) {
return false;
}
elem->state = state;
return true;
}
unsigned
TkQTreeSearch(
const TkQTree tree,
TkQTreeCoord x,
TkQTreeCoord y,
TkQTreeCallback cbHit,
TkQTreeClientData cbArg)
{
const Node *node;
unsigned hitCount;
TkQTreeRect bbox;
assert(tree);
if (!tree->elem) {
return 0;
}
if (!TkQTreeRectContainsPoint(&tree->bbox, x, y)) {
return 0;
}
node = tree->root;
bbox = tree->bbox;
hitCount = 0;
while (node) {
const Item *item;
for (item = node->spanningItem; item; item = item->next) {
Element *elem = item->elem;
hitCount += 1;
if (cbHit && !cbHit(elem->uid, &elem->bbox, &elem->state, cbArg)) {
return hitCount;
}
}
if (node->countPartial >= 0) {
for (item = node->partialItem; item; item = item->next) {
if (TkQTreeRectContainsPoint(&item->elem->bbox, x, y)) {
Element *elem = item->elem;
hitCount += 1;
if (cbHit && !cbHit(elem->uid, &elem->bbox, &elem->state, cbArg)) {
return hitCount;
}
}
}
node = NULL;
} else {
TkQTreeCoord xh = (bbox.xmax - bbox.xmin)/2;
TkQTreeCoord yh = (bbox.ymax - bbox.ymin)/2;
if (y < yh + bbox.ymin) {
if (x < xh + bbox.xmin) {
node = node->ne;
bbox.xmax = bbox.xmin + xh;
bbox.ymax = bbox.ymin + yh;
} else {
node = node->nw;
bbox.xmin += xh;
bbox.ymax = bbox.ymin + yh;
}
} else {
if (x < xh + bbox.xmin) {
node = node->se;
bbox.xmax = bbox.xmin + xh;
bbox.ymin += yh;
} else {
node = node->sw;
bbox.xmin += xh;
bbox.ymin += yh;
}
}
}
}
return hitCount;
}
bool
TkQTreeInsertRect(
TkQTree tree,
const TkQTreeRect *rect,
TkQTreeUid uid,
TkQTreeState initialState)
{
assert(tree);
assert(rect);
if (TkQTreeRectIsEmpty(rect) || !TkQTreeRectIntersects(&tree->bbox, rect)) {
return false;
}
InsertRect(&tree->bbox, tree->root, NewElement(tree, rect, uid, initialState));
return true;
}
bool
TkQTreeDeleteRect(
TkQTree tree,
const TkQTreeRect *rect,
TkQTreeUid uid)
{
Element *elem;
assert(tree);
assert(rect);
if (TkQTreeRectIsEmpty(rect)) {
return false;
}
elem = DeleteRect(tree, &tree->bbox, tree->root, rect, uid, &tree->epoch);
if (!elem) {
return false;
}
RemoveElem(tree, elem);
return true;
}
bool
TkQTreeUpdateRect(
TkQTree tree,
const TkQTreeRect *oldRect,
const TkQTreeRect *newRect,
TkQTreeUid uid,
TkQTreeState newState)
{
Element *elem;
assert(tree);
assert(newRect);
if (oldRect && TkQTreeRectIsEqual(oldRect, newRect)) {
return true;
}
elem = NULL;
if (oldRect && !TkQTreeRectIsEmpty(oldRect) && TkQTreeRectIntersects(&tree->bbox, oldRect)) {
if ((elem = DeleteRect(tree, &tree->bbox, tree->root, oldRect, uid, &tree->epoch))) {
elem->state = newState;
elem->bbox = *newRect;
}
}
if (TkQTreeRectIsEmpty(newRect) || !TkQTreeRectIntersects(&tree->bbox, newRect)) {
return false;
}
InsertRect(&tree->bbox, tree->root, elem ? elem : NewElement(tree, newRect, uid, newState));
return true;
}
void
TkQTreeDestroy(
TkQTree *treePtr)
{
assert(treePtr);
if (*treePtr) {
FreeNode((*treePtr)->root);
FreeElements((*treePtr)->elem);
free(*treePtr);
DEBUG_ALLOC(tkQTreeCountDestroyTree++);
*treePtr = NULL;
}
}
bool
TkQTreeConfigure(
TkQTree *treePtr,
const TkQTreeRect *rect)
{
TkQTree tree;
Element *elem;
assert(treePtr);
assert(rect);
if (TkQTreeRectIsEmpty(rect)) {
TkQTreeDestroy(treePtr);
return false;
}
if ((tree = *treePtr)) {
if (TkQTreeRectIsEqual(&tree->bbox, rect)) {
return true;
}
FreeNode(tree->root);
} else {
DEBUG_ALLOC(tkQTreeCountNewTree++);
*treePtr = tree = malloc(sizeof(struct TkQTree));
tree->elem = NULL;
tree->epoch = 0;
}
tree->root = NewNode(0);
tree->bbox = *rect;
for (elem = tree->elem; elem; ) {
Element *next = elem->next;
if (TkQTreeRectIntersects(&elem->bbox, &tree->bbox)) {
InsertRect(&tree->bbox, tree->root, elem);
}
elem = next;
}
return true;
}
const TkQTreeRect *
TkQTreeGetBoundingBox(
const TkQTree tree)
{
assert(tree);
return &tree->bbox;
}
#if QTREE_SEARCH_RECTS_CONTAINING
typedef struct {
TkQTreeCallback cbHit;
TkQTreeClientData cbArg;
unsigned count;
unsigned epoch;
} MyClientData;
bool HitRectContaining1(
TkQTreeUid uid,
const TkQTreeRect *rect,
TkQTreeState *state,
TkQTreeClientData arg)
{
MyClientData *cd = (MyClientData *) arg;
*state = arg->epoch;
return true;
}
bool HitRectContaining2(
TkQTreeUid uid,
const TkQTreeRect *rect,
TkQTreeState *state,
TkQTreeClientData arg)
{
*state += 1;
return true;
}
bool HitRectContaining3(
TkQTreeUid uid,
const TkQTreeRect *rect,
TkQTreeState *state,
TkQTreeClientData arg)
{
MyClientData *cd = (MyClientData *) arg;
if (++*state == arg->epoch + 3) {
if (cd->cbHit) {
cd->cbHit(uid, rect, NULL, cd->cbArg);
}
cd->count += 1;
}
return true;
}
unsigned
TkQTreeSearchRectsContaining(
const TkQTree tree,
const TkQTreeRect *rect,
TkQTreeCallback cbHit,
TkQTreeClientData cbArg)
{
static unsigned epoch = 0;
const Node *node;
unsigned hitCount;
TkQTreeRect bbox;
MyClientData cd;
assert(tree);
if (!tree->elem) {
return 0;
}
if (!TkQTreeRectContainsRect(&tree->bbox, rect)) {
return 0;
}
cd.cbHit = cbHit;
cd.cbArg = cbArg;
cd.count = 0;
cd.epoch = (epoch += 4);
if (TkQTreeSearch(tree, rect->xmin, rect->ymin, HitRectContaining1, NULL) > 0) {
if (TkQTreeSearch(tree, rect->xmax, rect->ymin, HitRectContaining2, NULL) > 0) {
if (TkQTreeSearch(tree, rect->xmin, rect->ymax, HitRectContaining2, NULL) > 0) {
TkQTreeSearch(tree, rect->xmax, rect->ymax, HitRectContaining3, (TkQTreeClientData) cd);
}
}
}
return cd.count;
}
#endif
#if __STDC_VERSION__ >= 199901L || (defined(_MSC_VER) && _MSC_VER >= 1900)
#define inline extern
inline bool TkQTreeRectIsEmpty(const TkQTreeRect *rect);
inline bool TkQTreeRectIsEqual(const TkQTreeRect *rect1, const TkQTreeRect *rect2);
inline bool TkQTreeRectContainsPoint(const TkQTreeRect *rect, TkQTreeCoord x, TkQTreeCoord y);
inline bool TkQTreeRectContainsRect(const TkQTreeRect *rect1, const TkQTreeRect *rect2);
inline bool TkQTreeRectIntersects(const TkQTreeRect *rect1, const TkQTreeRect *rect2);
inline TkQTreeRect *TkQTreeRectSet(TkQTreeRect *rect,
TkQTreeCoord xmin, TkQTreeCoord ymin, TkQTreeCoord xmax, TkQTreeCoord ymax);
inline TkQTreeRect *TkQTreeRectTranslate(TkQTreeRect *rect, TkQTreeCoord dx, TkQTreeCoord dy);
#endif