Add Face returns nil!

The Docs state that entities.add_face returns a Sketchup::Face or nil.

However there is no indication what the conditions are that return nil.
I understand that exceptions are raise for duplicate points in array, or if points are not planar., but I’m having trouble understanding why I get nil instead of a face.

Here is my model.

test1.skb.skp (928.1 KB)

And here is the code that is confusing me.

    porch = Sketchup.active_model.entities.grep(Sketchup::ComponentInstance).select {|c| c.definition.name == 'Porch#4'}[0]
    door = Sketchup.active_model.entities.grep(Sketchup::ComponentInstance).select {|c| c.definition.name == 'Door#1'}[0]
    points = [[240.0, -120.0, 138.0],
      [120.0, -120.0, 158.0],
      [0, -120.0, 138.0],
      [0, -120.0, 137.98333333333332],
      [0, -120.0, 138.0],
      [240.0, -120.0, 138.0],
      [240.0, -120.0, 137.98333333333332]]
    face = porch.definition.entities.add_face(points)
    puts 'Why is face nil when drawn in porch component?' if face.nil?
    face = door.definition.entities.add_face(points)
    puts 'But not when draw in door component?' unless face.nil?

Tested on SU 17,18, and 20

Another thing that seems really weird is that after the nil face, the Sketchup operation is aborted, but the code continues. What is really weird about this is that the code continues after the abort, but when commit_operation is called everything that was done is lost.

  1. It seems like the transaction is aborted at the same time that the nil face is created. This is observed by calling get_attribute for the component instance, and seeing that the attributes are reset to the state before the operation started.
  2. Everything that happens between the time the nil face is ‘created’, and the time commit_operation is called, is also lost.

I’d really like some insight on this, because at the moment is seams like a SketchUp bug. Even if it is a bug I need to figure out what is causing it so I can prevent it from happening.

PS. I’ve got 200 lines of code to build the list of points, and this is the one and only configuration that causes a problem.

The only difference I can see between your two components is that one is cutting and glueing and the other isn’t. If you change the axes of the porch so the blue axis points out from the wall, your code creates faces in both components. I noticed the blue cross was at the axes in the door, but not the porch. After changing the axes of the porch, you only see that cross on newly placed copies dragged from the component browser, but your code still makes a face in the porch without dragging a new copy out.

Door Cutting

porch-new-axes

porch-copy-cutting

I can’t answer your question.

Your points data is weird though,isn’t it? Here are indices 2, 3, and 4. The points at 2 and 4 are the same with 3 just all alone creating coincident edges. I’m not sure you can expect predictable results from the input.

Also, the length of that lonely edge is very close to SketchUp’s minimum tolerance. Maybe something is getting automatically merged when adding the face.

2020-05-23_100322

The problem is related to conflicting geometry. I’m trying to figure out why & how to check for it.

    porch = Sketchup.active_model.entities.grep(Sketchup::ComponentInstance).select {|c| c.definition.name == 'Porch#4'}[0]
    points = [[240.0, -120.0, 138.0],
      [120.0, -120.0, 158.0],
      [0, -120.0, 138.0],
      [0, -120.0, 137.98333333333332],
      [0, -120.0, 138.0],
      [240.0, -120.0, 138.0],
      [240.0, -120.0, 137.98333333333332]]
    face = porch.definition.entities.add_face(points)
    puts 'Conflicting geometry must be causing the nil face?' if face.nil?
    tr = Geom::Transformation.new([0,12,0])
    porch.definition.entities.transform_entities(tr, porch.definition.entities.to_a)
    face = porch.definition.entities.add_face(points)
    puts 'Face is created fine if there is no conflicting geometry present.' unless face.nil?
    tr = Geom::Transformation.new([0,-12,0])
    porch.definition.entities.transform_entities(tr, porch.definition.entities.to_a)

I’ve found the condition the was causing the unneeded points and fixed it. That of course took care of the issue. I guess ‘garbage in garbage out’ might be the only answer in this case.

The results are definitely weird and unexpected. It would have been nice to see some type of error, rather than such funky abortion of the operation. This way it took me quite a bit of time to find the issue.