2
\$\begingroup\$
Vec2 a, b; // some random vector
Vec2 cross = a.Cross(b);
RelativeDirection(a,b,cross); // return true if the direction of
                              // rotating a to b is counter-clockwise

How do I implement the function RelativeDirection()?

I got some suedo code from the textbook:

if a.Cross(b) > 0 then ... else ...

but the cross product is a vector right? how do you compare it with an integer?

\$\endgroup\$
2
  • 2
    \$\begingroup\$ The cross product isn't defined for 2D vectors. You can treat your inputs as 3D vectors with a z component of 0 to get a resulting 3D vector that lies purely in the z axis, as described in this recent answer \$\endgroup\$
    – DMGregory
    Jan 14, 2018 at 22:35
  • \$\begingroup\$ "pseudo" has a p, and the e comes first. \$\endgroup\$ Jan 15, 2018 at 1:13

2 Answers 2

4
\$\begingroup\$

I think the book means

if a.Cross(b).z > 0 then ... else ...

which translates to

if (a.x * b.y - a.y * b.x > 0)

(depending on coordinate system, you may need to replace > with <)


Essentially this works in the same way as dot product trick from the second part of Stephane Hockenhull answer, just rewritten in a short way. Contrary to what that answer says, you don't need to normalize your vectors beforehand.

\$\endgroup\$
1
1
\$\begingroup\$

You check the angular 2D direction of both vectors and see if the difference (modulo a full circle) is positive or negative (or 0 or 180 degrees).

double diff = (atan2(a.y, a.x) - atan2(b.y, b.x));
if(diff < -M_PI){
   diff += M_PI * 2;
}
if(diff > M_PI){
   diff -= M_PI * 2;
}

return (diff > 0);

Which ever return value (true or false) means clock-wise or counter-clockwise depends on your Cartesian system (positive Y going up or down, positive X going left or right).

Anything close to zero (both vectors pointing in the same direction) or 180 degrees (pointing opposite) will give a result depending on rounding-errors so you'll probably want to add a check for [almost 0 degrees] and [almost 180 degrees].

You may need to check for these cases before checking for CW/CCW:

// a and b need to be normalised for this error-margin check to work
// the other two code samples to check CW/CCW don't need normalised vectors but this check does
double dot = DotProduct(a, b);
double margin = cos(error_margin_as_angle_in_radiant);
if(dot > margin){
   return SAME_DIRECTION;
}
if(dot < -margin){
   return OPPOSITE_DIRECTION; // we can't tell if CW or CCW
}

//... continue with the above CW/CCW check here ...

Alternatively you can use the dot product of one of the normalised vectors rotated by 90 degrees and the other one as-is:

Vec2 rotated_a(a.y, -a.x);
return DotProduct(rotated_a, b) > 0;
\$\endgroup\$
3
  • 1
    \$\begingroup\$ There is no need for a and b to be normalized for the dot product trick. \$\endgroup\$ Jan 14, 2018 at 23:44
  • \$\begingroup\$ Also, I would remove the first part of your answer completely. It has no advantages against the second one. \$\endgroup\$ Jan 14, 2018 at 23:49
  • \$\begingroup\$ The first method does have an advantage if you're already keeping track of the vector as an angle which is fairly common in 2D video games. You can then outright skip the atan2. \$\endgroup\$ Feb 4, 2018 at 15:34

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .