Hi All,
I’ve been using the following script written by @sdmitch. It will take any selected components in the model and lay them out on the ground plane with blue axis facing up in a nice neat little row. Very useful for CNC machining etc. However, it also resets the scale of any components it encounters.

From my reading of the Ruby docs, it appears the ‘transformation.inverse’ method is responsible for resetting the scale, among other things.

I’m wondering if there’s a modification to this script which will allow a component to retain it’s scale but still perform the same lay-them-out-in-a-row out function? I’ve tried tinkering with the script with no immediate success so I need the help of 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).

Some highly untested code follows.

# 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 input. However, It is the ‘.inverse’ operation which 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 us say this component now has a scale of -1 (essentially a mirrored component). Applying the inverse transformation method will result in a component of scale = 1. Thus, the transformed component will possess it’s original scale.

I’m wanting to retain the scale factor of -1 (for instance) while changing rotation and position of said component - to orientate it with its blue axis aligned with the global blue axis… And in the case of many components, lay them out in a row.

The original script I posted does a pretty good job of this - except it resets the scale of any component in the process.

Attached is an example file that contains one group which has been scaled in the X, Y, and Z directions by factors of -1, -2, and -3 respectively. And below that is the code to extract those constants from the transformation matrix of the group.

Hi DanRathbun, you’ve really gone the extra mile here in wrapping the script into an extension and so I thank you very much for your effort already. Only problem is that your extension also resets the scale of a component too! Best way to illustrate this is with a video…

Well, it is version 1.0.0. (I’ve made a note of this known issue in the example post.)

I did ask for a test model. I created one but I did not test a negative scale only positive scales in one or more axis. So next version would be to handle negative axis scaling.

Here’s a longer video showing the issue in more detail. In the video, the two parts I move to the foreground are opposing. That is, the right side part is simply a mirrored instance of the left. When I run the original script, or yours, I’m left with two ‘unscaled’ parts. That is, the right side part has lost its -1 scaling.

Hopefully this will illustrate why a working script is a major time saver for CNC machining. Once the parts are laid out flat, the final step is to export a 3D DXF and then clean up the layering in the CAM software.

Attached is a model containing two pairs of mirrored parts.

Also I see that the parts seem to be arranged with their short side along the X axis. I did not do this either. I did see some comparison of bounds width vs height in the original script but did not understand what it was for.

What I find is that the parts are not really mirrored per the transformation, (ie, one negatively scaled from the other.) Instead they show as rotated opposite each other about the Z axis. (Both have a positive 90 deg X rotation. One has a positive 90 deg Z rotation, the other -90 Z rotation.)