How to group groups

Hey all, I’m new in programming for SketchUp and I start to follow a video tutorial in youtube of a “stairs maker plugin”. new I try to make it abit better for my purpose and I came out with a problem.
I want the end result will be that the staircase I create will be grouped (I also want that each step will be grouped which I already manage to do)

This is my code:

require 'sketchup.rb' 
SKETCHUP_CONSOLE.show 


UI.menu("Extensions").add_item("My First Pluing") {
  UI.messagebox("Lets Start!")
  prompts = ["Number of Staris"]
  defaults = ["1"]
  input = UI.inputbox(prompts, defaults, "Staricase Creator")
  
  #calling all methods
  draw_staris(input)
}

def cm_to_inch(x) 
  x = x / 2.54 
  return x
end 

def draw_staris(input)
   #vars
   staris = input[0].to_i 
   rise = cm_to_inch(17) 
   run = cm_to_inch(28) 
   width = cm_to_inch(110) 
   
   #GEt handle to our model 
   mod = Sketchup.active_model # Open model
   ent = mod.entities # All entities in model 
   
   #loop across this code
   for step in 1..staris
     x1 = 0 
     x2 = width
     y1 = run * step
     y2 = run * (step + 1) 
     z = rise * step
     #create our points using arrays
     pt1 = [x1,y1,z] 
     pt2 = [x2,y1,z] 
     pt3 = [x2,y2,z]
     pt4 = [x1,y2,z] 

     new_face = ent.add_face pt1, pt2, pt3, pt4
     step_group = ent.add_group(new_face) 
     new_face.material = "red"
     new_face.pushpull rise
     
    end
end

any help will be blessed.
btw:
I couldn’t find good tutorials for studying.
I can use the documentations but for a beginner, it’s a bit difficult. there is any good tutorial or book for this specific purpose?

thx a lot
Aviad.

indent preformatted text by 4 spaces

Reassigned this topic thread to the Ruby API subcategory.


FYI, Please read how to post color lexed code in the forum …


As said many times here in other threads, the API documentation is a programmer’s reference.
It is not a teaching resource, and it’s code snippets range from worthless to erroneous.

See the wiki lists of resources for learning Ruby and then how the SketchUp API extends the Ruby core…

In addition … ALL of your code, for ANY of your extensions, must be within a company or author namespace module. Then each of your extensions should be in a separate submodule within your namespace module.

I long ago posted a simple template for Basic extensions …


This would need to be removed after development, or you could make it dependent upon a debug / dev flag variable in your module.

But it is probably easier to use a console opener extension.
https://extensions.sketchup.com/extension/461ee6e6-1387-45dc-a071-8f136ad2376b/eneroth-console-opener

You do not need to require other files in your file, unless your file uses features defined in that other file.

In this case … SketchUp itself will already have loaded all 3 of the “special” files in it’s Tools subfolder (ie, "sketchup.rb", "langhandler.rb", and "extensions.rb",) before any custom extension (including yours) has even begun to load.


Proper SketchUp extensions require a extension subfolder and a registrar script of the same name in the “Plugins” directory folder. See:


Looking at your code quickly …

1. Ruby uses 2 space indentation. Some of your indents are 3 spaces.

2. "Plugin" is misspelled "Pluing"

3. "Stairs" is misspelled "Staris"

4. "Staircase" is misspelled "Staricase"

5. Use the active entities and you never know at what level the user will want to create their stairs:

   ents = mod.active_entities

6. The “Lets Start!” messagebox is frivolous and the input dialog does a good job on it’s own of signalling the beginning of the command cycle. (Both of them are modal dialogs that force the user to deal with them, so just use the input dialog.)

7. Your menu item proc should only call a command method. This way you can tweak your method code, reload your main file, and it will redefine the command method. Your way, you have to exit SketchUp and restart the application just to see the new functionality.

Example …

    def create_staircase_command
      prompts = ["Number of Stairs"]
      defaults = ["1"]
      input = UI.inputbox(prompts, defaults, "Staircase Creator")
      # Always check if user cancelled:
      return unless input # evals falsely if user cancels inpubox
      # User did not cancel and input is an array, so draw the stairs:
      draw_stairs(input)
    end

… and down at the bottom of your module …

    unless @loaded
      UI.menu("Extensions").add_item("Create Staircase...") {
        create_staircase_command()
      }
      @loaded = true
    end

Notice how the creation of UI menu items (commands, toolbars and buttons) must be done within a conditional that only happens upon first load. This prevents duplicate menu items when you reload files during development (which you’ll be doing many times.)


8. You do not need to write your own unit conversion methods. The SketchUp API added many conversion methods to the Numeric class, which passes them on down to Integer, Float, etc.
See:

In addition, the UI.inpubox will correctly convert between model units and internal Length (inches).
This means you do not need to write your code specifically for metric or imperial units. Read ThomThom’s primer blog on dealing with units and inputboxes …

Oh … and my last thought is you’ll need to move rise, run and tread width into the inputbox so users can tailor the staircase to their own needs (and local building codes.)

1 Like

Here is an example, where the staircase is grouped, and each tread is a component instance.
(It does not draw the stringer components.)

# encoding: UTF-8

module Aviad
  module StaircaseCreator

    extend self
    
    KEY ||= Module.nesting[0].name.gsub('::','_')

    def get_defaults
      defaults = Sketchup.read_default(KEY,'staircase_defaults')
      if defaults
        defaults.map! {|val|
          next val unless val.is_a?(String)
          val.to_l rescue val 
        }
      else
        defaults = [3, 17.cm, 28.cm, 110.cm, 3.8.cm, 'Staircase']
      end
      @staircase_defaults = defaults
    end

    def set_defaults(input)
      defaults = input.map {|val|
        next val unless val.is_a?(Length)
        val.to_s rescue val
      }
      Sketchup.write_default(KEY,'staircase_defaults',defaults)
      @staircase_defaults = input
    end

    # Initialize @staircase_defaults at load time:
    get_defaults() unless defined? @staircase_defaults

    def create_staircase_command
      prompts = [
        "Number of Stairs", "Rise", "Run", "Tread Width",
        "Tread Thickness", "Staircase Group Name"
      ]
      defaults = @staircase_defaults
      input = UI.inputbox(prompts, defaults, "Staircase Creator")
      # Always check if user cancelled:
      return unless input # evals falsely if user cancels inpubox
      # User did not cancel and input is an array, so draw the stairs:
      set_defaults(input) if @staircase_defaults != input
      draw_stairs(input)
    end

    def with_operation(model, op_name, disable_ui = true)
      return false unless block_given?
      model.start_operation(op_name,disable_ui)
      yield
      model.commit_operation
    end

    def draw_stairs(input)
      # vars
      stairs = input[0].to_i 
      rise   = input[1]
      run    = input[2]
      width  = input[3]
      thick  = input[4]
      staircase_name = input[5]

      # Get handle to our model 
      mod = Sketchup.active_model
      ents = mod.active_entities

      with_operation(mod, "Draw Staircase") do
        #
        staircase = ents.add_group
        staircase.entities.add_cpoint([0, 0, 0])
        staircase.name = staircase_name

        tread_component = mod.definitions.add("Step")
        # Create our points using arrays
        tread_pts = [
          [0, 0, 0],
          [width, 0, 0],
          [width, run, 0],
          [0, run, 0],
        ]
        tread_face = tread_component.entities.add_face(tread_pts)
        tread_face.material = "red"
        tread_face.pushpull(thick)

        # Add a tread instance for each step:
        for step in 1..stairs
          x = 0
          y = run * (step-1)
          z = rise * step
          staircase.entities.add_instance(tread_component,[x,y,z])
        end
        #
      end # operation
    end

    unless @loaded
      UI.menu("Extensions").add_item("Create Staircase...") {
        create_staircase_command()
      }
      @loaded = true
    end

  end
end