Return the x/y/z coordinates of a selection


#1

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.

model = Sketchup.active_model
entities = model.entities
selection = model.selection
definitions = model.definitions
selection = entities.add_instance(definitions[0],[selection.x+12,selection.y,selection.z])

Thanks for your help


#2

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?


#3

Given your previous …

model = Sketchup.active_model
entities = model.entities
selection = model.selection
definitions = model.definitions

… do the following …

# 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)

REF:


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.)


#4

For this method use instead of origin and one of the corners, …

# Get the center as a Geom::Point3d
center_point = bbox.center
# Use Ruby's multiple assignment
x, y, z = center_point.to_a

… then add the instance as above, … etc.


#5

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’ :slight_smile: 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.


#6

Oh okay then … lesson 3 …

The singleton Selection class has a boolean method to ask it if it is made up of one “thing” …

… and, groups and component instances have a geometric transformation that has a property getter method for it’s origin …

So we modify the above examples with a conditional ifelse 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 …

Since everything in Ruby is a subclass (descendant) of class Object, they all inherit this method.


#7

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.


#8

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?


#9

Kickass! Thank you. I’ll have some fun with this.


#10

Well, it is actually the application selecting using input from code or user.

I think you found the “kickass” answer at the bottom of the original example above.

# Set it selected
selection.clear
selection.add(inst)

#11

Yup. All of it was good.