Concavity problem and need help

Select an edge that connects two faces and then use the script below to verify the angle between the two face normals…Try to have face normals like in the example #1 and #2 in the picture above and you will see both puts 90 degrees.

model = Sketchup.active_model
selection = model.selection
edges = selection.grep(Sketchup::Edge)

edges.each do |edge|

  faces = edge.faces
  f1 = faces.first.normal
  f2 = faces.last.normal

  angle = f1.angle_between f2
  angle = angle * 180.0 / Math::PI
  puts "angle = #{angle}"


How can I make example #2 equal 270 degrees while example #1 still be 90 degrees?

Thanks in advance!

1 Like

You can compare the cross product of the face normals with the edge’s “actual” direction, with whether the edge is considered reversed in one of the faces.

# Assuming the faces are oriented the same way, the faces are not co-planar and
# the edge binds exactly two faces.
def concave?(edge)
  faces = edge.faces
  vector = faces[0].normal * faces[1].normal
  vector.samedirection?(edge.line[1]) == edge.reversed_in?(faces[0])

If the faces are correctly oriented any shared edge must be considered reversed in one of the faces but no the other, compared to the faces’ winding order. You can also check the “reversity” in relation the the second face, but then you must also swap the two faces when calculating the cross product (which reverses the product vector). What is the first and second face makes no difference, as long as it is internally consistent in the method.

In a real implementation you should also confirm there is only 2 faces bound by the edge, they are correctly oriented (the “reversity” of the edge differs between them) and the faces aren’t co-planar (the cross product of the normals bot being zero length).


By the way, a vector is merely a direction, meaning you can’t distinguish these 3 situations from looking at the normals alone. This is why also the common edge must be taken into consideration.



Can’t thank you enough!

I still have to wrap my head around why it works but I am happy it does…Thumbs Up!

Maybe these images help describing it.

The cross product of the two normals is the vector that is perpendicular to both of them (unless in the special case when they are parallel, then it is a zero length vector with no direction). What direction it has depends on the order of the multiplication, as cross multiplication is non-commutative. If A and B are swapped the cross product will be reversed.

Then there is the winding order of the faces, which is what defines the front and back side. Of we just reverse the faces convex becomes concave and vice versa. How the edge’s own direction relates to the winding order can be compared to how it relates to the normal cross product, to check if the edge is convex or concave.


The following should return an opposite value from each other…Got it!

edge.reversed_in?(faces[0]) #=> true or false
# vs
edge.reversed_in?(faces[1]) #=> false or true

First time I hear about faces having winding orders, but you explained that they are responsible for determining the face front and back site…Kinda got it but not so sure!

This is clear to understand and the images you posted helped a lot to visualize.

Following so far but because the order of multiplication is a little unpredictable it is kinda confusing.

I feel you’re giving me the answer in the above quote but I still don’t manage to figure out why the condition below figure its edge is concave.

vector.samedirection?(edge.line[1]) == edge.reversed_in?(faces[0])

Maybe it’ll hit me any moment…Thank you so much for explaining it!

I didn’t see any mention of the “right hand rule” when dealing with cross products …



Thanks for the tip!

I didn’t expect the cross product being so useful…Cheers!

As I am self-thought in linear algebra (I think this counts to that) I’ve not used that rule much, even though I learn a right hand rule in my physics class for currents, magnetic fields and forces.

I often think of it as X (red) * Y (green) = Z (blue), and the axes are positioned as in a non-mirrored SketchUp model or component. After 10 years I know those axes very well :stuck_out_tongue: .

Cross products are wonderful little puzzle pieces that can be used to solve almost every geometrical problem!