• Create Account

## Vector Projection with zero length

Old topic!

Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.

12 replies to this topic

### #1Grain  Members

500
Like
0Likes
Like

Posted 20 August 2013 - 03:32 AM

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?

### #2Brother Bob  Moderators

10109
Like
0Likes
Like

Posted 20 August 2013 - 03:42 AM

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.

5832
Like
0Likes
Like

Posted 20 August 2013 - 03:42 AM

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.

Edited by Paradigm Shifter, 20 August 2013 - 03:58 AM.

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

### #4Grain  Members

500
Like
0Likes
Like

Posted 20 August 2013 - 04:04 AM

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.

5832
Like
0Likes
Like

Posted 20 August 2013 - 04:29 AM

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

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.

Edited by Paradigm Shifter, 20 August 2013 - 04:50 AM.

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

### #6jjd  Members

2140
Like
2Likes
Like

Posted 20 August 2013 - 05:07 AM

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
--irc.freenode.net#gdnet

### #7Grain  Members

500
Like
0Likes
Like

Posted 20 August 2013 - 05:07 AM

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

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.

### #8Grain  Members

500
Like
0Likes
Like

Posted 20 August 2013 - 05:11 AM

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).

### #9Álvaro  Members

20270
Like
1Likes
Like

Posted 20 August 2013 - 05:49 AM

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.

### #10Grain  Members

500
Like
0Likes
Like

Posted 20 August 2013 - 06:25 AM

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.

        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);
}

Edited by Grain, 20 August 2013 - 06:29 AM.

### #11Álvaro  Members

20270
Like
0Likes
Like

Posted 20 August 2013 - 06:47 AM

That code is more robust, assuming division by 0 doesn't trigger an exception or anything (sorry, I don't know Java or whatever that language you are using is).

But I still wonder why you are projecting onto a vector that is not roughly unit length.

### #12jjd  Members

2140
Like
0Likes
Like

Posted 20 August 2013 - 06:48 AM

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.

        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);
}

The typical way of handling this would be,

float sqrA = Vector2.Dot(A, A);
if(sqrA < epsilon)
{
return Vector2.Zero;
}

return Vector2.Multiply(A, Vector2.Dot(A, B) / sqrA));



where 'epsilon' is a tolerance that you choose.

-Josh

Edited by jjd, 20 August 2013 - 06:48 AM.

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

### #13nowzer  Members

104
Like
0Likes
Like

Posted 23 August 2013 - 12:28 PM

... and I was going to say null until I saw Josh's answer...

Old topic!

Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.