Hello everyone,
I have been using the following script written by @sdmitch. It will take the selected components in the model and place them on the ground plane with the blue axis facing up in a neat little row. Very useful for CNC machining etc. However, it also resets the scale of any component it finds.
From my reading of the Ruby docs, it appears that the ‘transformation.inverse’ method is responsible for resetting the scale, among other things.
I am wondering if there is a modification to this script that would allow a component to retain its scale but still perform the same rowing function. I’ve been trying to play around with the script with no immediate success, so I need some help from one of you Ruby geniuses!
Thanks in advance.
mod = Sketchup.active_model
ent = mod.active_entities
sel = mod.selection
SKETCHUP_CONSOLE.clear
org = Geom::Point3d.new()
spc = 2.cm
cdn = ent.grep(Sketchup::ComponentInstance).map { |ci| ci.definition.name }.uniq.sort
cdn.each { |n|
cis = ent.grep(Sketchup::ComponentInstance).each { |ci|
next unless ci.definition.name == n
ci.transform! ci.transformation.inverse
ci.transform! Geom::Transformation.translation(org - ci.transformation.origin)
if ci.bounds.width > ci.bounds.height
ci.transform! Geom::Transformation.translation(org - ci.bounds.corner(2))
ci.transform! Geom::Transformation.rotation(org, Z_AXIS, 90.degrees)
end
if ci.bounds.depth > ci.bounds.width && ci.bounds.depth > ci.bounds.height
ci.transform! Geom::Transformation.rotation(org, X_AXIS, 90.degrees)
end
if ci.bounds.min.y < org.y
ci.transform! Geom::Transformation.rotation(org, X_AXIS, 180.degrees)
ci.transform! Geom::Transformation.translation(org - ci.bounds.corner(0))
end
org.offset!([ci.bounds.width + spc, 0, 0])
}
}
This might point you in the right direction (pun intended).
Below is some highly untested code.
# Get the first instance in the model
mod = Sketchup.active_model
ent = mod.active_entities[0]
# Print the transformation
tr = ent.transformation
tr.to_a.each_slice(4){ |slice| p slice }
# determine the Translation and Rotation matrix of the instance
tr_T_R = Geom::Transformation.axes(tr.origin, tr.xaxis, tr.yaxis, tr.zaxis)
# transform by the inverse matrix
# -> this should result in a scaled instance of the object at the origin of the model.
ent.transform!(tr_T_R.inverse)
# print the resulting transformation
puts
tr = ent.transformation
tr.to_a.each_slice(4){ |slice| p slice }
I appreciate your contribution. However, it is the ‘.inverse’ operation that resets the scale of the selected component.
For example, I have a component instance whose container has been manually scaled after it was originally defined as a component, using the scale tool. Let’s say this component now has a scale of -1 (essentially a reflected component). Applying the inverse transformation method will result in a scale component = 1. Therefore, the transformed component will have its original scale.
I want to keep the scale factor of -1 (for example) when changing the rotation and position of said component, to orient it with its blue axis aligned with the global blue axis… And in case of many components, distribute them in one row.
The original script I posted does a pretty good job of this, except that it resets the scale of any component in the process.
I hope I have clarified.
The published script acts on ALL the instances in the active entities of the model.
it does No it looks like it groups the instances of the select set.
Do you have a lightweight example model to try? Please add to the initial post.
1 like
Attached is an example file containing a group that has been scaled in the X, Y, and Z directions by factors of -1, -2, and -3 respectively. And below is the code to extract those constants from the group transformation matrix.
Matrix example TRS.skp (104.2 KB)
# Get the first instance in the model
mod = Sketchup.active_model
ent = mod.active_entities[0]
# Print the transformation
puts "Initial Transformation:"
tr = ent.transformation
tr.to_a.each_slice(4){ |slice| p slice.map{ |value| value.round(4)}.join(" ") }
puts "\nGroup's Axes:"
p tr.xaxis
p tr.yaxis
p tr.zaxis
axis_x = tr.xaxis[0] >= 0.0 ? tr.xaxis : tr.xaxis.reverse!
axis_y = tr.yaxis[1] >= 0.0 ? tr.yaxis : tr.yaxis.reverse!
axis_z = tr.zaxis[2] >= 0.0 ? tr.zaxis : tr.zaxis.reverse!
# determine the Rotation * Translation matrix of the instance
tr_T_R = Geom::Transformation.axes(tr.origin, axis_x, axis_y, axis_z)
ent.transform!(tr_T_R.inverse)
# print the transformation
puts "\nResulting Transformation:"
tr = ent.transformation
tr.to_a.each_slice(4){ |slice| p slice.map{ |value| value.round(4)}.join(" ") }
puts
puts "X scale = #{tr.to_a[0].round(4)}"
puts "Y scale = #{tr.to_a[5].round(4)}"
puts "Z scale = #{tr.to_a[10].round(4)}"
I wrote a sample plugin to do this, so you won’t need to cut and paste large blocks of code into the console.
The above code is still there wrapped in the ” methodold_way()
” for nostalgia, but the extension doesn’t use it.
I wrote a completely new method to move selected instances that don’t No wear transformation.inverse
.
Besides:
- It remembers the last space used, allowing it to be set via an input box.
- The changes are wrapped in an undo operation.
- The command appears on the Extensions menu and on the
right-click the context menu if instances are selected.
See: [Example] Place a set of selected instances in a row along the X axis