This is a very important class for collision detection between polygons for several reasons:
While intersection tests are rather straight forward and well known problems, the selection of the intersections to return is quite complicated. It suprised me that I was completely unable to find applicable information on this particular problem on the net.
Suppose we have two colliding polygons A and B. Observe that if we trace around the polygons in counterclockwise order starting on an edge of the polygon that is outside the other, we will encounter first an intersection that goes into the other polygon and then one that comes out again.
---- out| B |in ---+----+--- |A | | | | ->-- | ->----------
These in- and outgoing intersections can be used to determine two very important things:
Things get complicated when polygons don't just intersect but totally penetrate eachother. First of all, the collision normals would (depending on the specific polygons and their intersection) oppose eachother, this has unpredictable but possibly still acceptible results.
The biggest problem however is the penetration depth that will be completely off. Take for example the intersection pair 1 and 2 in the example. The penetration depth will be determined by the maximum vertical distance between the edges of A between in and out and the edges of B between out and in (both counterclockwise). Clearly this gives very large penetration depths which often are completely wrong.
In the example the final result will not be very problematic: the forces are most likely to cancel eachother out. But even here it's simple to see that the penetration depth for the intersection pair (3,4) will be much bigger than the other. There are many examples that occur frequently in practice which will cause bodies to be shot in orbit (if the physics would've allowed it ;) ).
---- in|A |out ---3----2-------- |B | | | | | | | ->-4----1-------- out| |in ->--
The/A solution actually is quite straightforward: if we throw out one of the two intersection pairs, the penetration depth will be correct and there won't be any normals that cancel eachother out while they shouldn't. Aditionally this technique will decrease the number of feature pairs, which is good for speed.
Throwing out the right pairs still is quite a challange, but we can apply a technique similar to the one we used to get the intersection pairs. Then we traced the contour of A, now we trace the contour of B starting with an outgoing intersection. If we encounter an ingoing intersection of the same pair we accept the pair (i.e. not throw it out) and move on to the next intersection. If we encounter an ingoing intersection belonging to a different pair or an outgoing intersection we throw it out.
We still are not done just yet. The following example shows that it matters a great deal which intersection we start with. If we start at intersection 2, all the other intersection pairs will be thrown out and B will be pushed down. If we had chosen to start with 4 or 6, the result would be more acceptable; only (1,2) would be thrown out and B would be pushed up.
-------------- |B | | ---- | out| in| |out |in ---6----5----4----3-- |A | | | | | | | | ---- | ->-1----2------------ in| |out ->--
This problem is not really solved currently. There is a heuristic in place that will select the outgoing edge that has the largest number of vertices outside A. In other words, the largest number of vertices between the chosen outgoing intersection and the last ingoing intersection (last as in clockwise as opposed to counterclockwise).
The heuristic is based on the idea that we are more likely to be pushed from A into the direction where the largest part of B is. For the example this would not work, but for many examples in practice it will.
TODO: When we're stacking a lot of triangles the heuristic fails occationaly. The triangles will sometimes jump in directions they shouldn't.If we manage to get all intersections between polygons, we should always encounter alternating ingoing and outgoing intersections when tracing either A or B. In practice this isn't really the case for two reasons:
In stead of trying to fix this issue or throw out the faulty intersections, I've made some adjustments that will simply skip these intersections. I am afraid that these issues might cause trouble somewhere sometime, so if possible this should be fixed some time.
TODO: This class could use some specialized data structures in stead of the countless arrays which clutter the code with modulo indices. @author Gideon Smeding
|
|
|
|