What to expect from a face when drawing lines along its plane

When drawing shapes from the GUI, it seems that faces are filled in more automatically than when creating the shapes from ruby. When producing shapes from ruby, when should I expect a face to be created automatically? And when a face exists, and I draw lines through it, when and how should it be sliced up into individual faces?

In this short example, I create a hexagon, fill it in with a face and then draw a circle inscribed inside the hexagon. This is the part of constructing a nut or bolt. I would hope and expect that the face would be sliced up into one new circular face and 6 small triangular faces around the perimeter. But this does not happen. What is worse, is that one triangle does get sliced off. This seems a bit random to me and I’m not sure why or how to create predictable behavior.

Is this because the points of the circle don’t line up exactly with the bisectors of the hexagon segments (i.e. very small floating point errors)? Or is there something else going on?

To see the problem, run this script and then try selecting faces on the plane. Notice that if you create the inscribed circle from the GUI, the face gets sliced up correctly. It is only when I create the circle from ruby that it doesn’t work right? Is there some kind of “cleanup” routine that gets called when using the GUI to check existing faces for bisecting lines?

#Test problem with intersecting points
require 'sketchup.rb'

model = Sketchup.active_model
ents = model.entities

w = 1.625                                       #Width from flat to flat on hex
r = (w / 2 / Math.cos(30.degrees))              #Radius of inscribed circle
n = ents.add_ngon([0,0,0], [0,0,1], r, 6)    #Make the hexagon
f = ents.add_face(n)                            #Fill in with a face
c = ents.add_circle([0,0,0], [0,0,1], w/2, 12)  #Make inscribed circle

Yes, there is a cleanup that gets called in the GUI each time the user completes an action but does not get called consistently when equivalent actions are performed via Ruby. The cleanup finds intersections, creates faces, removes duplicates, merges vertices that are too close, etc. There are some API calls that seem to trigger cleanup, but may others that do not, and there is no method in the API to explicitly request cleanup.

The simplest example may be this: try drawing two edges that intersect each other. In the GUI you will have four resulting edges since each is split where they intersect. In Ruby you will get only the two undivided edges you created.

It can be argued that having the API methods “close to the metal” avoids building in assumptions about what the coder is trying to achieve and avoids inserting a potentially expensive cleanup operation in the midst of code. When a user draws in the GUI, he can’t work fast enough to keep up with the cleanups, so the expense isn’t an issue. But when a Ruby creates entities, it can go much faster, so cleaning up repeatedly might dramatically slow an extension.

However, it can equally be argued that inconsistencies between what happens in the GUI and in the Ruby API just cause needless confusion and require extra effort from coders who struggle to get a desired result that is easy in the GUI. There are various extra steps (e.g. invoke find_faces on the edges at the end of your snippet) that “fix” the differences and tricks that experts have accumulated over the years. But I don’t know of any place that collects this lore together.

A couple of years ago I submitted a feature request to add a cleanup method to the API. I had trouble convincing the SketchUp team it was needed, and so far the request has been ignored.

Thanks for the reply. It worked fine iterating around the hexagon and using edge.find_faces explicitly. I’m fine with the philosophical decision to not find faces automatically. What seems random to me is that it automatically finds one of the faces, but not the others. Seems like it should find none or all in order to more predictable.

You’ll get no argument from me! There are a lot of ways in which the Ruby API and its documentation are lacking.