#include "rays/ruby/bounds.h" #include #include "rays/ruby/point.h" #include "defs.h" using namespace Rucy; using Rays::coord; static Class cBounds; RUCY_DEFINE_VALUE_FROM_TO(Rays::Bounds, cBounds) #define THIS to(self) #define CHECK RUCY_CHECK_OBJ(Rays::Bounds, cBounds, self) static VALUE alloc(VALUE klass) { return new_type(klass); } static VALUE initialize(VALUE self) { CHECK; check_arg_count(__FILE__, __LINE__, "Bounds#initialize", argc, 0, 1, 2, 3, 4, 6); if (argc == 0) return self; switch (argc) { case 1: *THIS = Rays::Bounds(to(argv[0])); break; case 2: *THIS = Rays::Bounds(to(argv[0]), to(argv[1])); break; case 3: *THIS = Rays::Bounds( to(argv[0]), to(argv[1]), to(argv[2])); break; case 4: *THIS = Rays::Bounds( to(argv[0]), to(argv[1]), to(argv[2]), to(argv[3])); break; case 6: *THIS = Rays::Bounds( to(argv[0]), to(argv[1]), to(argv[2]), to(argv[3]), to(argv[4]), to(argv[5])); break; } return self; } static VALUE initialize_copy(VALUE self, VALUE obj) { CHECK; *THIS = to(obj); return self; } static VALUE intersect(VALUE self) { CHECK; check_arg_count(__FILE__, __LINE__, "Bounds#intersect?", argc, 1, 2); const Rays::Bounds& bounds = to(argv[0]); int dimension = argc >= 2 ? to(argv[1]) : 2; return value(THIS->is_intersect(bounds, dimension)); } static VALUE include(VALUE self) { CHECK; check_arg_count(__FILE__, __LINE__, "Bounds#include?", argc, 1, 2); const Rays::Point& point = to(argv[0]); int dimension = argc >= 2 ? to(argv[1]) : 2; return value(THIS->is_include(point, dimension)); } static VALUE move_to(VALUE self) { CHECK; check_arg_count(__FILE__, __LINE__, "Bounds#move_to", argc, 1, 2, 3); if (argv[0].is_kind_of(Rays::point_class())) THIS->move_to(to(argv[0])); else { if (argv[0].is_array()) { argc = argv[0].size(); argv = argv[0].as_array(); } const Rays::Point& p = THIS->position(); 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__, "Bounds#move_by", argc, 1, 2, 3); if (argv[0].is_kind_of(Rays::point_class())) THIS->move_by(to(argv[0])); else { if (argv[0].is_array()) { argc = argv[0].size(); argv = argv[0].as_array(); } 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 resize_to(VALUE self) { CHECK; check_arg_count(__FILE__, __LINE__, "Bounds#resize_to", argc, 1, 2, 3); if (argv[0].is_kind_of(Rays::point_class())) THIS->resize_to(to(argv[0])); else { if (argv[0].is_array()) { argc = argv[0].size(); argv = argv[0].as_array(); } const Rays::Point& p = THIS->size(); 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->resize_to(x, y, z); } return self; } static VALUE resize_by(VALUE self) { CHECK; check_arg_count(__FILE__, __LINE__, "Bounds#resize_by", argc, 1, 2, 3); if (argv[0].is_kind_of(Rays::point_class())) THIS->resize_by(to(argv[0])); else { if (argv[0].is_array()) { argc = argv[0].size(); argv = argv[0].as_array(); } 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->resize_by(x, y, z); } return self; } static VALUE inset_by(VALUE self) { CHECK; check_arg_count(__FILE__, __LINE__, "Bounds#inset_by", argc, 1, 2, 3); if (argv[0].is_kind_of(Rays::point_class())) THIS->inset_by(to(argv[0])); else { if (argv[0].is_array()) { argc = argv[0].size(); argv = argv[0].as_array(); } 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->inset_by(x, y, z); } return self; } static VALUE set_x(VALUE self, VALUE x) { CHECK; return value(THIS->x = to(x)); } static VALUE get_x(VALUE self) { CHECK; return value(THIS->x); } static VALUE set_y(VALUE self, VALUE y) { CHECK; return value(THIS->y = to(y)); } static VALUE get_y(VALUE self) { CHECK; return value(THIS->y); } static VALUE set_z(VALUE self, VALUE z) { CHECK; return value(THIS->z = to(z)); } static VALUE get_z(VALUE self) { CHECK; return value(THIS->z); } static VALUE set_width(VALUE self, VALUE width) { CHECK; return value(THIS->width = to(width)); } static VALUE get_width(VALUE self) { CHECK; return value(THIS->width); } static VALUE set_height(VALUE self, VALUE height) { CHECK; return value(THIS->height = to(height)); } static VALUE get_height(VALUE self) { CHECK; return value(THIS->height); } static VALUE set_depth(VALUE self, VALUE depth) { CHECK; return value(THIS->depth = to(depth)); } static VALUE get_depth(VALUE self) { CHECK; return value(THIS->depth); } static VALUE set_left(VALUE self, VALUE left) { CHECK; Rays::Bounds* this_ = THIS; this_->set_left(to(left)); return value(this_->left()); } static VALUE get_left(VALUE self) { CHECK; return value(THIS->left()); } static VALUE set_right(VALUE self, VALUE right) { CHECK; Rays::Bounds* this_ = THIS; this_->set_right(to(right)); return value(this_->right()); } static VALUE get_right(VALUE self) { CHECK; return value(THIS->right()); } static VALUE set_top(VALUE self, VALUE top) { CHECK; Rays::Bounds* this_ = THIS; this_->set_top(to(top)); return value(this_->top()); } static VALUE get_top(VALUE self) { CHECK; return value(THIS->top()); } static VALUE set_bottom(VALUE self, VALUE bottom) { CHECK; Rays::Bounds* this_ = THIS; this_->set_bottom(to(bottom)); return value(this_->bottom()); } static VALUE get_bottom(VALUE self) { CHECK; return value(THIS->bottom()); } static VALUE set_back(VALUE self, VALUE back) { CHECK; Rays::Bounds* this_ = THIS; this_->set_back(to(back)); return value(this_->back()); } static VALUE get_back(VALUE self) { CHECK; return value(THIS->back()); } static VALUE set_front(VALUE self, VALUE front) { CHECK; Rays::Bounds* this_ = THIS; this_->set_front(to(front)); return value(this_->front()); } static VALUE get_front(VALUE self) { CHECK; return value(THIS->front()); } static VALUE set_position(VALUE self) { CHECK; check_arg_count(__FILE__, __LINE__, "Bounds#set_position", argc, 1, 2, 3); coord* pos = THIS->position().array; for (int i = 0; i < 3; ++i) if (argc > i && !argv[i].is_nil()) pos[i] = to(argv[i]); } static VALUE get_position(VALUE self) { CHECK; return value(THIS->position()); } static VALUE set_size(VALUE self) { CHECK; check_arg_count(__FILE__, __LINE__, "Bounds#set_size", argc, 1, 2, 3); coord* size = THIS->size().array; for (int i = 0; i < 3; ++i) if (argc > i && !argv[i].is_nil()) size[i] = to(argv[i]); } static VALUE get_size(VALUE self) { CHECK; return value(THIS->size()); } static VALUE set_center(VALUE self) { CHECK; check_arg_count(__FILE__, __LINE__, "Bounds#set_center", argc, 1, 2, 3); if (argv[0].is_kind_of(Rays::point_class())) THIS->set_center(to(argv[0])); else { Rays::Point p = THIS->center(); 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->set_center(x, y, z); } return value(THIS->center()); } static VALUE center(VALUE self) { CHECK; return value(THIS->center()); } static VALUE array_get(VALUE self, VALUE index) { CHECK; int i = index.as_i(); if (i < 0 || 1 < i) index_error(__FILE__, __LINE__); return value((*THIS)[i]); } static VALUE array_set(VALUE self, VALUE index, VALUE value) { CHECK; int i = index.as_i(); if (i < 0 || 1 < i) index_error(__FILE__, __LINE__); (*THIS)[i] = to(value); return value; } static VALUE and_(VALUE self, VALUE bounds) { CHECK; Rays::Bounds b = *THIS; b &= to(bounds); return value(b); } static VALUE or_(VALUE self, VALUE bounds) { CHECK; Rays::Bounds b = *THIS; b |= to(bounds); return value(b); } static VALUE inspect(VALUE self) { CHECK; return value(Xot::stringf("#", THIS->inspect().c_str())); } void Init_bounds () { Module mRays = rb_define_module("Rays"); cBounds = rb_define_class_under(mRays, "Bounds", rb_cObject); rb_define_alloc_func(cBounds, alloc); rb_define_private_method(cBounds, "initialize", RUBY_METHOD_FUNC(initialize), -1); rb_define_private_method(cBounds, "initialize_copy", RUBY_METHOD_FUNC(initialize_copy), 1); cBounds.define_method("intersect?", intersect); cBounds.define_method("include?", include); cBounds.define_method("move_to!", move_to); cBounds.define_method("move_by!", move_by); cBounds.define_method("resize_to!", resize_to); cBounds.define_method("resize_by!", resize_by); cBounds.define_method("inset_by!", inset_by); rb_define_method(cBounds, "x=", RUBY_METHOD_FUNC(set_x), 1); rb_define_method(cBounds, "x", RUBY_METHOD_FUNC(get_x), 0); rb_define_method(cBounds, "y=", RUBY_METHOD_FUNC(set_y), 1); rb_define_method(cBounds, "y", RUBY_METHOD_FUNC(get_y), 0); rb_define_method(cBounds, "z=", RUBY_METHOD_FUNC(set_z), 1); rb_define_method(cBounds, "z", RUBY_METHOD_FUNC(get_z), 0); rb_define_method(cBounds, "width=", RUBY_METHOD_FUNC(set_width), 1); rb_define_method(cBounds, "width", RUBY_METHOD_FUNC(get_width), 0); rb_define_method(cBounds, "height=", RUBY_METHOD_FUNC(set_height), 1); rb_define_method(cBounds, "height", RUBY_METHOD_FUNC(get_height), 0); rb_define_method(cBounds, "depth=", RUBY_METHOD_FUNC(set_depth), 1); rb_define_method(cBounds, "depth", RUBY_METHOD_FUNC(get_depth), 0); rb_define_method(cBounds, "left=", RUBY_METHOD_FUNC(set_left), 1); rb_define_method(cBounds, "left", RUBY_METHOD_FUNC(get_left), 0); rb_define_method(cBounds, "right=", RUBY_METHOD_FUNC(set_right), 1); rb_define_method(cBounds, "right", RUBY_METHOD_FUNC(get_right), 0); rb_define_method(cBounds, "top=", RUBY_METHOD_FUNC(set_top), 1); rb_define_method(cBounds, "top", RUBY_METHOD_FUNC(get_top), 0); rb_define_method(cBounds, "bottom=", RUBY_METHOD_FUNC(set_bottom), 1); rb_define_method(cBounds, "bottom", RUBY_METHOD_FUNC(get_bottom), 0); rb_define_method(cBounds, "back=", RUBY_METHOD_FUNC(set_back), 1); rb_define_method(cBounds, "back", RUBY_METHOD_FUNC(get_back), 0); rb_define_method(cBounds, "front=", RUBY_METHOD_FUNC(set_front), 1); rb_define_method(cBounds, "front", RUBY_METHOD_FUNC(get_front), 0); rb_define_method(cBounds, "set_position", RUBY_METHOD_FUNC(set_position), -1); rb_define_method(cBounds, "position", RUBY_METHOD_FUNC(get_position), 0); rb_define_method(cBounds, "set_size", RUBY_METHOD_FUNC(set_size), -1); rb_define_method(cBounds, "size", RUBY_METHOD_FUNC(get_size), 0); rb_define_method(cBounds, "set_center", RUBY_METHOD_FUNC(set_center), -1); rb_define_method(cBounds, "center", RUBY_METHOD_FUNC(center), 0); cBounds.define_method("[]", array_get); cBounds.define_method("[]=", array_set); cBounds.define_method("&", and_); cBounds.define_method("|", or_); rb_define_method(cBounds, "inspect", RUBY_METHOD_FUNC(inspect), 0); } namespace Rucy { template <> Rays::Bounds value_to (Value value, bool convert) { if (convert) { size_t argc = 0; Value* argv = NULL; if (value.is_array()) { argc = value.size(); argv = value.as_array(); } else { argc = 1; argv = &value; } if (argc < 1) Rucy::argument_error(__FILE__, __LINE__); if (argv[0].is_kind_of(Rays::bounds_class())) value = argv[0]; else if (argv[0].is_kind_of(Rays::point_class())) { switch (argc) { #define V(i) to(argv[i]) case 1: return Rays::Bounds(V(0)); case 2: return Rays::Bounds(V(0), V(1)); #undef V default: Rucy::argument_error(__FILE__, __LINE__); } } else if (argv[0].is_i() || argv[0].is_f()) { switch (argc) { #define V(i) argv[i].as_f(true) case 1: return Rays::Bounds(V(0)); case 2: return Rays::Bounds(V(0), V(1)); case 3: return Rays::Bounds(V(0), V(1), V(2)); case 4: return Rays::Bounds(V(0), V(1), V(2), V(3)); case 6: return Rays::Bounds(V(0), V(1), V(2), V(3), V(4), V(5)); #undef V default: Rucy::argument_error(__FILE__, __LINE__); } } } return value_to(value, convert); } }// Rucy namespace Rays { Class bounds_class () { return cBounds; } }// Rays