#include "rays/ruby/polygon.h" #include #include #include #include "rays/ruby/bounds.h" #include "rays/ruby/polyline.h" #include "defs.h" RUCY_DEFINE_VALUE_OR_ARRAY_FROM_TO(Rays::Polygon) #define THIS to(self) #define CHECK RUCY_CHECK_OBJECT(Rays::Polygon, self) static VALUE alloc(VALUE klass) { return new_type(klass); } static VALUE setup(VALUE self, VALUE args, VALUE loop) { CHECK; if (args[0].is_kind_of(Rays::polyline_class())) *THIS = to(args.size(), args.as_array()); else { std::vector points; get_line_args(&points, args.size(), args.as_array()); *THIS = Rays::Polygon(&points[0], points.size(), loop); } } static VALUE expand(VALUE self) { CHECK; check_arg_count(__FILE__, __LINE__, "Polygon#expand", argc, 1, 2, 3, 4); coord width = to (argv[0]); Rays::CapType cap = argc >= 2 ? to (argv[1]) : Rays::CAP_DEFAULT; Rays::JoinType join = argc >= 3 ? to(argv[2]) : Rays::JOIN_DEFAULT; coord ml = argc >= 4 ? to (argv[3]) : Rays::JOIN_DEFAULT_MITER_LIMIT; Rays::Polygon polygon; THIS->expand(&polygon, width, cap, join, ml); return value(polygon); } static VALUE bounds(VALUE self) { CHECK; return value(THIS->bounds()); } static VALUE size(VALUE self) { CHECK; return value(THIS->size()); } static VALUE empty(VALUE self) { CHECK; return value(THIS->empty()); } static VALUE get_at(VALUE self, VALUE index) { CHECK; int size = (int) THIS->size(); int i = to(index); if (i < 0) i += size; if (i < 0 || size <= i) index_error(__FILE__, __LINE__); return value((*THIS)[i]); } static VALUE each(VALUE self) { CHECK; Value ret = Qnil; for (const auto& line : *THIS) ret = rb_yield(value(line)); return ret; } static void each_polygon (const Value& value, std::function fun) { int size = value.size(); const Value* array = value.as_array(); for (int i = 0; i < size; ++i) fun(to(array[i])); } static VALUE op_sub(VALUE self, VALUE obj) { CHECK; if (obj.is_array()) { Rays::Polygon result = *THIS; each_polygon(obj, [&](const Rays::Polygon& polygon) { result = result - polygon; }); return value(result); } else return value(*THIS - to(obj)); } static VALUE op_and(VALUE self, VALUE obj) { CHECK; if (obj.is_array()) { Rays::Polygon result = *THIS; each_polygon(obj, [&](const Rays::Polygon& polygon) { result = result & polygon; }); return value(result); } else return value(*THIS & to(obj)); } static VALUE op_or(VALUE self, VALUE obj) { CHECK; if (obj.is_array()) { Rays::Polygon result = *THIS; each_polygon(obj, [&](const Rays::Polygon& polygon) { result = result | polygon; }); return value(result); } else return value(*THIS | to(obj)); } static VALUE op_xor(VALUE self, VALUE obj) { CHECK; if (obj.is_array()) { Rays::Polygon result = *THIS; each_polygon(obj, [&](const Rays::Polygon& polygon) { result = result ^ polygon; }); return value(result); } else return value(*THIS ^ to(obj)); } static VALUE create_rect(VALUE self, VALUE args, VALUE round, VALUE lefttop, VALUE righttop, VALUE leftbottom, VALUE rightbottom, VALUE nsegment) { coord x, y, w, h, lt, rt, lb, rb; uint nseg; get_rect_args( &x, &y, &w, &h, <, &rt, &lb, &rb, &nseg, args.size(), args.as_array(), round, lefttop, righttop, leftbottom, rightbottom, nsegment); return value(Rays::create_rect(x, y, w, h, lt, rt, lb, rb, nseg)); } static VALUE create_ellipse(VALUE self, VALUE args, VALUE center, VALUE radius, VALUE hole, VALUE angle_from, VALUE angle_to, VALUE nsegment) { coord x, y, w, h; Rays::Point hole_size; float from, to_; uint nseg; get_ellipse_args( &x, &y, &w, &h, &hole_size, &from, &to_, &nseg, args.size(), args.as_array(), center, radius, hole, angle_from, angle_to, nsegment); return value(Rays::create_ellipse(x, y, w, h, hole_size, from, to_, nseg)); } static VALUE create_curve(VALUE self, VALUE args, VALUE loop) { std::vector points; get_line_args(&points, args.size(), args.as_array()); return value(Rays::create_curve(&points[0], points.size(), loop)); } static VALUE create_bezier(VALUE self, VALUE args, VALUE loop) { std::vector points; get_line_args(&points, args.size(), args.as_array()); return value(Rays::create_bezier(&points[0], points.size(), loop)); } static Class cPolygon; void Init_rays_polygon () { Module mRays = rb_define_module("Rays"); cPolygon = rb_define_class_under(mRays, "Polygon", rb_cObject); rb_define_alloc_func(cPolygon, alloc); rb_define_private_method(cPolygon, "setup", RUBY_METHOD_FUNC(setup), 2); rb_define_method(cPolygon, "expand", RUBY_METHOD_FUNC(expand), -1); rb_define_method(cPolygon, "bounds", RUBY_METHOD_FUNC(bounds), 0); rb_define_method(cPolygon, "size", RUBY_METHOD_FUNC(size), 0); cPolygon.define_method("empty?", empty); cPolygon.define_method("[]", get_at); rb_define_method(cPolygon, "each", RUBY_METHOD_FUNC(each), 0); cPolygon.define_method("+", op_or); cPolygon.define_method("-", op_sub); cPolygon.define_method("&", op_and); cPolygon.define_method("|", op_or); cPolygon.define_method("^", op_xor); rb_define_singleton_method(cPolygon, "create_rect", RUBY_METHOD_FUNC(create_rect), 7); rb_define_singleton_method(cPolygon, "create_ellipse", RUBY_METHOD_FUNC(create_ellipse), 7); rb_define_singleton_method(cPolygon, "create_curve", RUBY_METHOD_FUNC(create_curve), 2); rb_define_singleton_method(cPolygon, "create_bezier", RUBY_METHOD_FUNC(create_bezier), 2); } namespace Rucy { template <> Rays::Polygon value_to (int argc, const Value* argv, bool convert) { assert(argc == 0 || (argc > 0 && argv)); if (convert) { if (argc <= 0) return Rays::Polygon(); else if (argv->is_kind_of(Rays::polygon_line_class())) { std::vector lines; lines.reserve(argc); for (int i = 0; i < argc; ++i) lines.emplace_back(to(argv[i])); return Rays::Polygon(&lines[0], lines.size()); } else if (argv->is_kind_of(Rays::polyline_class())) return Rays::Polygon(to(*argv)); else if (argv->is_num() || argv->is_array()) { std::vector points; get_line_args(&points, argc, argv); return Rays::Polygon(&points[0], points.size()); } } if (argc != 1) argument_error(__FILE__, __LINE__); return value_to(*argv, convert); } }// Rucy namespace Rays { Class polygon_class () { return cPolygon; } }// Rays