Face#area weird behavior


Hello guys,

I’m dealing with a situation here, very strange. Trying to get the biggest areas of a furniture door, but… I can’t describe that with just words, I’ll try with pictures, have this selected furniture door (porta_esquerda = left door):

1st thing: the preview picture in component options it’s different.
2nd thing: When execute this code with door selected:

mod = Sketchup.active_model
sel = mod.selection
faces = sel[0].definition.entities.grep(Sketchup::Face)
max = faces.max_by(&:area)
faces_max = faces.select{ |f| f.area == max.area }
sel.add faces_max

The selection goes to the top and the bottom area:

But, if I select the front face and execute:

And after that, select the top face and execute the same code, the top face area is smaller than the front face area.

All entities of the entire component have his len’s applied with formulas. I think that, when execute a script he is picking the initial value of the component without formula applied.

What should I do?


[quote=“kimpastro, post:1, topic:14500”]
max = faces.max_by(&:area)
faces_max = faces.select{ |f| f.area == max.area }
[/quote] Perhaps:

max = 0
faces.each{|f| max = f.area if f.area > max }
faces_max = faces.select{ f| f.area == max }



Thanks for reply, but, same problem…


Somehow SU is still getting the original value of the entity, like if no formula had been applied.


Component instances can have a transformation applied. That is what dynamic components extensively use (they are often just scaled boxes.

It can be that the component options dialog shows a thumbnail of the definition (?).

Inside a component, all sizes are defined in the local coordinate system of the definition. If a component has a 10× uniform scaling transformation applied and you draw a 10 cm edge inside of the definition, the edge will for this specific instance look 10× as big. When reading a coordinate, length or area, you get it in the dimensions of the coordinate system of the definition.

However SketchUp has the habit that all coordinates, lengths and areas are reported with the active path’s transformation applied. So you have to be very careful what is the active context: In your above example, the active context is not the model, but the dynamic component instance. And you are requesting the area of a face within a transformed sub-component instance.

Can you please do this test: Double-click into empty space to go into global model context. Then check the area again. If there is a transformation on the dynamic component, it will be now different.


Ah, the definition is not transformed, and it reports areas from the definition.
Applying a transformation to an already calculated area is not trivial if the area is not axis-aligned, but in this case you could (under the assumption of axis-aligned faces) apply the instance’s transformation:

instance = sel[0]
t = instance.transformation.to_a
# Create a vector of each plane's scale: (zscale*yscale, xscale*zscale, yscale*xscale)
# Using the dot product with the normal, we can easily
# look up for the X_AXIS the first scaling factor, 
# for the Y_AXIS the second etc.
# We also take into account the uniform scale factor 
# that is sometimes set (last matrix element).
xscale, yscale, zscale, scale = t[0].abs, t[5].abs, t[10].abs, t[15].abs
area_scaling = Geom::Vector3d.new(zscale*yscale*scale, 
max = faces.map{ |face| face.area * (face.normal%area_scaling) }.max
faces_max = faces.select{ |f| f.area == max }

Does this work?
[Edit: fixed to absolute scales factors]


Thanks for both explanation.
I’ll try it now.


Double clicked in empty space then execute code, like picture. Is that what you’ve suggested?


That can only be seen when looing on the numerical value of the area… (By no output one knows nothing)
I think my second response gets nearer to the problem in this case.


Well, this actually is taking the correct area now, but when perform:

faces_max = faces.select{ |f| f.area == max }

The select, compare to the wrong values (the old ones), so I made this:

faces_max = faces.select{ |f| f.area * (f.normal%area_scaling) == max }

and the result is just one biggest face selected, the back one, (must to select both biggest):


Maybe the:

xscale, yscale, zscale, scale = t[0], t[5], t[10], t[15]

must get another indexes to the front side?


*The numerical is still old one.



 faces_max = faces.select{ |face| (face.area * (face.normal%area_scaling)).abs == max }

need abs, cause has negative numbers.
Thank you so much.