How to select, push-pull, move and push pull? A new method test

Hi guys! Last time I was trying to create two boxes (wall layers) attached together by selecting a face. The method in Ruby was to select the face, push-pull, get vertices of the loop of the face, change coordination of the vertices that create a new face then push pull. I managed to do it with help from here. Really appreciate!

Now I am trying to use another method ‘Geom::Transformation’ to reach the result. The process is like: 1.select the face, 2.push-pull, 3.move the face, 4.push pull again. The direction of the push-pull and the move is the same. (please see image) The process might be simple in Grasshopper but not in Ruby.

In Ruby, I tried this code:

mod = Sketchup.active_model # Open model
ent = mod.entities # All entities in model
sel = mod.selection # Current selection

# Default values
material_1 = "CLT"
material_2 = "CLT"
thickness_1_prompt = 100.mm
thickness_2_prompt = 30.mm

# Create a new group for the face(s) selected by the user
only_faces = sel.grep(Sketchup::Face)
#mod.start_operation('Push_test_a', true)
only_faces.each do |f|
  group_1 = ent.add_group(f)
  f.pushpull(thickness_1_prompt)

  # Calculate the translation vector based on the push direction
  push_direction = f.normal # push-pull's direction 
  translation_vector_for_2 = push_direction.reverse * thickness_1_prompt # push-pull's vector 
  #translation_vector_for_2 = push_direction.transform(Geom::Transformation.scaling(thickness_1_prompt)) # another way

  # Create a transformation that represents the translation
  translation = Geom::Transformation.translation(translation_vector_for_2)
  

  # Transform the face by applying the translation transformation
  f.transform!(translation)

  # Push-pull the transformed face
  f.pushpull(thickness_2_prompt)
end

#mod.commit_operation('Push_test_a')

But it always shows the error: “Cannot convert argument to Geom::Vector3d” whatever I type for the vector

translation_vector_for_2 = push_direction.reverse * thickness_1_prompt

or

translation_vector_for_2 = push_direction.transform(Geom::Transformation.scaling(thickness_1_prompt))

I researched a lot but still stuck here. Anybody has any thought?
Thank you in advance!

The Vector3d #* method is used to compute the cross product between two vectors.
Where the parameter should be Geom::Vector3d, however you are using thickness_1_prompt = 100.mm which is a Length, not a Vector3d. That is a reason you get an error message.

I assume you want to set the vector length, so you need to use
the Vector3d #length= method to set the length of the vector.

translation_vector_for_2 = push_direction.reverse 
translation_vector_for_2.length = thickness_1_prompt

This line syntactically is “okay” (will not give an error), but be careful, how it works e.g.:

vector = Geom::Vector3d.new(0,0,1)
vector.transform(Geom::Transformation.scaling(25.4.mm))
=> Vector3d(0, 0, 1)

Transformation. scaling class_method

2 Likes

Hi, Dezmo, thanks for the reply.
Now I tried ‘length’ to move the selected face ‘f’ as you said and the modification is below.

mod = Sketchup.active_model # Open model
ent = mod.entities # All entities in model
sel = mod.selection # Current selection

# Default values
material_1 = "CLT"
material_2 = "CLT"
thickness_1_prompt = 100.mm
thickness_2_prompt = 10.mm

# Create a new group for the face(s) selected by the user
only_faces = sel.grep(Sketchup::Face)
#mod.start_operation('Push_test_a', true)
only_faces.each do |f|
  group_1 = ent.add_group(f)
  f.pushpull(thickness_1_prompt)

  # Calculate the translation vector based on the push direction
  push_direction = f.normal # push-pull's direction 
  
  translation_vector_for_2 = push_direction.reverse  # push-pull's vector
  translation_vector_for_2.length = thickness_1_prompt = 100.mm # Set the desired distance
 
  # Apply the transformation to the face
  face_2 = f.transform!(Geom::Transformation.translation(translation_vector_for_2))

  # Push-pull the transformed face by thickness_2_prompt
  face_2 = f.pushpull(thickness_2_prompt)
end

#mod.commit_operation('Push_test_a')

But now another problem comes that whatever I put ‘transform!’ or ‘transform’ for ‘face_2’, it gives me ‘undefined method ‘transform! (transform)’’ when I select the face in Sketchup and run the code. Do you think what the problem is or there are other methods to get the same result? Thank you!

The Sketchup::Face class does not have a transform nor transform! method.

Refer to the API documentation for what methods the classes have defined or inherited from their superclasses.

2 Likes

After checking again you original post… I would do something like this:

mod = Sketchup.active_model # Open model
ent = mod.entities # All entities in model
sel = mod.selection # Current selection
material_1 = "CLT"
material_2 = "CLT"
thickness_1_prompt = 100.mm
thickness_2_prompt = 10.mm
only_faces = sel.grep(Sketchup::Face)
mod.start_operation('Push_test_3', true)
only_faces.each do |f|
  group_1 = ent.add_group(f)
  f.pushpull(thickness_1_prompt)
  # find new face creted pararell to 'f'
  face_2 = group_1.entities.grep(Sketchup::Face).find{|face| 
    face.normal.parallel?(f.normal) && face != f
  }
  face_2.pushpull(thickness_2_prompt, true)
end
mod.commit_operation

Take attention of the Face #pushpull method second parameter… (for the second pushpull)

In addition, some mistakes:

__

The Face #pushpull method does not return a new face it returns nil.
If you want to retrieve the new face you should check e.g. my previous post…
__

The Model #commit_operation method does not have an argument.

2 Likes

Thank you for your reference. You code works partly. However I want to make the two faces into groups so that I can later on add components with definitions to them. And they are solid componets. For this purpose, I added ‘group_2’ to ‘face_2’ in your code.

mod = Sketchup.active_model # Open model
ent = mod.entities # All entities in model
sel = mod.selection # Current selection
material_1 = "CLT"
material_2 = "CLT"
thickness_1_prompt = 100.mm
thickness_2_prompt = 50.mm
only_faces = sel.grep(Sketchup::Face)
mod.start_operation('Push_test_3', true)
only_faces.each do |f|
  group_1 = ent.add_group(f)
  f.pushpull(thickness_1_prompt)
  # find new face creted pararell to 'f'
  face_2 = group_1.entities.grep(Sketchup::Face).find{|face| 
    face.normal.parallel?(f.normal) && face != f
  }
  group_2 = ent.add_group(face_2)
  face_2.pushpull(thickness_2_prompt, true)
end
mod.commit_operation

But something weird happened (see image): the first is the faces messed up in two groups. You could copy the code in SU to see how messed it is lol (hard to explain in texts) . The second is that ‘face_2’ is always based on origin (0,0,0) after adding ‘group’ to it. This issue you mentioned last time for me when I created face(group) by vertices but in this case for face, I tried but failed

Because previously I managed to move the coordination of vertices of a selected face towards a push-pull’s vector, and that becomes a new face by ‘add_face’ function, I am wondering if there are ways of directly moving the selected face, that is push-pulled first, towards the direction of push-pull. And after moving, it becomes a new face push-pulled again. As a result, they are two boxes next to each other. Then I can have better control of adding more faces with its thickness (push-pull) and definitions if they become components later.

Thank you!

Actually you added a new group to model entities, then you assigned the face_2 to that new group also. That face_2 is now assigned to two different entities collection, witch is “illegal”. You’re lucky that it’s “only” “weird happening” and the whole Sketchup didn’t fall apart… :wink:
(You also did not considered the group_1 own coordinate system I mentioned in you other similar topic…)

Here is one example how you can do it:

mod = Sketchup.active_model
ent = mod.entities
sel = mod.selection
thickness_1_prompt = 100.mm
thickness_2_prompt = 10.mm
only_faces = sel.grep(Sketchup::Face)
mod.start_operation('Push_test_4', true)
only_faces.each do |f|
  # Motto: You have to think ahead...

  # determine the selected face normal. Will be used
  # for moving the second group in a direction of pushpull
  move_vec = f.normal
  # set the length, so the mowing will be same 
  # as the first pushpull
  move_vec.length = thickness_1_prompt
  # create a transformation for move
  tr_move = Geom::Transformation.translation(move_vec)
  # create a group and add the selected face into it
  group_1 = ent.add_group(f)
  # "clone" that group, to same position as the original
  group_2 = group_1.copy
  # move the new group with the transformation calculated above
  group_2.transform!(tr_move)
  # get the face inside the second group
  face_2 = group_2.entities.grep(Sketchup::Face).first
  # make the pushpull's
  f.pushpull(thickness_1_prompt)
  face_2.pushpull(thickness_2_prompt)
end
mod.commit_operation

1 Like

Hi, Dezmo, Now I am able to create and modify the functions I prefer in Sketchup with this one. Thank you very much for helping me who is a beginner in Ruby. You are always very kind checking the problems, explaining the theories behind and even giving some references. All of these helped me gain a better understanding of how Ruby works in Sketchup so I could get a step further ! Thank you and others who helped me here @DanRathbun again!

2 Likes