An efficient but robust algorithm for fixing reversed faces of a Solid

I use Solid Inspector a lot (one of my favorite extensions actually, and most useful) when I am manually modeling. However I’ve potentially encountered solid geometry (within my own plugins) that is unpredictable so now I need to write a compact and efficient way to check for reversed faces within a solid group and then correct them.

I can’t assume that any of the faces are correctly oriented, so I have to start with the assumption that any, all or none of the faces might be reversed.

At the moment I really don’t have a solid or good idea on how to approach this but I may post up a few sample blocks of code after some testing.

Do you know the principle of normal to the face ?

Here is what I have so far, but I do have to send it a seed face that is oriented correctly:


def fix_solid(group1, seed_face)
  faces = group1.entities.grep(Sketchup::Face)
 
  visited = {}
  queue = []

  visited[seed_face] = true
  queue << seed_face

  until queue.empty?
    current = queue.shift

    current_loop = current.outer_loop.vertices

    current.edges.each do |edge|
      edge.faces.each do |adjacent|
        next if adjacent == current
        next if visited[adjacent]

        adjacent_loop = adjacent.outer_loop.vertices

        # Find shared edge vertices
        v0, v1 = edge.vertices

        cur_idx0 = current_loop.find_index(v0)
        cur_idx1 = current_loop.find_index(v1)

        adj_idx0 = adjacent_loop.find_index(v0)
        adj_idx1 = adjacent_loop.find_index(v1)

        next unless cur_idx0 && cur_idx1 && adj_idx0 && adj_idx1

        cur_forward = (cur_idx1 == (cur_idx0 + 1) % current_loop.size)
        adj_forward = (adj_idx1 == (adj_idx0 + 1) % adjacent_loop.size)

        if cur_forward == adj_forward
          adjacent.reverse!
        end

        visited[adjacent] = true
        queue << adjacent
      end
    end
  end
end

Basically, the native Orient Faces function should work if the object is a manifold solid. I wonder if it can be accessed via Ruby.

1 Like

Try this:
To be a ‘proper’ solid each edge is part of two faces (duh) and will be used in the forward direction in one face and in the reverse direction in the other. If this condition isn’t true then one of the faces is misoriented.

Sketchup::Edge.reversed_in?

2 Likes

This is based on the face-to-face orientation method, which is not robust, since there is a risk of taking two incorrectly oriented faces as a reference. This is equivalent to the orient function with a right click on a face (which only works if you choose a correctly oriented face).

If the shape is a true solid, you can determine the correct orientation of a face.

  1. take one face
  2. take a half-line from the center of the face oriented along it’s normal vector.
  3. count the intersections with the other faces of the shape (use classify_point, and if the intersection point happens to be a vertex or on an edge , count it once).
  4. if the count is even (0, 2, 4), then the face is correctly oriented.

Then, you can propagate the orientation to the adjacent faces by using edge.reverse_in? method at their common edge.

2 Likes