#include "livecode/api/api.h" #include namespace Inkscape { namespace Livecode { extern "C" Janet geom_point_get(void *p, Janet key); extern "C" void geom_point_set(void *p, Janet key, Janet value); extern "C" void geom_point_tostring(void *p, JanetBuffer *buffer) { std::stringstream stream; stream << "(p) << ">"; janet_buffer_push_cstring(buffer, stream.str().c_str()); } const JanetAbstractType geom_point_type = { "geom/point", NULL, NULL, geom_point_get, geom_point_set, NULL, NULL, geom_point_tostring }; Janet janet_wrap_point(Geom::Point const &x) { Geom::Point *box = (Geom::Point *)janet_abstract(&geom_point_type, sizeof(Geom::Point)); *box = Geom::Point(x); return janet_wrap_abstract(box); } Janet janet_wrap_point(Geom::IntPoint const &x) { Geom::Point *box = (Geom::Point *)janet_abstract(&geom_point_type, sizeof(Geom::Point)); *box = Geom::Point(x); return janet_wrap_abstract(box); } Geom::Point &janet_unwrap_point(Janet x) { if (janet_checktype(x, JANET_ABSTRACT)) { void *abst = janet_unwrap_abstract(x); if (janet_abstract_type(abst) == &geom_point_type) return *(Geom::Point *)abst; } janet_panic("expected a geom/point"); } Geom::Point janet_unwrap_point_or_scalar(Janet x) { if (janet_checktype(x, JANET_ABSTRACT)) { void *abst = janet_unwrap_abstract(x); if (janet_abstract_type(abst) == &geom_point_type) return *(Geom::Point *)abst; } else if (janet_checktype(x, JANET_NUMBER)) { double val = janet_unwrap_number(x); return Geom::Point(val, val); } janet_panic("expected a geom/point"); } extern "C" Janet cfun_geom_point_new(int32_t argc, Janet *argv) { janet_arity(argc, 0, 2); double x = 0; double y = 0; if (argc == 2) { x = janet_getnumber(argv, 0); y = janet_getnumber(argv, 1); } else if (argc == 1) { x = janet_getnumber(argv, 0); y = x; } return janet_wrap_point(Geom::Point(x, y)); } const JanetReg it_cfuns[] = { { "geom/point", cfun_geom_point_new, "(geom/point x y)\n\nCreate a Point from x/y coordinate values." }, {NULL, NULL, NULL} }; static Janet cfun_geom_point_add(int32_t argc, Janet *argv) { janet_arity(argc, 2, -1); Geom::Point *box = (Geom::Point *)janet_abstract(&geom_point_type, sizeof(Geom::Point)); *box = janet_unwrap_point(argv[0]); for (int i = 1; i < argc; i++) *box += janet_unwrap_point(argv[i]); return janet_wrap_abstract(box); } static Janet cfun_geom_point_add_mut(int32_t argc, Janet *argv) { janet_arity(argc, 2, -1); Geom::Point *box = (Geom::Point *)janet_getabstract(argv, 0, &geom_point_type); for (int i = 1; i < argc; i++) *box += janet_unwrap_point(argv[i]); return janet_wrap_abstract(box); } static Janet cfun_geom_point_sub(int32_t argc, Janet *argv) { janet_arity(argc, 2, -1); Geom::Point *box = (Geom::Point *)janet_abstract(&geom_point_type, sizeof(Geom::Point)); *box = janet_unwrap_point(argv[0]); for (int i = 1; i < argc; i++) *box -= janet_unwrap_point(argv[i]); return janet_wrap_abstract(box); } static Janet cfun_geom_point_sub_mut(int32_t argc, Janet *argv) { janet_arity(argc, 2, -1); Geom::Point *box = (Geom::Point *)janet_getabstract(argv, 0, &geom_point_type); for (int i = 1; i < argc; i++) *box -= janet_unwrap_point(argv[i]); return janet_wrap_abstract(box); } static Janet cfun_geom_point_mul(int32_t argc, Janet *argv) { janet_arity(argc, 2, -1); Geom::Point *box = (Geom::Point *)janet_abstract(&geom_point_type, sizeof(Geom::Point)); *box = janet_unwrap_point(argv[0]); for (int i = 1; i < argc; i++) { Geom::Point arg = janet_unwrap_point_or_scalar(argv[i]); (*box)[0] *= arg[0]; (*box)[1] *= arg[1]; } return janet_wrap_abstract(box); } static Janet cfun_geom_point_mul_mut(int32_t argc, Janet *argv) { janet_arity(argc, 2, -1); Geom::Point *box = (Geom::Point *)janet_getabstract(argv, 0, &geom_point_type); for (int i = 1; i < argc; i++) { Geom::Point arg = janet_unwrap_point_or_scalar(argv[i]); (*box)[0] *= arg[0]; (*box)[1] *= arg[1]; } return janet_wrap_abstract(box); } static Janet cfun_geom_point_div(int32_t argc, Janet *argv) { janet_arity(argc, 2, -1); Geom::Point *box = (Geom::Point *)janet_abstract(&geom_point_type, sizeof(Geom::Point)); *box = janet_unwrap_point(argv[0]); for (int i = 1; i < argc; i++) { Geom::Point arg = janet_unwrap_point_or_scalar(argv[i]); (*box)[0] /= arg[0]; (*box)[1] /= arg[1]; } return janet_wrap_abstract(box); } static Janet cfun_geom_point_div_mut(int32_t argc, Janet *argv) { janet_arity(argc, 2, -1); Geom::Point *box = (Geom::Point *)janet_getabstract(argv, 0, &geom_point_type); for (int i = 1; i < argc; i++) { Geom::Point arg = janet_unwrap_point_or_scalar(argv[i]); (*box)[0] /= arg[0]; (*box)[1] /= arg[1]; } return janet_wrap_abstract(box); } static Janet cfun_geom_point_eq(int32_t argc, Janet *argv) { janet_fixarity(argc, 2); Geom::Point &v1 = janet_unwrap_point(argv[0]); Geom::Point &v2 = janet_unwrap_point(argv[1]); return janet_wrap_boolean(v1 == v2); } static Janet cfun_geom_point_lt(int32_t argc, Janet *argv) { janet_fixarity(argc, 2); Geom::Point &v1 = janet_unwrap_point(argv[0]); Geom::Point &v2 = janet_unwrap_point(argv[1]); return janet_wrap_boolean(v1 < v2); } #define CONSTMETHOD(name, method, type) \ static Janet cfun_geom_point_##name(int32_t argc, Janet *argv) { \ janet_fixarity(argc, 1); \ Geom::Point *box = (Geom::Point *)janet_getabstract(argv, 0, &geom_point_type); \ return janet_wrap_##type(box->method()); \ } CONSTMETHOD(is_zero, isZero, boolean) CONSTMETHOD(is_finite, isFinite, boolean) CONSTMETHOD(is_normalized, isNormalized, boolean) CONSTMETHOD(x, x, number) CONSTMETHOD(y, y, number) CONSTMETHOD(length, length, number) CONSTMETHOD(cw, cw, point) CONSTMETHOD(ccw, ccw, point) CONSTMETHOD(round, round, point) CONSTMETHOD(floor, floor, point) CONSTMETHOD(ceil, ceil, point) CONSTMETHOD(normalize, normalized, point) static Janet cfun_geom_point_normalize_mut(int32_t argc, Janet *argv) { janet_fixarity(argc, 1); Geom::Point *box = (Geom::Point *)janet_getabstract(argv, 0, &geom_point_type); box->normalize(); return janet_wrap_point(*box); } static JanetMethod geom_point_methods[] = { {"+", cfun_geom_point_add}, {"-", cfun_geom_point_sub}, {"*", cfun_geom_point_mul}, {"/", cfun_geom_point_div}, {"<", cfun_geom_point_lt}, {"==", cfun_geom_point_eq}, {"+!", cfun_geom_point_add_mut}, {"-!", cfun_geom_point_sub_mut}, {"*!", cfun_geom_point_mul_mut}, {"/!", cfun_geom_point_div_mut}, {"zero?", cfun_geom_point_is_zero}, {"finite?", cfun_geom_point_is_finite}, {"normalized?", cfun_geom_point_is_normalized}, {"x", cfun_geom_point_x}, {"y", cfun_geom_point_y}, {"length", cfun_geom_point_length}, {"cw", cfun_geom_point_cw}, {"ccw", cfun_geom_point_ccw}, {"round", cfun_geom_point_round}, {"floor", cfun_geom_point_floor}, {"ceil", cfun_geom_point_ceil}, {"normalize", cfun_geom_point_normalize}, {"normalize!", cfun_geom_point_normalize_mut}, {NULL, NULL} }; extern "C" Janet geom_point_get(void *p, Janet key) { Geom::Point *box = (Geom::Point *)p; if (janet_checktype(key, JANET_KEYWORD)) return janet_getmethod(janet_unwrap_keyword(key), geom_point_methods); if (!janet_checksize(key)) janet_panic("expected size as key"); size_t const index = (size_t) janet_unwrap_number(key); switch (index) { case 0: return janet_wrap_number((*box)[0]); case 1: return janet_wrap_number((*box)[1]); default: return janet_wrap_nil(); } } extern "C" void geom_point_set(void *p, Janet key, Janet value) { Geom::Point *box = (Geom::Point *)p; if (!janet_checksize(key)) janet_panic("expected size as key"); if (!janet_checktype(key, JANET_NUMBER)) janet_panic("expected number as value"); size_t const index = (size_t) janet_unwrap_number(key); switch (index) { case 0: (*box)[0] = janet_unwrap_number(value); break; case 1: (*box)[1] = janet_unwrap_number(value); break; default: janet_panic("index out of bounds"); } } void janet_lib_geom_point(JanetTable *env) { janet_cfuns(env, NULL, it_cfuns); janet_register_abstract_type(&geom_point_type); } } }