Case Studies

Quick review: If we have two directions, vectors, coordinates in any number of dimensions that we want to find out how they are related and if they are independent then there is a unique plane which contains them. Otherwise they fall on the same line through the origin and there is an infinite number of planes, so this is a potential hedge case. And with FP computations they don’t have to be exactly linear. Choose one to be the reference “a” and that is the direction of the positive x-axis of the plane (a Cartesian coordinate system) and some of the relations (with how they relate to trig) are:

[tr][td]unit direction of positive x[/td][td] a/|a| = a/sqrt(a·a)[/td][/tr]
[tr][td]scaled projection of ‘b’ onto the x axis[/td][td] (a·b)[/td][td]|a||b| cos(t)[/td][/tr]
[tr][td]scaled projection of ‘b’ onto the y axis[/td][td] sqrt((a·a)(b·b) - (a·b)2)[/td][td]sqrt(|a|2|b|2 - (|a||b| cos(t))2) = |a||b| sin(t)[/td][/tr]
[tr][td]unit direction of positive y[/td][td] ((a·a)b - (a·b)a)/sqrt((a·a)(b·b) - (a·b)2)[/td][/tr]

One thing I forgot to point out before was why ‘b’ magically is projected into the positive ‘y’ axis. This is because how we would compute the direction of ‘y’ if we actually needed. If ‘a’ and ‘b’ fall on the same line through the origin, then the projection into ‘y’ is zero and if we were to attempt to compute the unit direction of it the equation would explode. This is common when an equation expects a unique solution and there is in fact none or an infinite number.

An example, walking through @theagentd code above, translates into:

We have an entity at point § with a unit direction facing of (f) and we want to know if some other entity at point (e) is inside a view cone, which is centered about the facing and the outer edge has some angle (t) with respect to the facing. If we choose (f) to be the reference direction (a=f), then the relative direction to the other entity is (b=e-p). Pre-compute: k=cos(t), then

(a·b) = |a||b| cos(s), and since |a|=1, (a·b) = |b| cos(s), where ‘s’ is the unknown angle

and since we want to know if s < t, we can change that to cos(s) > cos(t) given the properties of cos. Since |b| is unknown, theagentd balances out the scale by computing: (a·b)/|b| > k. The thing I mentioned earlier is a property of inequalities: multiplying both side by a positive number is valid and doesn’t change the direction. So this can be computed as:

(a·b) > |b| k

For geometry (and math in general) it’s always true that “a change in coordinate system doesn’t change the problem”. In this case the extra uniform scaling on the problem does effect the relation.

If restricting the maximal half-angle of the cone to >= Pi/2, then

(a·b)2 > (b·b) k2, where k2 could be the pre computed value.


EDIT: had dot(a,b)…instead of dot(b,b) on that last left-hand side, which is |b|^2…opps. Also the restriction can be lifted, but need to inequality properties typed up…and this whole scaled projection into a direction is half of how SAT works.

Put a brute force shader visualization here: http://glslsandbox.com/e#27884.1

Hide the code…change the sampling from 2 to 1. You can pan around with left-click drag (and less useful zoom with right-click)

There some set-up at the top, junk to draw the sample at the bottom. A macro value FOV which is the half angle of the cone in degrees…another TURN_RATE to make the facing rotate. Otherwise the stuff is as from above, other than the comparison has be changed…the left hand side as been subtracted through so we’re always comparing against zero. You can fiddle with the macros and just uncomment the various computations. They are as follows:

[tr][td]Original version with a root and divide [/td][td] k-dot(a,b)/length(b)[/td][/tr]
[tr][td]Multiply through to loose the divide: [/td][td]length(b)*k-dot(a,b)[/td][/tr]
[tr][td]Square to loose the root, but now need to handle the behind case.
Purposefully not in the visualization. Also limits maximum FOV. :([/td][td] dot(b,b)*k2-dot(a,b)*dot(a,b)[/td][/tr]
[tr][td]But x*|x| is like squaring and maintains the sign! :slight_smile:
Bye Bye artificially introduced restrictions![/td][td] dot(b,b)*k2-dot(a,b)*abs(dot(a,b))[/td][/tr]

Monologue granted :point:

Cheers.

Something that may not be clear is that these unit directions derived above are only needed if you’re going to perform some 2D calculations and then take the 2D result and place it back into the original space of the problem. If you’re not going to do that then you don’t even care about them or if the plane is not unique. The axis unit directions in the 2D space are always what you expect:

X = (1,0)
Y = (0,1)

and the coordinates in the 2D plane are:

A = (|a|,0)
B = (a·b, sqrt((a·a)(b·b)-(a·b)2)

back to @theagentd’s example we have (since a.a=1), the a in the plane is A, and b is B:

A = (1,0)
B = (a·b, sqrt((b·b)-(a·b)2)

then the n-D computation:

|b|k-(a·b)

should be identical to the 2D:

|B|k-(A·B)

(A·B) = dot((1,0), (a·b, sqrt((a·a)(b·b)-(a·b)2)) = a·b
|B| = sqrt((a·b)2 + (b·b)-(a·b)2) = sqrt(b·b)

So, as expected, they are identical. We’re logically performing a rotation into a known plane since a rotation is n (number of dimensions) parallel projections into the target coordinate system.

In this 2D space we can think of the pre-computed value: k=cos(t) as the projection into ‘x’ (the axis of the cone) of the direction of the surface of the cone. So in the 2D slice the surface of the cone is a line through the origin, the unit direction © of that line would dot with C·X = k. And our test above is: Is B on the positive side of this line.

Let me break it down by parts. We have |B|. That is how far from the origin the point B is. ‘k’ is how much in ‘x’, which is the same as how much in ‘a’. Some point on the line that has a distance of |B| from the origin will parallel project into ‘a’ as |B|k. Our test point B projects into x as (A·B)=(a·b). The set of all point at a distance |B| from origin fall on a circle of radius B. And those below our test line will have (a·b) > k|B|