Component in a component

Hi everybody, I am a ruby beginner.
I have a small background in developpment.
I started this summer with the lecture of the book Automatic Sketchup, I look after exemples in this forum…but since few weeks i am face to a problem.

I want to make a list of components and I only succed to make a component in a component. My design look like a Russian doll.

this is my code exemple

# load "C:/ruby_scripts/CubeComponent.rb"

#First we pull in the standard api hooks
require 'sketchup.rb'

Sketchup.send_action "showRubyPanel:"

# Add a menu item to Launch our plugin
UI.menu("PlugIns").add_item("Cube") {
	Sketchup.active_model.start_operation "Cube"
	# Create a new layer
	model = Sketchup.active_model
	l_new = model.layers.add "Cube"
	model.active_layer = l_new
	#List of entities of the roof
	cube1
	cube2
}
		


def cube1

	#Create the component definition
	ents = Sketchup.active_model.entities
	
	#Get handles to our model and the Entities collection it contains
	model = Sketchup.active_model
	entities = model.entities
	
	x1 = 0
	x2 = 1000.mm
	y = 0
	z1 = 0
	z2 = 1000.mm
 
	pt1 = [x1, y, z1]
	pt2 = [x1, y, z2]
	pt3 = [x2, y, z2]
	pt4 = [x2, y, z1]

	# Call methods on the Entities collection top drax stuff
	new_face = entities.add_face pt1, pt2, pt3, pt4
	new_face.pushpull 1000.mm

	# Create a group and make it a component
	cube1_group = ents.add_group ents.to_a
	component_instance = cube1_group.to_component
	definition = component_instance.definition
	definition.name = "cube1"
end

def cube2

	#Create the component definition
	ents = Sketchup.active_model.entities
	
	#Get handles to our model and the Entities collection it contains
	model = Sketchup.active_model
	entities = model.entities
	
	x1 = 2000.mm
	x2 = 3000.mm
	y = 0
	z1 = 0
	z2 = 1000.mm

	pt1 = [x1, y, z1]
	pt2 = [x1, y, z2]
	pt3 = [x2, y, z2]
	pt4 = [x2, y, z1]


	# Call methods on the Entities collection top drax stuff
	new_face = entities.add_face pt1, pt2, pt3, pt4
	new_face.pushpull 1000.mm

	# Create a group and make it a component
	cube2_group = ents.add_group ents.to_a
	component_instance = cube2_group.to_component
	definition = component_instance.definition
	definition.name = "cube2"
		
end

could you give me hint? I am sure, it will look so obvious to you…

thank you in advance

Best regards,

General note here: Please safely namespace your extension to insulate it from other extensions.
For more info, check this out:https://developer.sketchup.com/hello-cube

Dan has also created this template for such a thing:

As for your issue; in your second function “cube2”, when you set:
ents = Sketchup.active_model.entities
You are setting “ents” to include all entities that are currently in your model (including the component created in “cube1”).

1 Like

Thank you very much for your help.

Have a nice day!

David

1 Like

I would like to add my notes too.

  1. Bad habit of using Layers (Tags)
    The proper way is described here: Controlling-visibility-tags
    Therefore, I suggest that you do not activate the new layer:
    model.active_layer = l_new
    Instead, draw on the default layer and assign layer to group. So, e.g. I would do the cube1 method like this:
    (The ents = Sketchup.active_model.entities is redundant, so removed)
def cube1
  
  #Get handles to our model and the Entities collection it contains
  model = Sketchup.active_model
  entities = model.entities
  
  x1 = 0
  x2 = 1000.mm
  y = 0
  z1 = 0
  z2 = 1000.mm
 
  pt1 = [x1, y, z1]
  pt2 = [x1, y, z2]
  pt3 = [x2, y, z2]
  pt4 = [x2, y, z1]
  
  # Create an empty group
  cube1_group = entities.add_group
  
  # Call methods on the cube1_group Entities collection 
  # to draw stuff into it
  new_face = cube1_group.entities.add_face pt1, pt2, pt3, pt4
  new_face.pushpull 1000.mm
  
  #Assign layer to group
  cube1_group.layer = "Cube"
  
  # Convert a group to a component
  component_instance = cube1_group.to_component
  definition = component_instance.definition
  definition.name = "cube1"
  
end

You can do similar with cube2.


  1. Operation left open.
    You have been started the operation but did not closed. Therefore I would do the menu stuff like this:
UI.menu("PlugIns").add_item("Cube") {
  # Create a new operation (which can be undone) 
  model = Sketchup.active_model
  model.start_operation( "Create Cubes" , true )
  
  # Create a new layer
  l_new = model.layers.add "Cube"

  #List of entities of the roof
  cube1
  cube2
  
  #Commit the operation
  model.commit_operation
}

  1. I moved your topic to [Developers][Ruby API] category.
3 Likes

4. That book does not properly teach correct Ruby programming. You need to learn the basics of good Ruby programming to apply the additions that the SketchUp API adds to Ruby.

Free books for download here …

5. Then study the “official example extensions” …


#First we pull in the standard api hooks
require 'sketchup.rb'

6. The comment “pull in the standard api hooks” is erroneous.
The "sketchup.rb" file does not do this. It simply adds a few global methods, (which you can and should code without using,) to the top level ObjectSpace.

Also, SketchUp itself has already loaded this file by the time your extension code gets loaded.
Please understand that the Ruby API “hooks” are compiled into a library and are loaded automatically by SketchUp before any files in the program’s "Tools" folder or the user’s "Plugins" folder get loaded.

3 Likes

7. This is not a statement that should be in every code file you write.
Use a plugin to control if you wish the Ruby Console to open when SketchUp starts.
Christina has published one …

You can toggle console opening on and off, as well as decide when to load the extension or not, via the Extension Manager dialog.


8. When creating UI commands, toolbar or menu items, always have the command block call a command method, rather than putting the code for the command inside the block.

The reason is that you cannot redefine this block after the extension loads. This makes development difficult as you would need to close and reopen SketchUp to see any command code changes take effect.

Instead, put the code for a UI command into it’s own method. In Ruby methods can be redefined at Runtime (ie, anytime after loading.) So change can be made to the command code, and your extension module reloaded, and the changes will take immediate effect. And your testing can resume without the rigmarole of closing and restarting SketchUp.


9. Look at the two method cube1 and cube2. What is different about them?
Not much. Just a few numeric arguments and perhaps a name string. This is a perfect opportunity to write a generic “cube maker” method that accepts arguments passed in to create the cube.


10. Your pattern for creating the cube definitions is convoluted. If you know you will need a component, then create a component, not a group. (FYI, groups are just components with “special” behaviors such as being hidden from the “In Model” components collection.)

Secondly, when creating geometry within a group or component, you use local coordinates and start from the local origin.

model = Sketchup.active_model

cube1_def = model.definitions.add("Cube1")
c1ents = cube1_def.entities
w = h = d = 1000.mm
pts = [
  [0,0,0], [0,0,h], [w,0,h], [w,0,0]
]
face = c1ents.add_face(pts)
face.pushpull(d)

And afterward you place the instance (either group or component) at the needed 3D position in some entities context using a transformation. (The most basic transform is translational to a given point, and many API methods take an array of 3 numeric coordinates in place of a transformation argument.)

# Place an instance:
x = 2000.mm
y = z = 0
ents = model.active_entities
cube1 = ents.add_instance(cube1_def, [x,y,z])
2 Likes