#include "cell.h" #include "src/rtree.h" #include #include // 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; JS_GETATOM(js,r,v,rect,rect) 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; JS_GETATOM(js,r,v,rect,rect) 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) )