Ruby API: face and push/pull direction inconsistent

I’m using a script to draw some solids using faces and push-pull. It appears there is a strange and un-expected corner case behavior. A positive push-pull distance is normally drawn in a positive Z direction (for faces in a plane parallel to the XY plane). But, when the faces is actually in the XY plane (Z=0), that
direction is reversed. I’m guessing the face and back face are swapped.

The following code file demonstrates the behavior. Simply open the Ruby console and load the code from a file. The red cylinder shows the “problem”. Is this intentional ? Does it make sense for some reason ?

=begin rdoc 


================================================================
 SketchUp strange behavior (from Ruby API).

 A cylinder can be drawn by drawing a circlular face, then 
 performing a push/pull to a specific height.  This can all 
 be done from a Ruby script.  But there seems to be an odd
 corner case in the way the API works.  The direction of the 
 face seems to depend upon the Z coordinate of its origin.
 If this coordinate is 0, the direction is reversed.
 ================================================================
=end


=begin rdoc 
 ================================================================
 Method:  cylinder
 
 Creates an empty group in the entities for the active model, 
 then adds cylinder entities to that group.  The cyliinder has
 a vertical axis. 
 
 Arguments: 
   * origin    3dPoint at center of bottom face of cyliner
   * radius    radius of the cylinder 
   * height    height of the cylinder
   * material  color of the cylinder 

 ================================================================
=end


def cylinder( origin, radius, height, material ) 
  group = Sketchup.active_model.entities.add_group 
  entities = group.entities
  up = Geom::Vector3d.new(0,0,1)
  # Call methods on the group's entities collection to draw a 
  # circle perpendicular to the specified axis 
  circle = entities.add_circle origin, up, radius
  face   = entities.add_face( circle )
  face.material      = material  
  face.back_material = material  
  face.pushpull height
  #
  return 
end # method    


=begin rdoc 
 ================================================================
                             Main

                         
 3 identical cylinders are drawn to show how the direction of 
 the push/pull differs when the face is at Z=0. The Red cylinder
 is the oddball.                             
 ================================================================
=end

#
# 3 cylinders will be drawn.  They are parametrically identical
#
radius   =  10                 # radius of all cylinders
height   =  50                 # height of all cylinders

#
# The cylinders are spaced out in the XY plane (they all have 
# vertical axes).  The only difference is the polarity of the
# Z coordinate of the origin.
#
spacing  =  4 * radius         # XY spacing between cylinders 
center  =  [] 
center[0] = Geom::Point3d.new(1*spacing,1*spacing,-10)
center[1] = Geom::Point3d.new(2*spacing,2*spacing,  0)
center[2] = Geom::Point3d.new(3*spacing,3*spacing, 10)

#
# Draw the 3 cylinders
#
cylinder( center[0], radius, height, "Green" ) 
cylinder( center[1], radius, height, "Red" ) 
cylinder( center[2], radius, height, "Green" )

SketchUp perform some exceptions to its rules some times. This include the ground plane. When you draw a face on the ground plane it always face down. And while I don’t have a full overview of all the quirks, I’m not surprised if PushPull also has some.

Thomas, the z=0 quirk is well known among developers, but do you know if it is officially documented anywhere?

As far as I’m aware of, I don’t think it’s mentioned in the API docs anywhere.
It’s a side effect of the underlying push pull tool - not a contract the API declares.

To quibble, it’s a surprise effect of creating any Face at z=0. Push/pull is just an innocent bystander!

I’m certainly not the expert on this, but I have, um, …“history” on my side. I believe it’s because of the typical user pattern: draw a face on z=0, then push-pull in the positive z direction, expecting the style’s front color to be displayed. It wasn’t, and people were having to reverse faces. We saved them the trouble.

Trouble is that this behaviour was exposed to the API - where it’s quite often a noisy obstacle.
Though changing it now would break all kinds of extensions.

True that, though cautious developers learned long ago to test the direction of the normal before doing a push-pull and reverse either the face or the push/pull direction before the operation.

Yea, that is the safe way to do it - but you know people will cry murder if we change it. Optional argument is possible - oh the joy of API clutter due to compatibility.

Thanks to all of you for the explanations. I guess you guys are well aware of this “quirk”. I thought it might be a bug, and am a little surprised to hear that it was intentional. But i have been using the API exclusively, and have hardly any experience using the GUI. So it may in fact be a beneficial work saver.

From my perspective just a clear description of the rules for face reversal in the API would have saved me a lot of time and effort. First i had to debug my bad results down to the API. Then i had to experiment with a ton of cases to figure out what i thought the trigger was. I would suggest this info be added to the docs both under the Face class, and perhaps under Entities.add_face().

Now that you have provided that info i have already solved my problem. I just coded a little operator method to “fix” the face orientation. It grabs the normal vector from the face, and a (the first) vertex. If the Z coordinate of the normal is 1, and the Z coordinate of the vertex is 0, it does a reverse! on the face. I always call the method everywhere i create a face for push-pull. This way i get consistent behavior (up is always up).

I’m creating an issue to improve the Ruby API for add_face to describe this quirk. You’re absolutely correct - if you haven’t been a user of SketchUp you would never have observed this behaviour.

Thanks API-Ites, I thought it was my new computer, OPENGL, …as my fixes to assure no z=0.000000 I am from the school, how could they be wrong after umpteen releases. API is short for APItite, and hunger is needed to secure every victual crumb into its dispensing!