[World] Solid Progress

Daniel Phillips phillips at phunq.net
Sat Jul 7 15:09:41 PDT 2012


Progress marches on

Progress continues on mesh intersection. I expected this to be a challenging 
project, and it is. But the rewards of producing a fast, powerful and reliable 
mesh intersection algorithm are large. For one thing, this will support a 
simple, intuitive solid modeling editor design  I intend to demonstrate that 
as soon as I get through the tedium of turning that nice clean algorithm that 
works well for non-degenerate cases into a less clean but far more useful 
algorithm that always works.

I did not need to look far to find a poster child for degenerate intersection. 
A simple pair of cubes, offset so that three edges of each intersect midpoints 
of three faces of the other produces a scary number of degenerate alignments. 
Dividing the cube faces into triangles causes the problem. Each diagonal may 
or may make glancing intersections with the other cube at zero, one or two 
faces. What actually happens is essentially random, depending on the exact 
behavior of low order bits of floating point calculations as it does.

Note that the problem is not floating point imprecision per se. If we were to 
use exact arithmetic, as some existing boolean composition algorithms do, we 
might be able to determine reliably that a given edge/face intersection lies 
exactly on some other edge, but we would still be left with the nontrivial 
problem of how to employ that knowledge. Since exact arithmetic is far slower 
than floating point arithmetic and can consume an impractical amount of memory, 
I prefer to just suck it up and put in the hard work to deal consistently with 
effectively random floating point precision effects.

After contemplating the issue for some time, I settled on the following 
approach. First, I rely on the nice, clean and fast algorithm that works well 
in general position (no degenerate alignments) and detect where that fails. If 
it is going to fail, it always fails while trying to trace out an intersection 
arc, by failing to find a topologically valid candidate intersection for the 
next arc hop.

When the arc trace becomes blocked, I assume that it must be because of 
degenerate alignment. The next intersection the arc either was completely 
missed by the initial edge/face intersection detection pass or it was assigned 
to the "wrong" face, which must lie very close to the "right" face. I theorize 
that it is sufficient to compare each edge of the arc's last intersected face  
to each edge of the face of the pair of the last intersecting edge. Whew, does 
that sound weird? I think it is correct, because all topologically valid 
continuations of the arc involve the face last intersected and the face paired 
to the intersecting edge.

Because our mesh is restricted to triangles, we need to perform nine fairly 
expensive edge/edge comparisons to find any valid candidates for the next arc 
hop. We may find multiple topologically valid candidates, any of which should 
produce correct results, but some will yield fewer arc hops than others. For 
now, I just randomly choose the first candidate.

Once having found a valid continuation, the edge/face intersection database is 
updated to reflect that  re-interpretation. The candidate intersection might 
already be present in the database, in which case it must be found and 
deleted. After possibly deleting the "alias" intersection, the new 
intersection is added and we jump back into the arc trace algorithm at the 
point it was interrupted.

There is plenty of room for error here. We could easily end up in an infinite 
loop, reinterpreting the same near miss intersection candidate over and over 
again. I theorize that this can never happen if only topologically valid 
continuations are chosen at each step, but this remains to be demonstrated.

Intersection arcs may be entirely missed

The above recovery algorithm relies on the assumption that at least one 
intersection point of every intersection arc was discovered in the initial 
edge/face intersection pass. In rare cases, this might not be true. I was able 
to construct  an example with just two triangles: even though they "obviously" 
intersect, every edge one face can be a near miss on the other face.

This proves that the initial edge/face intersection pass must detect near 
misses in addition to edge/face hits. Adding this extra geometric test is not 
horribly expensive, and over time, a greater mathematician then me will 
probably reformulate the two tests to make the additional expense largely 
vanish.

In any case, the result of the extra near miss testing is a list of near 
misses, which may be added to the intersection database wherever no 
topologically equivalent face hit is already present. Near misses should be 
particularly rare in "organic" meshes, in which edges and faces rarely have a 
simple geometric relation to each other. This is where efficiency will be most 
critical, so that is nice.

Implementation strategy

Implementing this algorithm is slow going, mainly because of the difficulty of 
sorting out precisely what is happening topologically. The strategy I have 
chosen is to start with an algorithm that often works and incrementally 
improve it until it always works. That it will eventually get to the latter 
point is an article of faith. I estimate that I am still a few weekends away 
from proving it one way of the other.

The failure recovery code described above is potentially complex, however it 
does have one saving grace: it must by definition implement exactly the same 
topological logic as the algorithm that is already known to work. Therefore, 
the existing, simpler algorithm can be used as "documentation" and to cross 
check the more complex recovery algorithm.

In fact, the algorithm for general position could be completely discarded and 
we could just fail and recover at each arc hop. This would require nine 
relatively expensive edge/edge comparisons per hop, so it is clearly a good 
idea to keep the existing error-prone algorithm around, because it is fast. 
Much like a deathray: if it works it always destroys all your enemies, but 
sometimes it just explodes instead.

A typical debugging session

The attached image shows a typical debugging session. Easy, right? This is the 
"simple" cube/cube intersection. There are 14 possible diagonal/face 
intersections, of which 6 happen to be detected. The edge highlighted in white 
is one of the edge/face intersections, which I can step through and examine 
one at a time using keyboard controls. The face intersected is indicated by a 
line from the intersection point to the center of the face. The intersection 
arc trace fails on the first hop, shown as "e36" in white. Happy hunting.

Regards,

Daniel
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://phunq.net/pipermail/world/attachments/20120707/8ceea303/attachment-0001.html>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: solid26.png
Type: image/png
Size: 159303 bytes
Desc: not available
URL: <http://phunq.net/pipermail/world/attachments/20120707/8ceea303/attachment-0001.png>


More information about the World mailing list