203 lines
4.4 KiB
C
203 lines
4.4 KiB
C
#include "qjs_rtree.h"
|
|
#include "qjs_macros.h"
|
|
#include "jsffi.h"
|
|
#include "rtree.h"
|
|
#include "cell.h"
|
|
#include <stdlib.h>
|
|
#include <stdbool.h>
|
|
|
|
// External declarations
|
|
typedef struct rtree rtree;
|
|
|
|
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);
|
|
}
|
|
)
|
|
|
|
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;
|
|
};
|
|
|
|
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;
|
|
};
|
|
|
|
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_UNDEFINED, 0, NULL);
|
|
uncaught_exception(each->js, ret);
|
|
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;
|
|
|
|
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));
|
|
}
|
|
|
|
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),
|
|
};
|
|
|
|
JSValue js_rtree_use(JSContext *js) {
|
|
// Register the rtree class
|
|
QJSCLASSPREP_FUNCS(rtree);
|
|
|
|
// Create the constructor function
|
|
JSValue ctor = JS_NewCFunction2(js, js_rtree_constructor, "rtree", 0, JS_CFUNC_constructor, 0);
|
|
|
|
// Set the prototype on the constructor
|
|
JSValue proto = JS_GetClassProto(js, js_rtree_id);
|
|
JS_SetConstructor(js, ctor, proto);
|
|
JS_FreeValue(js, proto);
|
|
|
|
return ctor;
|
|
} |