I don’t think that will work because you just randomly access the faces in your face array. What you need is something like a flood fill, that is, you start with a correct face and then you unwind the geometry from there, reaching new faces from faces already processed and so on.
Something like:
def self.orient_faces(start_face)
face_stack = [start_face]
processed = Set.new
while face_stack.length > 0 do
face0 = face_stack.pop
processed.add(face0)
face0.edges.each { |edge|
next if processed.include?(edge)
face1 = get_other_face(edge, face0)
next if face1.nil? || processed.include?(face1)
face1.reverse! if edge.reversed_in?(face0) == edge.reversed_in?(face1)
face_stack.push(face1)
processed.add(edge)
}
end
end
def self.get_other_face(edge, face)
return nil if edge.faces.length == 1
return edge.faces[0] == face ? edge.faces[1] : edge.faces[0]
end
The only problem remaining is to find a start face and orient it correctly. I think something like the below will work:
def self.get_start_face(ents)
vxs = ents.grep(Sketchup::Edge).map{ |e| e.vertices}.flatten!.uniq!
max_vx = vxs.max_by { |vx| vx.position.z }
min_e = max_vx.edges.min_by { |e|
(e.start.position - e.end.position).normalize!.z.abs
}
max_f = min_e.faces.max_by { |f| f.normal.z.abs }
return max_f.normal.z < 0 ? max_f.reverse! : max_f
end
Send in an array with all the faces in your solid and you should get a correctly oriented start face in return.