Insert dynamic component by "Drawing"

Hello everyone!

I am looking to make a small script to insert a dynamic component from the Sketchup library, it would be as follows:

  1. Choose Component (drop down list?)
  2. Get Insert point (click 0,0,0)
  3. Get Second point (click 400,200,0)
  4. Insert component (origin 0,0,0 scale Y to 400,200,0)

It should be noted that I am learning ruby ​​and the Sketchup API in this forum and reviewing the Automatic Sketchup Creation of 3D models in Ruby book. I reviewed the example of the book on modeling a sphere sphere_tool.rb and it is fascinating, could you make some changes and adapt it to the tool I am looking to create??

class SphereTool
 def activate
 $ents = Sketchup.active_model.entities

 # The points clicked by the user
 @pt1 = Sketchup::InputPoint.new
 @pt2 = Sketchup::InputPoint.new

 # The initial state (user hasn't clicked yet)
 @first_click = false
 end
 # If the user clicked, draw a line
 def onMouseMove flags, x, y, view
 if @first_click
 @pt2.pick view, x, y, @pt1
 view.invalidate
 end
 end

# Check the state, then draw a sphere or a point
 def onLButtonDown flags, x, y, view
 if @first_click
 if (@pt1.position.distance @pt2.position) > 0
 # Remove the construction point
 $ents.erase_entities $c_point
 draw_sphere
 end
 else
 @pt1.pick view, x, y
 $c_point = $ents.add_cpoint @pt1.position
 @first_click = true
 end
 end
 def draw view
 if @first_click && @pt2.valid?
 view.set_color_from_line @pt1.position, @pt2.position
 view.line_width = 3
 view.draw_line @pt1.position, @pt2.position
 end
 end
 # Draw the sphere
 def draw_sphere
 # Draw the circles
 rad = @pt1.position.distance @pt2.position
 circle = $ents.add_circle @pt1.position, [1, 0, 0], rad
 path = $ents.add_circle @pt1.position, [0, 1, 0], rad + 1
 circle_face = $ents.add_face circle
 # Extrude the sphere and erase the extrusion path

circle_face.followme path
 $ents.erase_entities path
 reset
 end
 # Return to original state
 def reset
 @pt1.clear
 @pt2.clear
 @first_click = false
 end
 # Respond when user presses Escape
 def onCancel flags, view
 reset
 end
end
# Create the Command object
sphere_cmd = UI::Command.new("Sphere") {
 Sketchup.active_model.select_tool SphereTool.new
}
# Configure the Command's appearance
sphere_cmd.small_icon = "sphere_small.gif"
sphere_cmd.large_icon = "sphere_large.gif"
sphere_cmd.tooltip = "Create a sphere"
# Create and configure the Toolbar
sphere_toolbar = UI::Toolbar.new "Sphere"
sphere_toolbar.add_item sphere_cmd
sphere_toolbar.show

when inserting the dynamic component it would be like the rectangle tool. Please if someone can give me an idea of ​​how to modify the code of the sphere to adapt it to what I am looking for. Thank you very much!

(a) Please correct the indentation in the example. (2 spaces for each level.)

(b) do NOT use global variables such as $ents.
Instead use local variables within your methods or @vars withinyour modules or classes.

Be careful, as that book does not teach proper Ruby coding in SketchUp’s shared environment.

For example, any custom tool class would need to be wrapped in your custom extension submodule, which must be within your unique toplevel namespace module.


For (1) you will need to get the path to a local folders of components.
This has been discussed in a previous topic thread.

Once you have the path, you can use UI.openpanel dialog so the user can select the component file.

  comp_path = UI.openpanel("Select Component", path, "SketchUp Model Files|*.skp;||")

We usually ask that you at least make an attempt to solve your own coding challenges.

If the user picks a valid component path, add it to the model’s definition list

    return if !comp_path # break out of your method
    comp_def = model.definitions.load(comp_path)

Then place an instance at the location of @pt1

    inst = model.active_entities.add_instance(comp_def, @pt1)

Lastly scale the instance …

    bb = inst.bounds
    xdiff = (@pt2.x - @pt1.x).to_l
    xscale = xdiff == 1.to_l || xdiff == 0.to_l ? 1.0 : xdiff / bb.width
    ydiff = (@pt2.y - @pt1.y).to_l
    yscale = ydiff == 1.to_l || ydiff == 0.to_l ? 1.0 : ydiff / bb.height
    zdiff = (@pt2.z - @pt1.z).to_l
    zscale = zdiff == 1.to_l || zdiff == 0.to_l ? 1.0 : zdiff / bb.depth
    inst.transform!(Geom::Transformation::scaling(xscale,yscale,zscale))

thank you very much sir danrathbun. I will review the code with the proposed solutions.

If any of the bounding box dimensions are 0, dividing the difference can cause a division by zero error. So a rescue modifier can help. Ie …

xscale = xdiff == 1.to_l || xdiff == 0.to_l ? 1.0 : (xdiff / bb.width rescue 1.0)

… or …

if bb.width == 0.0.to_l || xdiff == 1.to_l || xdiff == 0.to_l
  xscale = 1.0
else
  xscale = xdiff / bb.width
end

The latter is likely better as it checks whether the bounds dimension is within SketchUp’s tolerance for Length values.

Whichever test you use, repeat for the other two dimensions/axis.