Files
cell-rtree/rtree.c
2025-12-05 19:37:57 -06:00

232 lines
5.0 KiB
C

#include "cell.h"
#include "src/rtree.h"
#include <stdlib.h>
#include <stdbool.h>
// External declarations
typedef struct rtree rtree;
typedef struct rect {
float x;
float y;
float w;
float h;
} rect;
static rect js2rect(JSContext *js, JSValue v)
{
rect r;
JSValue js_x = JS_GetPropertyStr(js, v, "x");
JSValue js_y = JS_GetPropertyStr(js, v, "y");
JSValue js_w = JS_GetPropertyStr(js, v, "w");
JSValue js_h = JS_GetPropertyStr(js, v, "h");
double x, y, w, h;
JS_ToFloat64(js, &x, js_x);
JS_ToFloat64(js, &y, js_y);
JS_ToFloat64(js, &w, js_w);
JS_ToFloat64(js, &h, js_h);
r.x = (float)x;
r.y = (float)y;
r.w = (float)w;
r.h = (float)h;
JS_FreeValue(js, js_x);
JS_FreeValue(js, js_y);
JS_FreeValue(js, js_w);
JS_FreeValue(js, js_h);
return r;
}
static JSValue rect2js(JSContext *js, rect r)
{
JSValue js_rect = JS_NewObject(js);
JS_SetPropertyStr(js, js_rect, "x", JS_NewFloat64(js, r.x));
JS_SetPropertyStr(js, js_rect, "y", JS_NewFloat64(js, r.y));
JS_SetPropertyStr(js, js_rect, "w", JS_NewFloat64(js, r.w));
JS_SetPropertyStr(js, js_rect, "h", JS_NewFloat64(js, r.h));
return js_rect;
}
void rtree_free(JSRuntime *rt, rtree *tree)
{
rtree_destroy(tree);
}
QJSCLASS(rtree,)
JSC_CCALL(rtree_add,
rtree *tree = js2rtree(js,self);
JSValue v = argv[0];
rect r = js2rect(js,v);
NUMTYPE min[3];
NUMTYPE max[3];
min[0] = r.x;
min[1] = r.y;
min[2] = 0;
max[0] = r.x+r.w;
max[1] = r.y+r.h;
max[2] = 0;
JSValue *ins = malloc(sizeof(*ins));
*ins = JS_DupValue(js,v);
if (!rtree_insert(tree, min, max, ins)) {
JS_FreeValue(js,*ins);
return JS_ThrowOutOfMemory(js);
}
)
static int rtree_cmp(const JSValue *a, const JSValue *b, JSContext *js)
{
int same = JS_SameValue(js, *a, *b);
if (same)
JS_FreeValue(js,*a);
return !same;
}
JSC_CCALL(rtree_delete,
rtree *tree = js2rtree(js,self);
JSValue v = argv[0];
rect r = js2rect(js,v);
NUMTYPE min[3];
NUMTYPE max[3];
min[0] = r.x;
min[1] = r.y;
min[2] = 0;
max[0] = r.x+r.w;
max[1] = r.y+r.h;
max[2] = 0;
if (!rtree_delete_with_comparator(tree, min, max, &v, rtree_cmp, js))
return JS_ThrowOutOfMemory(js);
)
struct rtree_iter_data {
JSContext *js;
JSValue arr;
int n;
};
static bool rtree_iter(const NUMTYPE *min, const NUMTYPE *max, const JSValue *data, struct rtree_iter_data *ctx)
{
JS_SetPropertyUint32(ctx->js,ctx->arr,ctx->n, JS_DupValue(ctx->js,*data));
ctx->n++;
return 1;
}
JSC_CCALL(rtree_query,
rtree *tree = js2rtree(js,self);
rect r = js2rect(js,argv[0]);
NUMTYPE min[3];
NUMTYPE max[3];
min[0] = r.x;
min[1] = r.y;
min[2] = 0;
max[0] = r.x+r.w;
max[1] = r.y+r.h;
max[2] = 0;
struct rtree_iter_data data = {0};
data.js = js;
data.arr = JS_NewArray(js);
data.n = 0;
rtree_search(tree, min, max, rtree_iter, &data);
ret = data.arr;
)
struct rtree_each
{
JSValue fn;
JSContext *js;
};
static int rtree_foreach(const NUMTYPE *min, const NUMTYPE *max, const JSValue *value, struct rtree_each *each)
{
JSValue ret = JS_Call(each->js, each->fn, JS_NULL, 0, NULL);
if (JS_HasException(each->js))
return 0;
return 1;
}
JSC_CCALL(rtree_forEach,
rtree *tree = js2rtree(js,self);
struct rtree_each each;
each.fn = JS_DupValue(js,argv[0]);
each.js = js;
rtree_scan(tree, rtree_foreach, &each);
JS_FreeValue(js,each.fn);
)
typedef struct {
JSContext *js;
JSValue v;
int has;
} rtree_has;
static int rtree_hasfn(const NUMTYPE *min, const NUMTYPE *max, const JSValue *value, rtree_has *has)
{
if (JS_SameValue(has->js, has->v, *value)) {
has->has = 1;
return 0;
}
return 1;
}
JSC_CCALL(rtree_has,
rtree *tree = js2rtree(js,self);
rtree_has has;
has.js = js;
has.v = JS_DupValue(js,argv[0]);
has.has = 0;
rtree_scan(tree, rtree_hasfn, &has);
JS_FreeValue(js,argv[0]);
return JS_NewBool(js,has.has);
)
JSValue js_rtree_get_size(JSContext *js, JSValue self, int magic)
{
rtree *tree = js2rtree(js,self);
return number2js(js,rtree_count(tree));
}
static int rtree_valuefn(const NUMTYPE *min, const NUMTYPE *max, const JSValue *value, struct rtree_iter_data *data)
{
JS_SetPropertyUint32(data->js, data->arr, data->n, JS_DupValue(data->js, *value));
data->n++;
return 1;
}
JSC_CCALL(rtree_values,
rtree *tree = js2rtree(js,self);
struct rtree_iter_data data = {0};
data.js = js;
data.arr = JS_NewArray(js);
data.n = 0;
rtree_scan(tree, rtree_valuefn, &data);
ret = data.arr;
)
// Constructor function for rtree
static JSValue js_rtree_constructor(JSContext *js, JSValueConst new_target, int argc, JSValueConst *argv) {
struct rtree *tree = rtree_new();
if (!tree) return JS_ThrowOutOfMemory(js);
return rtree2js(js,tree);
}
static const JSCFunctionListEntry js_rtree_funcs[] = {
MIST_FUNC_DEF(rtree, add, 1),
MIST_FUNC_DEF(rtree, delete, 1),
MIST_FUNC_DEF(rtree, query, 1),
JS_CGETSET_DEF("size", js_rtree_get_size,NULL),
MIST_FUNC_DEF(rtree, forEach, 1),
MIST_FUNC_DEF(rtree, has, 1),
MIST_FUNC_DEF(rtree,values,0),
};
CELL_USE_INIT(
return QJSCLASSPREP_FUNCS_CTOR(rtree, 0)
)