2

I am working with a serialization pipeline. I am taking a model and exporting it. I do not wish to export any model with a hole in a face. How would I detect a hole and report a error?

I have access to all vertexes, edges, faces etc.

Here is a picture of what I mean.

Hole in face

As you can see there is a hole in the face. I am fairly new to geometry so please try to explain in layman terms.

marsh
  • 2,191
  • 4
  • 26
  • 46
  • 1
    What type of model is it? Your tags indicate that that it is a mesh, but the concept of hole in a face is more in keeping with a boundary representation. – Codie CodeMonkey Jun 12 '15 at 20:21
  • 1
    This can become a good question, the OP just needs to provide more details. Let's not be too quick to close it. – Codie CodeMonkey Jun 12 '15 at 20:22
  • As I said I am fairly new to this kind of thing. I am simply creating a cube in Maya and then using a boolean difference to create the hole. I am then exporting it by getting the information from the Maya sdk. I am aware of the MItMeshPolygon.isHoled() method. This works but I need to do this from Max and many other programs so it has to be agnostic. – marsh Jun 12 '15 at 20:25
  • 1
    Unfortunately, the representation of the model is essential to answering this. For example, if the model is a single mesh, I would suggest finding "open edges" which are edges that are used by exactly one triangle. If the faces are planes with boundary loops, I would look for loops are clockwise oriented with respect to the face normal, etc. – Codie CodeMonkey Jun 12 '15 at 20:32

2 Answers2

5

If a 3D object is "simple", meaning that it doesn't have holes, it satisfies Euler's Formula for Polyhedra, V - E + F = 2 where V is the number of vertices in the figure, E is the number of edges, and F is the number of faces. If you can easily obtain those three numbers, you can calculate the formula V - E + F. If the result is not 2, the object has a hole (or some other pathology like a pinch). In fact, you can tell how many holes the object has by V - E + F: if the number is 0, it has one hole; if the number is -2, it has two holes; etc.

Calculating V, E, and F can be a little tricky because vertices are generally shared by two or more edges, and edges are generally shared by two faces. You don't want to overcount; if three edges meet in a single vertex, you only want to count the vertex once, not three times.

Not only that, but it's easy to make a mistake counting when the shapes have holes (which is exactly the case you're interested in). The easiest way to avoid making a mistake is to break the figure up into convex parts with e.g., triangulation.

The formula doesn't tell you which face has the hole, but if you know that the figure has a hole you can apply Euler's formula to each face individually, again with triangulation. In that case, faces without holes will have V - E + F = 1 where V,E,F are now restricted to the face in question. (the discrepancy with the previous formula is resolved if you count the region outside the face as another (infinite) face). Faces with holes will have V - E + F < 1.

For example, a triangle on the plane has V=3, E=3, and F=1 (the "face" of the triangle represented by its interior) giving V-E+F=1. On the other hand, a triangle with a similarly shaped triangular hole inside, in which corresponding vertices of inner and outer triangles are connected, will have V=6, E=9, and F=3 for V-E+F=0. I have broken the figure into three convex quadrilaterals in this case.

Most books on computer graphics have a discussion of this topic.

Edward Doolittle
  • 3,770
  • 2
  • 12
  • 24
  • When doing the check on a single face, you say "where V,E,F are now restricted to the face in question" So is F now 1. The face in question? Or is it still the number of total faces? – marsh Jun 15 '15 at 17:27
  • If you're talking about the front face in the rendering you posted, then V,E,F would be counted just from that face. You have to make sure that you're including all edges and all vertices incident with the face, of course. F would not include any of the other five major faces of the figure, nor any of the rectangular bits inside the hole. However, F should not be 1, either. You need to break the face up into convex pieces; I recommend you triangulate it. That will break up the face into multiple triangles (each of which contributes to F) and add more edges and maybe vertices too. – Edward Doolittle Jun 15 '15 at 19:43
3

If I understand correctly, you want to detect polygons with holes. Now how polygons with holes are represented can vary with each software (some store separate internal contour lists). However, a common representation in 3D packages (including formats like OBJ) use a flat face vertices representation which tends to look like this:

Holeagon ... where 2,6 and 1,7 would be the same vertex index stored twice in the same polygon (the numbers in the picture indicate face point indices). Note that this edge from 1,7 to 2,6 could be hidden in some software, but it's there even if it's not visible if the software stores polygon vertices in a flat list of indices/pointers.

So a quick way to tell if a polygon has a hole with such representations given only face data (ex: from an OBJ file) is to see if it has duplicate entries for the vertex indices. If the same vertex index is repeated more than one time in a polygon, then it has a hole.

Now there is a case where you can find duplicated vertices for an empty inner contour, like so:

Holeagon2

... where 2,4 are welded (same vertex). If you want to distinguish these cases, you can detect them when the edge connecting exterior contour to interior contour only has one vertex duplicated instead of two. In that case, the interior contour is empty and this polygon is just a funky one (perhaps created through a CSG/plane slicing operation).

If you want a really robust solution, it's worth writing a routine that "unflattens" these flat contour lists into multiple interior/exterior groups by splitting the list apart where the duplicate edges connecting one contour to another are found. If the interior groups have fewer than 3 vertices, then they're probably just funky polygons without a visually noticeable hole. If they have 3 or more, then they meet the criteria required to show a hole which you can see visually. In cases where the interior contours don't form a full-fledged hole, you can just toss the interior contour and keep the exterior contour (in which case it's like just keeping the 3-point triangle exterior in the above pic while tossing out those redundant vertices, kind of cleaning up the geometry in the process and giving you the triangle formed from {1, 2/4, 5}).

A simple solution you can apply if you don't mind exporting unwelded geometry as long as it isn't funky (no holes or interior contours) is to simply clone (make unique) vertices that are duplicates in a polygon, basically unwelding it, like so:

Holeagon3

That's a little easier than a full-blown tessellation kind of solution, and it still ends up giving you polygons without any holes or separate interiors. I visually moved 2 and 4 apart for the sake of demonstration to emphasize that they're now separate vertices, but you don't have to do that (they can be coincident).

This kind of unwelding technique is also useful if you have a tessellator that doesn't support holes. You can apply this technique to unweld the polygon, tessellate it, then weld/merge back coincident vertices to give you the final result.

  • Yes, I am currently doing that check. But it could also just be a problem with the geometry and not necessarily a hole. – marsh Jun 22 '15 at 16:44
  • 1
    Typically if you find this kind of duplicated vertex index, there's an outer edge connecting to an inner contour. You can get such a result also if there's a slice but not inner contour in which case you can imagine like a polygon that isn't all one piece (not a circular loop) but unfolds into a flat segment. That's still somewhat like a hole even though there isn't one carved out, and can likely trip up importers that don't support holes -- so you might want to tessellate those duplicate vertex cases anyway, even if they don't visually look like a hole. If you want to restrict it only to... –  Jun 22 '15 at 16:46
  • 1
    ... cases where there is an actual hole carved out, then you can see from the diagram above that a hole would continue to define additional vertices past the edge connecting exterior to interior with the duplicates vertices. If there are no additional vertices there, then the polygon is just split without an actual hole. –  Jun 22 '15 at 16:48
  • Like if you see a case where there's {1, 2, 3, 4, 5, 6, 7, 8, 5, 4} then it has an actual hole. If you see a case where it's like {1, 2, 3, 4, 5, 4}, then it's just hole-like without a hole carved out (there is an inner contour, but it's empty). –  Jun 22 '15 at 16:49
  • 1
    But that duplicated edge is what connects inner contour (hole) to outer contour. If you want to write like a general-purpose function, the goal is to separate the inner contour from the outer contour into two or more separate contour lists. If the contour is empty, then there is no visual hole, but there is an empty inner contour. If the inner contour is non-empty, then it has a visual hole. –  Jun 22 '15 at 16:51
  • 1
    Updated the answer with a pic to show how to distinguish those empty interior cases. It's easier to explain these things visually (at least for me). –  Jun 22 '15 at 17:03
  • And another with a simple solution to make a robust exporter if you don't mind exporting unwelded geometry (users can auto-weld/merge back if their software supports holes). –  Jun 22 '15 at 17:29