#include "rays/ruby/point.h" #include "defs.h" RUCY_DEFINE_VALUE_OR_ARRAY_FROM_TO(Rays::Point) #define THIS to(self) #define CHECK RUCY_CHECK_OBJ(Rays::Point, self) static VALUE alloc(VALUE klass) { return new_type(klass); } static VALUE initialize(VALUE self) { CHECK; check_arg_count(__FILE__, __LINE__, "Point#initialize", argc, 0, 1, 2, 3); if (argc >= 1) *THIS = to(argc, argv); return self; } static VALUE initialize_copy(VALUE self, VALUE obj) { CHECK; *THIS = to(obj); return self; } static VALUE move_to(VALUE self) { CHECK; check_arg_count(__FILE__, __LINE__, "Point#move_to", argc, 1, 2, 3); if (argv[0].is_kind_of(Rays::point_class())) THIS->move_to(to(argv[0])); else { const Rays::Point& p = *THIS; coord x = (argc >= 1 && argv[0]) ? to(argv[0]) : p.x; coord y = (argc >= 2 && argv[1]) ? to(argv[1]) : p.y; coord z = (argc >= 3 && argv[2]) ? to(argv[2]) : p.z; THIS->move_to(x, y, z); } return self; } static VALUE move_by(VALUE self) { CHECK; check_arg_count(__FILE__, __LINE__, "Point#move_by", argc, 1, 2, 3); if (argv[0].is_kind_of(Rays::point_class())) THIS->move_by(to(argv[0])); else { coord x = (argc >= 1 && argv[0]) ? to(argv[0]) : 0; coord y = (argc >= 2 && argv[1]) ? to(argv[1]) : 0; coord z = (argc >= 3 && argv[2]) ? to(argv[2]) : 0; THIS->move_by(x, y, z); } return self; } static VALUE rotate(VALUE self, VALUE degree) { CHECK; Rays::Point p = *THIS; p.rotate(to(degree)); return value(p); } static VALUE rotate_self(VALUE self, VALUE degree) { CHECK; THIS->rotate(to(degree)); } static VALUE length(VALUE self) { CHECK; return value(THIS->length()); } static VALUE normalize(VALUE self) { CHECK; THIS->normalize(); return self; } static VALUE normal(VALUE self) { CHECK; return value(THIS->normal()); } static VALUE set_x(VALUE self, VALUE x) { CHECK; THIS->x = to(x); return x; } static VALUE get_x(VALUE self) { CHECK; return value(THIS->x); } static VALUE set_y(VALUE self, VALUE y) { CHECK; THIS->y = to(y); return y; } static VALUE get_y(VALUE self) { CHECK; return value(THIS->y); } static VALUE set_z(VALUE self, VALUE z) { CHECK; THIS->z = to(z); return z; } static VALUE get_z(VALUE self) { CHECK; return value(THIS->z); } static VALUE negate(VALUE self) { CHECK; return value(-*THIS); } static VALUE add(VALUE self) { CHECK; if (argc == 1 && argv->is_num()) return value(*THIS + to(*argv)); else return value(*THIS + to(argc, argv)); } static VALUE sub(VALUE self) { CHECK; if (argc == 1 && argv->is_num()) return value(*THIS - to(*argv)); else return value(*THIS - to(argc, argv)); } static VALUE mult(VALUE self) { CHECK; if (argc == 1 && argv->is_num()) return value(*THIS * to(*argv)); else return value(*THIS * to(argc, argv)); } static VALUE div(VALUE self) { CHECK; if (argc == 1 && argv->is_num()) return value(*THIS / to(*argv)); else return value(*THIS / to(argc, argv)); } static VALUE set_at(VALUE self, VALUE index, VALUE value) { CHECK; int i = index.as_i(); if (i < 0 || 2 < i) index_error(__FILE__, __LINE__); (*THIS)[i] = to(value); return value; } static VALUE get_at(VALUE self, VALUE index) { CHECK; int i = index.as_i(); if (i < 0 || 2 < i) index_error(__FILE__, __LINE__); return value((*THIS)[i]); } static VALUE inspect(VALUE self) { CHECK; return value(Xot::stringf("#", THIS->inspect().c_str())); } static VALUE dot(VALUE self, VALUE p1, VALUE p2) { return value(Rays::dot(to(p1), to(p2))); } static VALUE cross(VALUE self, VALUE p1, VALUE p2) { return value(Rays::cross(to(p1), to(p2))); } static Class cPoint; void Init_point () { Module mRays = rb_define_module("Rays"); cPoint = rb_define_class_under(mRays, "Point", rb_cObject); rb_define_alloc_func(cPoint, alloc); rb_define_private_method(cPoint, "initialize", RUBY_METHOD_FUNC(initialize), -1); rb_define_private_method(cPoint, "initialize_copy", RUBY_METHOD_FUNC(initialize_copy), 1); cPoint.define_method("move_to!", move_to); cPoint.define_method("move_by!", move_by); rb_define_method(cPoint, "rotate", RUBY_METHOD_FUNC(rotate), 1); cPoint.define_method("rotate!", rotate_self); rb_define_method(cPoint, "length", RUBY_METHOD_FUNC(length), 0); rb_define_method(cPoint, "normalize", RUBY_METHOD_FUNC(normalize), 0); rb_define_method(cPoint, "normal", RUBY_METHOD_FUNC(normal), 0); rb_define_method(cPoint, "x=", RUBY_METHOD_FUNC(set_x), 1); rb_define_method(cPoint, "x", RUBY_METHOD_FUNC(get_x), 0); rb_define_method(cPoint, "y=", RUBY_METHOD_FUNC(set_y), 1); rb_define_method(cPoint, "y", RUBY_METHOD_FUNC(get_y), 0); rb_define_method(cPoint, "z=", RUBY_METHOD_FUNC(set_z), 1); rb_define_method(cPoint, "z", RUBY_METHOD_FUNC(get_z), 0); cPoint.define_method("-@", negate); cPoint.define_method("+", add); cPoint.define_method("-", sub); cPoint.define_method("*", mult); cPoint.define_method("/", div); cPoint.define_method("[]=", set_at); cPoint.define_method("[]", get_at); rb_define_method(cPoint, "inspect", RUBY_METHOD_FUNC(inspect), 0); rb_define_module_function(cPoint, "dot", RUBY_METHOD_FUNC(dot), 2); rb_define_module_function(cPoint, "cross", RUBY_METHOD_FUNC(cross), 2); } namespace Rucy { template <> Rays::Point value_to (int argc, const Value* argv, bool convert) { if (argc == 1 && argv->is_array()) { argc = argv->size(); argv = argv->as_array(); } assert(argc == 0 || (argc > 0 && argv)); if (convert) { if (argc == 0) return Rays::Point(); else if (argv->is_num()) { switch (argc) { #define V(i) to(argv[i]) case 1: return Rays::Point(V(0)); case 2: return Rays::Point(V(0), V(1)); case 3: return Rays::Point(V(0), V(1), V(2)); #undef V default: argument_error(__FILE__, __LINE__); } } } if (argc != 1) argument_error(__FILE__, __LINE__); return value_to(*argv, convert); } }// Rucy namespace Rays { Class point_class () { return cPoint; } }// Rays