Vector Projection with zero length

Started by
11 comments, last by nowzer 10 years, 7 months ago

Currently I'm doing this


        public static Vector2 Project(this Vector2 A, Vector2 B)
        {
            if (A.X != 0f || A.Y != 0)
                return Vector2.Multiply(A, Vector2.Dot(A, B) / Vector2.Dot(A, A));
            else
                return A;
                //return B; ???
        }

Without the zero length check in there every thing blows up because this method returns an effectively infinite length vector. What is the best thing to return when the length of A is zero?

Advertisement

If A is a zero-vector, then the result is undefined and anything you return is technically wrong. Which, among all incorrect, options is the better one depends on what it is you do with the result. But I would suggest that, in general, the best thing to do is avoid division by zero, or in this case having a zero-length A, in the first place.

Return the zero vector.

You are trying to scale A (which is the zero vector) by an indeterminate dot(A, B) / dot(A, A). dot(A, B) == 0, dot(A, A) == 0, so you are trying to calculate A * (0/0), but A is zero anyway => return A (which is the zero vector).

To see this (non-rigorous argument) is correct, consider the limit when length(A) tends to zero. (EDIT: If you halve the length of A, the length of the projected vector is halved too, so it is easy to see that the limit when length(A) -> 0 is the zero vector).

EDIT: Considering the limit is the way to do it, but it doesn't apply in all cases e.g. normalisation of a vector, which has no limit as the length tends to zero. You have to consider each function separately.

"Most people think, great God will come from the sky, take away everything, and make everybody feel high" - Bob Marley

To see this (non-rigorous argument) is correct, consider the limit when length(A) tends to zero. (EDIT: If you halve the length of A, the length of the projected vector is halved too, so it is easy to see that the limit when length(A) -> 0 is the zero vector).

I'm not sure what you mean considering the result should be the same for all lengths of A with the sole exception 0.

Whoops, my mistake then.

You can't return anything meaningful in that case. Either return the zero vector anyway or throw an exception.

EDIT: I confused myself from looking at this picture in wikipedia from the vector projection page

200px-Projection_and_rejection.png

which suggested to me that if a was twice as long then the length a1 would be also. EDIT2: I was confused ;) More coffee required.

"Most people think, great God will come from the sky, take away everything, and make everybody feel high" - Bob Marley

Currently I'm doing this


        public static Vector2 Project(this Vector2 A, Vector2 B)
        {
            if (A.X != 0f || A.Y != 0)
                return Vector2.Multiply(A, Vector2.Dot(A, B) / Vector2.Dot(A, A));
            else
                return A;
                //return B; ???
        }

Without the zero length check in there every thing blows up because this method returns an effectively infinite length vector. What is the best thing to return when the length of A is zero?

What you are trying to do here is figure out how much of B is pointing in the A direction. This assumes that A is a direction vector. A direction vector is usually required to have a length of 1. Any vector that can be normalized can be a direction vector. However, a zero-length vector cannot be normalized and thus has no direction. If A was correctly normalized your project function simply return Vector2.Dot(A,B). If you should not be projecting zero-length vectors, it seems that there is a problem upstream of this function. Personally, I would get rid of this function and make sure that my direction vector was normalized and use the dot product directly.

-Josh

--www.physicaluncertainty.com
--linkedin
--irc.freenode.net#gdnet

Whoops, my mistake then.

You can't return anything meaningful in that case. Either return the zero vector anyway or throw an exception.

EDIT: I confused myself from looking at this picture in wikipedia from the vector projection page

200px-Projection_and_rejection.png

which suggested to me that if a was twice as long then the length a1 would be also. EDIT2: I was confused ;) More coffee required.

Also I'm projecting B onto A, as where this example projects A onto B.

Currently I'm doing this


        public static Vector2 Project(this Vector2 A, Vector2 B)
        {
            if (A.X != 0f || A.Y != 0)
                return Vector2.Multiply(A, Vector2.Dot(A, B) / Vector2.Dot(A, A));
            else
                return A;
                //return B; ???
        }

Without the zero length check in there every thing blows up because this method returns an effectively infinite length vector. What is the best thing to return when the length of A is zero?

What you are trying to do here is figure out how much of B is pointing in the A direction. This assumes that A is a direction vector. A direction vector is usually required to have a length of 1. Any vector that can be normalized can be a direction vector. However, a zero-length vector cannot be normalized and thus has no direction. If A was correctly normalized your project function simply return Vector2.Dot(A,B). If you should not be projecting zero-length vectors, it seems that there is a problem upstream of this function. Personally, I would get rid of this function and make sure that my direction vector was normalized and use the dot product directly.

-Josh

Normalizing requires a square root call which I'd like to avoid as much as possible, and seeing as I can project just fine while avoiding that I see no benefit in doing so. Also zero vectors are perfectly valid in some cases(a velocity vector for example).

I want to point out that the code in the OP is not very robust: If the input is the vector (0, epsilon) --where epsilon is a number so small that its square is 0--, the code will still divide by zero.

I want to point out that the code in the OP is not very robust: If the input is the vector (0, epsilon) --where epsilon is a number so small that its square is 0--, the code will still divide by zero.

How about this then?


        public static Vector2 Project(this Vector2 A, Vector2 B)
        {
            float DotOverDot = Vector2.Dot(A, B) / Vector2.Dot(A, A);
            if (float.IsNaN(DotOverDot) || float.IsInfinity(DotOverDot))
                return Vector2.Zero;
            else
                return Vector2.Multiply(A, DotOverDot);                
        }

This topic is closed to new replies.

Advertisement