Transformations and Efficiency

When it comes to multiple transforms to an object I realize that one can consolidate multiple transforms into a single transform but I am wondering if it is more efficient. In other words I want to apply three different transforms as my code suggests below but would it be better to consolidate the three transforms into one and then transform only once?

tr1 = Geom::Transformation.new([xtransl, ytrans, ztrans])
vbarinstance1 = Sketchup.active_model.active_entities.add_instance(vbar_comp, tr1)
vbarinstance1.name = "REBAR VERT #{secnum}-#{vbarcount}"

tr2 = Geom::Transformation.rotation(origin, Z_AXIS, angle)
vbarinstance1.transform! tr2

tr3 = Geom::Transformation.new(pt0)
vbarinstance1.transform! tr3

And I might add that the order in which the transforms are applied does matter, but I think this is not a problem if I consolidate the transforms carefully. Which brings me to the next point, what would be the correct syntax to consolidate the transforms in order. I need them transformed in this order tr1 → tr2 → tr3

A transformation is internally a 4x4 matrix. Concatenating two transformations therefore costs the same as multiplying two 4x4 matrices. Applying a transformation to a coordinate point costs the same as multiplying a 4 element vector by a 4x4 matrix: 1/4 as much as concatenating. So on the face of it, it is faster to apply three transformations in succession than to concatenate them and apply the result. But…the devil is in the details:

  • It should be obvious that if you will be applying the same transformation to a lot of entities, building it just once and reusing it will be faster.
  • Even better is to use one of the API methods that applies a transformation to a collection of entities, such as Entities#transform_entities. That moves the heavy work off to C instead of Ruby.
  • Transforming a complex entity implicitly requires transforming each of its vertex coordinates. If the entity has a lot of vertices, that may offset the 4x matrix multiply difference for building a composite transformation. Said another way, the cost difference may depend on what you are transforming.
  • Transforming an entity requires that SketchUp updates the entity’s values in the database. That could conceivably cost more than the matrix multiplies, in which case the whole question becomes moot.

The bottom line is that you need to perform actual timing comparisons to be certain which is faster in your specific situation. Guessing in advance is what we used to call “premature optimization”!

3 Likes

Yes because this creates only 1 operation on the undo stack instead of 3.

Within your module …

ROT_90_ABOUT_Z ||= Geom::Transformation.rotation(ORIGIN, Z_AXIS, 90.degrees)
2 Likes

I didn’t know there was a built in 90 deg transform about the Z axis, again I learn something new everyday.

There is not. I did say … “Within your module” … meaning that YOU can locally define a constant at the top of YOUR plugin submodule and use it again and again as needed.

Or if you’d rather …

  def rotate_90(sym)
    case sym
    when :x, :X
      axis = X_AXIS
    when :y, :Y
      axis = Y_AXIS
    else
      axis = Z_AXIS
    end
    Geom::Transformation.rotation(ORIGIN, axis, 90.degrees)
  end
1 Like

In general; bulk operations are faster. Whether it’s modifying geometry, selection or drawing to the viewport. Passing bulk data to SketchUp allows SketchUp to perform more optimized operations.

For the specific cases; time and profile. There are so many subtle different ways to do things in Ruby that can affect performance. (For instance, size and length is faster than count because count will iterate each item in a collection while size and length just query the known size.)

2 Likes

That would be:

vbarinstance1 = 
   Sketchup.active_model.active_entities.add_instance(vbar_comp, tr3 * tr2 * tr1)

In Sketchup for the above example, tr1 will be applied first, followed by tr2 and tr3. That is for development environments that internally store transformation arrays by column major order. Some development environments use row major order (e.g. Autodesk’s Maya®) and the multiplication order would need to be reversed.

Given that order, I would recommend that the initial transformation be any scaling, followed by rotation(s), and finally translation (i.e. positioning).

2 Likes

I think an important question here is what the transformation(s) represent, and what makes the code easiest to understand when looking at it later. Is it a single positioning of an element? If so I’d make it one transformation and give that variable a name that describes what the position means.

1 Like