sketchucation logo sketchucation
    • Login
    🤑 SketchPlus 1.3 | 44 Tools for $15 until June 20th Buy Now

    Pass array to a c/c++ ruby extension

    Scheduled Pinned Locked Moved Developers' Forum
    6 Posts 3 Posters 2.1k Views 3 Watching
    Loading More Posts
    • Oldest to Newest
    • Newest to Oldest
    • Most Votes
    Reply
    • Reply as topic
    Log in to reply
    This topic has been deleted. Only users with topic management privileges can see it.
    • D Offline
      dacastror
      last edited by

      Hi, I am creating my first c / c ++ ruby extension with the help of the examples found in: https://github.com/SketchUp/ruby-c-extension-examples
      I have been able to modify these examples successfully. But now I want to pass an array of ruby to C ++ like the following:

      [ [1, 2, 3], [2 ,3, 4], [4, 5, 6], ... ]

      That correspond to the 3d coordinates of some points, and I want to bring back to ruby another similar array. For the moment I have only been successful with strings and with floats using the example of the repository called SUEX_UsingSWIG, but I do not know how it is done for arrays. Thank you in advance for your help.
      (I use google translator, sorry for the mistakes in the translation)

      1 Reply Last reply Reply Quote 0
      • Dan RathbunD Offline
        Dan Rathbun
        last edited by

        Read this book for that kind of normal Ruby C extension stuff:

        This is the Pragmatic Programmer's Guide to Extending Ruby (for v1.9.2)
        by Dave Thomas.
        (A companion to the good ol' "Pick Axe" Pragmatic Programmer's Guide):

        http://media.pragprog.com/titles/ruby3/ext_ruby.pdf

        I'm not here much anymore.

        1 Reply Last reply Reply Quote 0
        • Dan RathbunD Offline
          Dan Rathbun
          last edited by

          @anton_s said:

          Note: I did not check this code for typos, so it's up to you to fix it (if there are any).

          I see one. The Ruby initiator function should begin:

          
          void Init_some_lib() {
          // ...
          
          

          where the name of the library file is exactly "some_lib" (with whatever the platform shared library extension is, ie ".so", ".dll", ".bundle". etc.)

          I'm not here much anymore.

          1 Reply Last reply Reply Quote 0
          • D Offline
            dacastror
            last edited by

            Anton thank you very much, your code worked very well when I entered it in SUEX_HelloWorld.cpp from the HelloWorld example of the repository, I just changed some names in the project to match everything and it worked perfectly 😄 .

            Thanks a lot for the pdf Dan, it's very interesting.

            I still have one question, how could I do this in the example called SUEX_UsingSWIG ?, I observed the Swig documentation and the pdf that shows Dan, but I could not see how this is done. Any idea?

            1 Reply Last reply Reply Quote 0
            • A Offline
              Anton_S
              last edited by

              Everything you pass to ruby and obtain from ruby is in a form of pointers (except for fixed numbers and some literals). So, an array passed to a c extension would be in a form of a pointer. Here is how you would process it:

              static VALUE process_array(VALUE self, VALUE v_array) {
                  // Ensure the data passed is an array
                  Check_Type(v_array, T_ARRAY);
                  // Process the array
                  unsigned int array_size = (unsigned int)RARRAY_LEN(v_array);
                  for (unsigned int i = 0; i < array_size; ++i) {
                      VALUE v_internal_array = rb_ary_entry(v_array, i);
                      // Ensure the internal value is an array
                      Check_Type(v_internal_array, T_ARRAY);
                      // Process the internal array
                      unsigned int internal_array_size = (unsigned int)RARRAY_LEN(v_internal_array);
                      for (unsigned int j = 0; j < internal_array_size; ++j) {
                          VALUE v_res = rb_ary_entry(v_array, i);
                          int res = NUM2INT(v_res);
                          // Do something
                      }
                  }
                  // Return something (nil in this case)
                  return Qnil;
              }
              

              If you want to process an array of Geom::Point3d/Geom::Vector3d objects, you have to access them by their x, y, z interns:

              static VALUE process_array_of_points(VALUE self, VALUE v_array) {
                  // Ensure the data passed is an array
                  Check_Type(v_array, T_ARRAY);
                  // Process the array
                  unsigned int array_size = (unsigned int)RARRAY_LEN(v_array);
                  for (unsigned int i = 0; i < array_size; ++i) {
                      VALUE v_point = rb_ary_entry(v_array, i);
                      double x = rb_num2dbl(rb_funcall(v_point, rb_intern("x"), 0));
                      double y = rb_num2dbl(rb_funcall(v_point, rb_intern("y"), 0));
                      double z = rb_num2dbl(rb_funcall(v_point, rb_intern("z"), 0));
                      // Do something
                  }
                  // Return something (nil in this case)
                  return Qnil;
              }
              

              Accessing even an Array object with x,y,z interns will work too, because SketchUp adds these functions to an Array class. So, this second function will work with an array of array, array of Point3d objects, and array of Vector3d objects.

              And then of course, you will have to link them with Ruby in the initiator function:

              void Init_some_lib() {
                  VALUE mDacastror = rb_define_module("Dacastror");
              
                  rb_define_module_function(mDacastror, "process_array", VALUEFUNC(process_array), 1);
                  rb_define_module_function(mDacastror, "process_array_of_points", VALUEFUNC(process_array_of_points), 1);
              }
              

              Note: I did not check this code for typos, so it's up to you to fix it (if there are any).

              Here are a few links to Ruby c++ extension guides:
              http://clalance.blogspot.com/2011/01/writing-ruby-extensions-in-c-part-9.html
              https://silverhammermba.github.io/emberb/c/

              If you search the web, there are plenty of more links on that.

              1 Reply Last reply Reply Quote 0
              • Dan RathbunD Offline
                Dan Rathbun
                last edited by

                Never could understand SWIG much. Cryptic interface language.
                If you intended to write a library that needs interfaces in multiple scripting languages, then SWIG might lessen the workload. Or if you are wanting a Ruby interface for some library already written that has SWIG interface files, then again I can see using SWIG.

                But for an extension that will be written specifically for SketchUp, since it only uses Ruby, I cannot see much use for SWIG.

                Link Preview Image
                SWIG - Wikipedia

                favicon

                (en.wikipedia.org)

                Link Preview Image
                SWIG Tutorial

                favicon

                (www.swig.org)

                Link Preview Image
                Simplified Wrapper and Interface Generator

                favicon

                (www.swig.org)

                I'm not here much anymore.

                1 Reply Last reply Reply Quote 0
                • 1 / 1
                • First post
                  Last post
                Buy SketchPlus
                Buy SUbD
                Buy WrapR
                Buy eBook
                Buy Modelur
                Buy Vertex Tools
                Buy SketchCuisine
                Buy FormFonts

                Advertisement