git.s-ol.nu janet-2geom / master src / point.cpp
master

Tree @master (Download .tar.gz)

point.cpp @masterraw · history · blame

#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);
}