a little trigonometry/vector headache

jedidia

shoemaker without legs
Addon Developer
Joined
Mar 19, 2008
Messages
10,882
Reaction score
2,133
Points
203
Location
between the planets
Well, what about trigonometry except the essentials doesn't give me a headache... ?

I guess this could also have gone in the SDK forum, but the problem is majorly mathematical, although the formulation is in Orbiterish.

basically, all I need is the cosine of the angle between a surface and the sun.

I have the direction the surface is facing as a normalised vector vessel-relative. So I convert it to global, which I think should give me the direction the surface is facing relative to the sun (0,0,0; close enough for my purposes):

Code:
vessel->Local2Global(openDirections[di], globalDir);

Next I need the angle between my vessel and the sun, which should simply be the inverse of its global position. Then, as far as I understood it (which is obviously wrong, judging by my results) the cosine between these two vectors should be the dot product divided by the distance to the sun, which would be
Code:
double cosDir = dotp(globalDir, -vesselGlobalPos) / sunDist;

However, I get complete gibberish. I don't know much, but I know that a well behaved cosine isn't larger than 1. So, what am I doing wrong?
 

Moach

Crazy dude with a rocket
Addon Developer
Joined
Aug 6, 2008
Messages
1,581
Reaction score
62
Points
63
Location
Vancouver, BC
the angle between two points in 3d space can be defined as the arcosine of the dot product between them :hmm:

but uhh, i'd recommend you normalize those vectors before dot'ing them together :rolleyes:


well, you did come in pretty close to it there already :cheers:
 
Last edited:

tblaxland

O-F Administrator
Administrator
Addon Developer
Webmaster
Joined
Jan 1, 2008
Messages
7,320
Reaction score
25
Points
113
Location
Sydney, Australia
Before normalising and calculating the angle, I think you will need to subtract vesselGlobalPos from globalDir (I don't have the API Ref handy but I recall that Local2Global adds the vessel global position to the result after applying the vessel rotation matrix). If you don't do that, the angle between vesselGlobalPos and globalDir will be consistently very small at any reasonable distance from the Sun, regardless of the orientation of your surface.
 

Enjo

Mostly harmless
Addon Developer
Tutorial Publisher
Donator
Joined
Nov 25, 2007
Messages
1,665
Reaction score
13
Points
38
Location
Germany
Website
www.enderspace.de
Preferred Pronouns
Can't you smell my T levels?
atan2 works better, because it's limited to (-180, 180), not (-90, 90):

Code:
double VectorMath::dot(const Vect3 & a, const Vect3 & b )
{
  return a.x*b.x + b.y*a.y + a.z*b.z;
}

Vect3 VectorMath::cross(const Vect3 & a, const Vect3 & b )
{
  Vect3 v;
  v.x = a.y*b.z - b.y*a.z;
  v.y = a.z*b.x - b.z*a.x;
  v.z = a.x*b.y - b.x*a.y;
  return v;
}

double VectorMath::angle(const Vect3 & a, const Vect3 & b )
{
    const Vect3 & aNorm = a.norm();
    const Vect3 & bNorm = b.norm();

    return atan2( cross(aNorm, bNorm).len(), dot(aNorm, bNorm) );
}

double Vect3::len() const
{
    return sqrt(x * x + y * y + z * z );
}

Vect3 Vect3::norm() const
{
    return Vect3(*this) /= len();
}

Full code in Math and Systems dirs here:
http://enjomitchsorbit.svn.sourceforge.net/viewvc/enjomitchsorbit/lib/
 
Last edited:

Miner1

New member
Joined
Jun 9, 2008
Messages
25
Reaction score
0
Points
0
Actually, when finding the angle between two vectors, using arccosine is the better method. The defined range for the arccosine function is [math][0,\pi][/math] and this is all you need for this purpose. Notice that in your function VectorMath::angle, the first argument to the atan2 function is cross(aNorm, bNorm).len() which is necessarily a positive number. So you are automatically restricting the result to the same range provided by the arccosine function. Additionally using arccosine instead of atan2 requires fewer calculations since you don't need to calculate the cross product.
 

Enjo

Mostly harmless
Addon Developer
Tutorial Publisher
Donator
Joined
Nov 25, 2007
Messages
1,665
Reaction score
13
Points
38
Location
Germany
Website
www.enderspace.de
Preferred Pronouns
Can't you smell my T levels?
Actually, when finding the angle between two vectors, using arccosine is the better method. The defined range for the arccosine function is [math][0,\pi][/math] and this is all you need for this purpose.

For jedidia's purpose, where he needs arccos, a he said, or for the purpose of calculating angles between vectors? For the second atan2 is better because many times [math][0,\pi][/math] is not enough.

Notice that in your function VectorMath::angle, the first argument to the atan2 function is cross(aNorm, bNorm).len() which is necessarily a positive number.
That's the equation for arctan in 3d space. Nothing is wrong there to my knowledge.

So you are automatically restricting the result to the same range provided by the arccosine function.

What about the sign of the dot product? Doesn't it make a difference you think?

Additionally using arccosine instead of atan2 requires fewer calculations since you don't need to calculate the cross product.

Negligible for today's machines. It would make a difference if you had to calculate it in an NP-Hard problem, but in such case more sophisticated methods must be used, similar to Divide and Conquer instead of static optimizations, which don't make much difference if you're going exponential anyway.

It's better to turn on compiler optimizations and have a one general-purpose function, that you can rely on, no matter if you want the result to be in range of [math][0,\pi][/math] or [math][-\pi,\pi][/math]. Define such function once and use it in high level code, not worrying about the internals anymore, or having to think whether to choose one variation of a function or the other. What can be better?

[EDIT] It's true that the angle between 2 3d vectors will be always 0 < x < pi, but you will get garbage for arccos, if one of the vectors flips beyond pi angle.
 
Last edited:

Miner1

New member
Joined
Jun 9, 2008
Messages
25
Reaction score
0
Points
0
The only point of contention I have to your argument is that the dot product of two vectors will always give you the product of the magnitude of the two vectors and the cosine of the small angle between them (small meaning between 0 and [math]\pi[/math]). So when finding the angle between two vectors, as long as you properly normailize the vectors, arccosine is all you need. With the atan2 method you showed, the first argument will always be positive, automatically restricting the result to the first and second quadrant (where the y component is positive). The sign of the dot product will then determine which of these quadrants contains the final result (i.e. the x component positive or negative).

Let me make it clear that I see nothing wrong with what you are doing, I just don't believe it to be necessary. And while it is true that a few additional steps won't cause many problems when dealing with modern PCs that have multiple 2.5 GHz processors, imagine writing code for a satellite that uses a single rad hard processor that (if you're lucky) may top out at just a few hundred MHz. Everybody's code writing style is different, I'm just giving a little insight into my prefered method. I do use atan2 in many cases, but when calculating the angle between two vectors, I always stick to just using arccosine.

Anyway, hope you have a great day!
 

jedidia

shoemaker without legs
Addon Developer
Joined
Mar 19, 2008
Messages
10,882
Reaction score
2,133
Points
203
Location
between the planets
atan2 works better, because it's limited to (-180, 180), not (-90, 90):

Thanks, but limited to 90 degrees is actually exactly what I needed, since the surface has no backside (that is, the backside is actually another surface...).
 

Enjo

Mostly harmless
Addon Developer
Tutorial Publisher
Donator
Joined
Nov 25, 2007
Messages
1,665
Reaction score
13
Points
38
Location
Germany
Website
www.enderspace.de
Preferred Pronouns
Can't you smell my T levels?
Miner1: I'm less mathematically educated than you, so I can't defend my position by showing you exactly where the difference is. I'm basing on my experience. I've been experimenting with applications available in download here (the "da_solver"), and when I was using arccos, it wasn't getting correct answers for all spectrum of source (ship's) and target (satellite's) vectors. For a certain setup, I was getting a "mirror" result of what should be, while atan2 worked fine. I don't know if I make myself clear.

Other than that, a few hundred MHz is still a huge value for mathematical calculations. My 400 MHz terminal is able to process 4 color images per second, 320x480 each. Angle calculation is far less time consuming than image processing.

Just to get an idea why you shouldn't sacrifice generality of your code for small speedup, and shouldn't care about what the optimizer normally cares, not only on PCs, check the anecdote presented at minute 21 of this movie by the creator of C++:
http://channel9.msdn.com/Events/GoingNative/GoingNative-2012/Keynote-Bjarne-Stroustrup-Cpp11-Style

And have a nice day too :)
 
Last edited:

Enjo

Mostly harmless
Addon Developer
Tutorial Publisher
Donator
Joined
Nov 25, 2007
Messages
1,665
Reaction score
13
Points
38
Location
Germany
Website
www.enderspace.de
Preferred Pronouns
Can't you smell my T levels?
Well, it looks like Miner1 was right. I've ran a series of combinations of angles, trying to reproduce the problem I've stumbled upon with my Direct Ascent Solver back in the days, when the acos and atan did make a difference, but they both produce the same results for all combinations... I dunno... The problem must have been somewhere else then.

So my apologies - it was a (too) quick answer.
 

mjessick

Donator
Donator
Joined
Apr 26, 2008
Messages
174
Reaction score
0
Points
0
Location
Houston
Cross products aren't as useful in the case where the two vectors lie along the same line.

Did you try calculating the angle between two vectors pointing in opposite directions?
Seems like VectorMath::angle would result in atan2(0,1) for both the same direction and also for the opposite direction case.
 
Top