Hi. I’m new to Ruby. I’m just trying to cut my teeth on something simple. I want to add a new instance of a component to my model and I want to add it 12 inches from the current selection on the x axis and on the same y and z axes.
Here’s a sample of my code. I don’t really think that it’s as easy as this portion of code… ([selection.x+12,selection.y,selection.z])
I just wrote that in to illustrate what I’m attempting.
Basically it’s just about trying to create a new instance of a component relative to a selection.
A selection isn’t a point but a collection of entities. What do you mean by 12 inches from it? From the center of its bounding box? From a specific endpoint within the selection?
# Create a virtual bounding box
bbox = Geom::BoundingBox.new
# For each entity in the selection array, ...
# add to it the bounding box of each entity
selection.each { |ent| bbox.add(ent.bounds) rescue nil }
# Get the bottom front left corner as a Geom::Point3d
origin = bbox.corner(0)
# Use Ruby's multiple assignment
x, y, z = origin.to_a
# Add the instance
inst = entities.add_instance(definitions[0],[x+12,y,z])
# Set it selected
selection.clear
selection.add(inst)
As an aside … why did I use a rescue nil modifier within the each iterator block ?
(Cliick to expand answer ...)
Because I seem to remember in some SketchUp versions there being some strange object references held within either the selection or entities collections. So in the event that any of the entity items in the selection do not respond to a bounds method call, and a NoMethodError is raised, the rescue nil modifier will return nil for that iteration (which does nothing as the each iterator itself simply ignores the return values of the block’s iterative evaluations, and when done just returns the collection object itself, … in this case the selection.)
Thanks for the replies. First, to answer your question, Julia. I guess I assumed that it would return the selection’s origin. At this stage I wasn’t going to be too picky about which point it returns, I just wanted to learn how to return any point and then work from there. Also what I left out is that the selection would just be one component at this ‘point’ in time.
Thanks Dan. I’ve seen your replies to a lot of questions on this site and as I get deeper into this I will definitely absorb what I can from those answers. I’m going to give what you’ve shown me, a try, and I’ll get back to you with my results.
So we modify the above examples with a conditional if … else statement.
if selection.single_object? &&
selection.first.respond_to?(:transformation)
origin = selection[0].transformation.origin
x, y, z = origin.to_a
else
# Create a virtual bounding box
bbox = Geom::BoundingBox.new
# For each entity in the selection array, ...
# add to it the bounding box of each entity
selection.each { |ent| bbox.add(ent.bounds) rescue nil }
# Get the bottom front left corner as a Geom::Point3d
origin = bbox.corner(0)
# Use Ruby's multiple assignment
x, y, z = origin.to_a
end
What we are doing in the second term of the conditional expression is called “ducking-typing”.
(“If it talks or walks like a duck we can treat it like a duck”.)
We do this using one of Ruby’s object introspection methods …
Okay cool! Thanks! Gotta go to a birthday party for a couple hours and my wife won’t let me take my computer. I can’t wait to get back and play with this.
That worked great! Thanks Dan. That was exactly what I needed to see. Now for the fun of it. How can I make the model select the new instance of the component?