While working on the 2d visibility demo, I wrote some code in Visibility.hx that I wasn’t sure about. I had written it as:
private function _segment_in_front_of(a:Segment, b:Segment, relativeTo:Point):Bool {
var A1 = leftOf(a, b.p1);
var A2 = leftOf(a, b.p2);
var A3 = leftOf(a, relativeTo);
var B1 = leftOf(b, a.p1);
var B2 = leftOf(b, a.p2);
var B3 = leftOf(b, relativeTo);
// NOTE: this algorithm is probably worthy of a short article
// but for now, draw it on paper to see how it works. Consider
// the line A1-A2. If both B1 and B2 are on one side and
// relativeTo is on the other side, then A is in between the
// viewer and B. We can do the same with B1-B2: if A1 and A2
// are on one side, and relativeTo is on the other side, then
// B is in between the viewer and A.
if (B1 == B2 && B2 != B3) return true;
if (A1 == A2 && A2 == A3) return true;
if (A1 == A2 && A2 != A3) return false;
if (B1 == B2 && B2 == B3) return false;
...
}
I had convinced myself on paper that this was correct, at least in the cases I care about. However, John N asked about this function[1] and I decided to look at the function again to see if I could find any bugs and maybe write it to be more clear.
Here’s the original algorithm. You can adjust the A and B lines (which determine a1, a2, b1, b2), and then it shows you the areas where relativeTo might be (which determines a3, b3):
There are definitely places where neither A nor B is closer, but the algorithm arbitrarily decides. Here’s an algorithm that is better about this, although I think it doesn’t work any better in practice in the context of the visibility algorithm:
(Note: for this diagram I didn’t spend the time to make all cases work; I just wanted to write something quickly that showed how this function works.)
Note that although this code is simple, in practice it may have artifacts. See these notes[2] to understand why.