#include "janet_2geom.h"
#include <sstream>
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 << "<2geom/point " << *static_cast<Geom::Point *>(p) << ">";
janet_buffer_push_cstring(buffer, stream.str().c_str());
}
const JanetAbstractType geom_point_type = {
"2geom/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");
}
Geom::Point& janet_unwrap_point_ref(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");
}
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[] = {
{
"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_ref(argv[0]);
Geom::Point& v2 = janet_unwrap_point_ref(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_ref(argv[0]);
Geom::Point& v2 = janet_unwrap_point_ref(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");
}
}
extern "C" void janet_lib_geom_point(JanetTable *env) {
janet_cfuns(env, NULL, it_cfuns);
janet_register_abstract_type(&geom_point_type);
}