API Question Vessel Rotations

E

ex-orbinaut

Guest
Perhaps someone has a sound grip on this. I will reduce the blurb to a minimum.

OBJECTIVE: Function to immediately rotate a vessel to 0º bank and 0º pitch relative to the reference body, using SetGlobalOrientation(). It is also important that the heading (on the reference body) not be changed in the process.

Present development...

Code:
VECTOR3 HorInvRot; 
HorizonInvRot(_V(0, 1, 0), HorInvRot); 
double bankdif = atan2(HorInvRot.x, HorInvRot.y); 
 
// is the same as... 
 
double bank = GetBank(); 
 
// so now then... 
 
VECTOR3 Glob_Orient; 
GetGlobalOrientation(Glob_Orient); 
 
// ...gives you the same as... 
 
VESSELSTATUS vs; 
GetStatus(vs); 
 
// vs.arot.x, vs.arot.y, vs.arot.z 
 
// ...and with this it is easy enough to set a 0º bank angle by doing... 
 
Glob_Orient.z += bank;  
// ...or, indeed, "vs.arot.z += bankdif"... 
 
// ...and this physically sets the bank to 0º relative to the surface of the reference body... 
 
SetGlobalOrientation(_V(Glob_Orient.x, Glob_Orient.y, Glob_Orient.z));
So far, so good. As a point of note, it is also possible to obtain these euler angles by doing the conversion of the Matrix, as the Doctor says in his API Reference Manual. However, going into that will just bulk out the text of what has already been accomplished above. You get what I mean, anyway.

The snag comes when I try to set the pitch to 0º. There seems to be a confusing feature of SetGlobalOrientation() here. The angle around the x axis CANNOT be used to do the same with GetPitch(), even if it is done in two steps (bank first, then pitch).

So, what's confusing?

The SetGlobalOrientation() around the z axis appears to be equivalent to the local vessel frame, and not the global.

Done my head in... I am obviously misunderstanding something.

Can somebody please be so kind as to point me in the right direction to set that pitch to 0º, as the Rotation functions in the OrbiterAPI are a veritable labyrinth that frequently lead to the same outcome and REALLY do succeed in losing one completely.

That, of course, unless trying previously has not done the same thing to you... ;)

If any assistance is forthcoming it will be duly appreciated. My thanks in advance.
 

Bj

Addon Developer
Addon Developer
Donator
Joined
Oct 16, 2007
Messages
1,886
Reaction score
11
Points
0
Location
USA-WA
Website
www.orbiter-forum.com
If any assistance is forthcoming it will be duly appreciated. My thanks in advance.


Try Local2Global and Global2Local. I think that will work...


Code:
VECTOR3 global;
VESSEL *v = oapiGetFocusInterface();
v->Local2Global ( _V(0,0,0) , global);

SetGlobalOrientation( global );
 
Last edited:

jedidia

shoemaker without legs
Addon Developer
Joined
Mar 19, 2008
Messages
10,842
Reaction score
2,105
Points
203
Location
between the planets
The SetGlobalOrientation() around the z axis appears to be equivalent to the local vessel frame, and not the global.

this is due to a "problem" that I'm expieriencing just now when trying to get my galactical coordinates aligned with the global coordinate system in Orbiter. The Y-axis is at a right angle to the ecliptic, not the Z-axis, as I intuitively expected.
 
E

ex-orbinaut

Guest
First, thanks Bj for the comment.

I had understood (from the API Manual) that the functions Local2Global(), Global2Local() and Local2Rel() were strictly limited to coordinates of the vessel, either relative to the ecliptic and its origin, the reference body, or the vessel's own position, and not rotations. Global2Local() would therefore probably be useful for detecting range between two vessels and (once the distances were normalized into a vector) the angles between them. Would be useful for a docking autopilot, perhaps?

You are probably right, though, but I think it might be a bit more complicated than as you had it in your code above.

Here's a snippet of my understanding of the above mentioned functions.

Global variables..

Code:
VECTOR3 Global_Pos_1, Global_Pos_2, Local_Pos_1, Rel_Pos_1; 
VECTOR3 Ref_Global_Pos_1, Ref_Vessel_Local, Ref_Vessel_Relative; 
 
VESSELSTATUS vs, vs_ref; 
 
OBJHANDLE h_ref_vessel; 
VESSEL *p_ref_vessel; 
 
bool print_ref_data;
In the clbkPreStep()

Code:
Local2Global(_V(0,0,0), Global_Pos_1); 
// This gets you the global position of the vessel, 
// basically from the system "origin", relative to the ecliptic.
 
GetGlobalPos(Global_Pos_2); 
// ...as does this. 
 
Global2Local(Global_Pos_2, Local_Pos_1); 
// This gets you the vessel's local position from it's own global position, 
// which you obtained by either of the above methods. Pretty useless as is demonstrated right here,  
// as it will always be 0, 0, 0 (ie; the vessel's local position relative to itself). But please read on... 
 
Local2Rel(_V(0,0,0), Rel_Pos_1); // This is the vessel's position relative to the current reference (orbit) body. 
 
// It is the same thing as VECTOR3 vs.rpos from the vessel's status, as obtained in the following line. 
GetStatus(vs); // For getting vs.rpos.x, vs.rpos.y, vs.rpos.z 
 
 
if(h_ref_vessel = oapiGetVesselByName("GL-01S")) // For example. Could be any vessel by name included in your scenario. 
{ 
    print_ref_data = true; // Just to suppress output of rubbish or possible CTD if the vessel does not exist (NULL handle)...
 
    p_ref_vessel = oapiGetVesselInterface(h_ref_vessel); 
    p_ref_vessel->GetGlobalPos(Ref_Global_Pos_1); 
    // Obtains the reference vessel's global position.
 
    Global2Local(Ref_Global_Pos_1, Ref_Vessel_Local); 
    // Obtains the position of the refence vessel with relation to the current 
    // vessel, but DOES seem to be related to the orientation of the local vessel's axes, strangely enough, despite the API 
    // Manual's comment that it is for coordinates and NOT rotations. 
 
    p_ref_vessel->GetRelativePos(GetHandle(), Ref_Vessel_Relative); 
    // This gets the relative positions between the two vessels, 
    // but strictly on the Global frame. If you put your vessel into the 0,0,0 orientation (head up to Polaris,  
    // wings level with the ecliptic, and nose pointing at the longitude line between Gemini and Taurus), this function gives 
    // you the same value as the resulting Global2Local() Ref_Vessel_Local. 
} 
else 
    print_ref_data = false;
In the clbkDrawHUD...

Code:
int x, y; 
char buffer[250]; 
 
x = int(hps->W * 0.05);    y = int(hps->H * 0.2); 
sprintf_s(buffer, sizeof(buffer), "Global_Pos_1(x,y,z)........: %0.2f %0.2f %0.2f", Global_Pos_1.x, Global_Pos_1.y, Global_Pos_1.z); 
TextOut(hDC, x, y, buffer, strlen(buffer)); 
 
x = int(hps->W * 0.05);    y = int(hps->H * 0.23); 
sprintf_s(buffer, sizeof(buffer), "Global_Pos_2(x,y,z)........: %0.2f %0.2f %0.2f", Global_Pos_2.x, Global_Pos_2.y, Global_Pos_2.z); 
TextOut(hDC, x, y, buffer, strlen(buffer)); 
 
x = int(hps->W * 0.05);    y = int(hps->H * 0.26); 
sprintf_s(buffer, sizeof(buffer), "Local_Pos_1(x,y,z).........: %0.2f %0.2f %0.2f", Local_Pos_1.x, Local_Pos_1.y, Local_Pos_1.z); 
TextOut(hDC, x, y, buffer, strlen(buffer)); 
 
x = int(hps->W * 0.05);    y = int(hps->H * 0.29); 
sprintf_s(buffer, sizeof(buffer), "Rel_Pos_1(x,y,z)...........: %0.2f %0.2f %0.2f", Rel_Pos_1.x, Rel_Pos_1.y, Rel_Pos_1.z); 
TextOut(hDC, x, y, buffer, strlen(buffer)); 
 
x = int(hps->W * 0.05);    y = int(hps->H * 0.32); 
sprintf_s(buffer, sizeof(buffer), "vessel.rpos(x,y,z).........: %0.2f %0.2f %0.2f", vs.rpos.x, vs.rpos.y, vs.rpos.z); 
TextOut(hDC, x, y, buffer, strlen(buffer)); 
 
if(print_ref_data == true) // If a handle to the ref vessel was obtained... 
{ 
    x = int(hps->W * 0.05);    y = int(hps->H * 0.35); 
    sprintf_s(buffer, sizeof(buffer), "Ref_Global_Pos_1(x,y,z)....: %0.2f %0.2f %0.2f", Ref_Global_Pos_1.x, Ref_Global_Pos_1.y, Ref_Global_Pos_1.z); 
    TextOut(hDC, x, y, buffer, strlen(buffer)); 
 
    x = int(hps->W * 0.05);    y = int(hps->H * 0.38); 
    sprintf_s(buffer, sizeof(buffer), "Ref_Vessel_Local(x,y,z)....: %0.2f %0.2f %0.2f", Ref_Vessel_Local.x, Ref_Vessel_Local.y, Ref_Vessel_Local.z); 
    TextOut(hDC, x, y, buffer, strlen(buffer)); 
 
    x = int(hps->W * 0.05);    y = int(hps->H * 0.41); 
    sprintf_s(buffer, sizeof(buffer), "Ref_Vessel_Relative(x,y,z).: %0.2f %0.2f %0.2f", Ref_Vessel_Relative.x, Ref_Vessel_Relative.y, Ref_Vessel_Relative.z); 
    TextOut(hDC, x, y, buffer, strlen(buffer)); 
}
As I said, a labyrinth. I have not had the time to look into the root of the query again since my original post...


jedidia said:
this is due to a "problem" that I'm expieriencing just now when trying to get my galactical coordinates aligned with the global coordinate system in Orbiter. The Y-axis is at a right angle to the ecliptic, not the Z-axis, as I intuitively expected.

That's exactly the confusing part of this. It seems that the planet relative pitch angle of the vessel should be (needs to be) set by the x and y global rotation angles, and would therefore need to be divided into its two respective components based on the global bank angle (sine of the z angle). But as it has managed to confuse me, I am here believing that the global rotation angle around the z axis is the same as the vessel's local. I am still convinced that the solution lies in the HorizonInvRot() function. I will look into it again as soon as I get the time.

Thanks again for the suggestions.
 

tblaxland

O-F Administrator
Administrator
Addon Developer
Webmaster
Joined
Jan 1, 2008
Messages
7,320
Reaction score
25
Points
113
Location
Sydney, Australia
Keith said:
OBJECTIVE: Function to immediately rotate a vessel to 0º bank and 0º pitch relative to the reference body, using SetGlobalOrientation(). It is also important that the heading (on the reference body) not be changed in the process.
To clarify, "relative to the reference body" means:
1. Relative to a planet centred reference frame such that {0,1,0} is defined by the rotational axis and {1,0,0} is defined by the longitude of the ascending node of the ecliptic through the equatorial plane? or
2. Relative to a reference frame centred at the intersection of the vessel's radius vector with the surface of the reference body, such that {0,1,0} is local north and {1,0,0} is local east? or
3. Relative to a planet centred reference frame such that the frame is aligned with the ecliptic reference frame?

The functions you have been discussing above use different reference frames (including the ones mentioned above), and defining your reference frame is critical to your success here.

FWIW, here is how I would attack the problem:
1. Determine the orientation of the desired reference frame relative to the ecliptic reference frame (as a direction cosine matrix, or rotation matrix). Call it R_ref.
2. Determine the desired orientation of the vessel relative to desired reference frame (again, as a direction cosine matrix). Call it R_rel.
3. Find the product R_ref*R_rel. This matrix now describes the desired orientation of the vessel in the ecliptic frame. Use this product in the function SetRotationMatrix.

Hope that helps.
 

jedidia

shoemaker without legs
Addon Developer
Joined
Mar 19, 2008
Messages
10,842
Reaction score
2,105
Points
203
Location
between the planets
But as it has managed to confuse me, I am here believing that the global rotation angle around the z axis is the same as the vessel's local.
IF your global X/Y alignement is 0/0, then Z global and Z local are identical (because both axis are parallel). otherwise they shouldn't be...
 
E

ex-orbinaut

Guest
Yeah, this.

3. Relative to a planet centred reference frame such that the frame is aligned with the ecliptic reference frame?

The functions you have been discussing above use different reference frames (including the ones mentioned above), and defining your reference frame is critical to your success here.
I understand this, as far as rotations go in Orbiter.

1. Global, relative to the ecliptic.
2. Reference, to the horizon of the planet being orbited (or landed on), and which cannot be manipulated directly.
3. Local, the vessel itself, which I do not see the point of as it is always going to be zero (unless you are mapping it to another vessel or planet, which leads you back to item 2, anyway).

What I want to do is get the angle (global relative) of the two tangents x and y, on the great circle of the planet, these tangents having their origin at the point where a radius extending from the center of the planet to the center of the vessel intersects the surface of the planet. I want to align the vessel's y axis parallel to this radius to set the pitch and bank to 0º. Finally, rotate the vessel around its y axis to the heading it had originally (as the transformation as here described is sure to upset that, too). Now, I can see that the HorizonInvRot() function, when the 1 normal is positive z axis, provides the vector figures to derive heading.

FWIW, here is how I would attack the problem:
1. Determine the orientation of the desired reference frame relative to the ecliptic reference frame (as a direction cosine matrix, or rotation matrix). Call it R_ref.
2. Determine the desired orientation of the vessel relative to desired reference frame (again, as a direction cosine matrix). Call it R_rel.
3. Find the product R_ref*R_rel. This matrix now describes the desired orientation of the vessel in the ecliptic frame. Use this product in the function SetRotationMatrix.

Hope that helps.
What you mean is there is no way of doing it with SetGlobalOrientation(). That is, with euler angles. Not so sure about that, but if it is the case, this goes on the shelf for a time when I have a bit more than 0.5 to 1 hour, at most, in every 24 hour cycle, to look into it.

Thank you for your help, just the same. Come back to it sometime (forewarning of a necropost here).

All the best.:cheers:
 

tblaxland

O-F Administrator
Administrator
Addon Developer
Webmaster
Joined
Jan 1, 2008
Messages
7,320
Reaction score
25
Points
113
Location
Sydney, Australia
3. Local, the vessel itself, which I do not see the point of as it is always going to be zero (unless you are mapping it to another vessel or planet, which leads you back to item 2, anyway).
It is not necessarily a useful reference frame for this application but it is plenty useful when you want to know where an object is relative to your vessel, for example, aiming a satellite dish at a target.

What you mean is there is no way of doing it with SetGlobalOrientation(). That is, with euler angles. Not so sure about that, but if it is the case, this goes on the shelf for a time when I have a bit more than 0.5 to 1 hour, at most, in every 24 hour cycle, to look into it.
On the contrary, it can certainly be done with Euler angles, but it's just not the method I would elect to use ;)

I don't have time to code it up atm, but here is what I think you want to do, in pseudo-code:

1. Get the vessel rotation matrix.
2. Get a vector that corresponds to a plane of constant heading. This can be determined from the cross product of the radius vector and a vector pointing the direction of the vessel's nose (vessel +z).
3. The cross product of the vector derived in step 2 with the radius vector will give you the vector that the nose needs to be aligned to.
4. The cross product of the nose vector from 3 with the radius vector will give the vector that the vessel +x needs to aligned to.
5. The radius vector gives you the vector that tge vessel +y needs to be aligned to.
6. Normalise the results from steps 3, 4, 5 and put them in as the colum vectors of a 3x3 matrix. This matrix is your direction cosine matrix, or rotation matrix, from the ecliptic frame to the desired local vessel frame. Use SetRotationMatrix to set it.

Does that make sense?

Disclaimer: I have not checked the handedness of the cross products in my pseudo-code above. The order of some of those may need to be reversed.
 

tblaxland

O-F Administrator
Administrator
Addon Developer
Webmaster
Joined
Jan 1, 2008
Messages
7,320
Reaction score
25
Points
113
Location
Sydney, Australia
Try this code (I've only checked this visually, no actual testing done):
Code:
MATRIX3 rotVesselCurrent; // current rotation matrix for the vessel
GetRotationMatrix(rotVesselCurrent);

VECTOR3 vesselZCurrent=_V(0,0,1); // current direction of the vessel nose, now in local vessel coordinates
vesselZCurrent = mul(rotVesselCurrent,vesselZCurrent); // convert to ecliptic frame

VECTOR3 r;
GetRelativePos(GetSurfaceRef(),r); // radius vector
r = r/length(r); // normalise

VECTOR3 headingPlane, heading;
headingPlane = crossp(r,vesselZCurrent); // get heading plane
heading = crossp(headingPlane,r); // get heading vector
heading = heading/length(heading); // normalise

VECTOR3 vesselXRequired;
vesselXRequired = crossp(r,heading); // no need to normalise, r and heading are already normalised and orthogonal

MATRIX3 rotVesselRequired = // build required rotation matrix as direction cosine matrix
	_M(	vesselXRequired.x,	r.x,	heading.x,
		vesselXRequired.y,	r.y,	heading.y,
		vesselXRequired.z,	r.z,	heading.z);

SetRotationMatrix(rotVesselRequired); // set the vessel attitude
 
Last edited:
E

ex-orbinaut

Guest
I don't have time to code it up atm, but here is what I think you want to do, in pseudo-code:

1. Get the vessel rotation matrix.
2. Get a vector that corresponds to a plane of constant heading. This can be determined from the cross product of the radius vector and a vector pointing the direction of the vessel's nose (vessel +z).
3. The cross product of the vector derived in step 2 with the radius vector will give you the vector that the nose needs to be aligned to.
4. The cross product of the nose vector from 3 with the radius vector will give the vector that the vessel +x needs to aligned to.
5. The radius vector gives you the vector that tge vessel +y needs to be aligned to.
6. Normalise the results from steps 3, 4, 5 and put them in as the colum vectors of a 3x3 matrix. This matrix is your direction cosine matrix, or rotation matrix, from the ecliptic frame to the desired local vessel frame. Use SetRotationMatrix to set it.

Does that make sense?

That is essentially what I am trying to do.

Try this code (I've only checked this visually, no actual testing done):

Though I am going to have to manually hold in a circuit breaker or two in order to get my head completely around that, I see the point, and yes it more or less what I am after. By the cross product you are obtaining the normal of the "plane" of each axis, as relative to the planet surface and the radius, as I had described in the previous post, which is essentially what I want to parallel each axis of the vessel to. That is as much as I understand of it (and sorry, I have not yet had the opportunity to try the code).

However, it does give me an idea. Isn't HorizonInvRot() already "kind of" getting this? I am probably wrong, but maybe that, done for each axis, can be fed straight into SetRotationMatrix(). Worth a try, perhaps.

Many thanks and respects, tblaxland! :tiphat:
 

tblaxland

O-F Administrator
Administrator
Addon Developer
Webmaster
Joined
Jan 1, 2008
Messages
7,320
Reaction score
25
Points
113
Location
Sydney, Australia
Though I am going to have to manually hold in a circuit breaker or two in order to get my head completely around that
Nice image for me there... :lol:
By the cross product you are obtaining the normal of the "plane" of each axis, as relative to the planet surface and the radius, as I had described in the previous post, which is essentially what I want to parallel each axis of the vessel to.
Yes and no.

headingPlane defines a plane of constant heading. Imagine if your vessel is sitting at lat=0, lon=0 and the nose facing due east. headingPlane would point due south (we are doing left handed cross products here BTW). Any vector in the plane perpendicular to headingPlane will also be pointing due east (for -90° < pitch < +90°). Any vector crossed with headingPlane will lie in that plane. Since you also want pitch=0, the direction the nose points also needs to be perpendicular to the radius vector. The cross product of headingPlane and the radius vector will give you a vector that lies in the same plane as the original heading as well as being horizontal wrt the surface.

The reason for that long-winded explanation is to demonstrate that the vector "heading" does not define a plane, it defines the direction the nose needs to point, measured against the in the ecliptic reference frame. This becomes the z-column vector (or 3rd column) in your direction cosine matrix (so called because each term in that matrix corresponds to the cosine of the angular distance between the vector and the axis. Eg, the matrix member R_13 is the cosine of the angular distance between the +z vector of the rotated frame (3rd column) and the +x axis of the reference frame (1st row)).

The other axes of the target rotation are defined similarly, the important thing being that they are unit length and orthogonal.

However, it does give me an idea. Isn't HorizonInvRot() already "kind of" getting this? I am probably wrong, but maybe that, done for each axis, can be fed straight into SetRotationMatrix(). Worth a try, perhaps.
SetRotationMatrix requires a rotation matrix from the ecliptic frame to the vessel frame. HorizonInvRot will allow you to derive a rotation matrix from the local horizontal frame to the required vessel frame, but you will still need to derive a rotation matrix from the ecliptic frame to the local horizon frame. I alluded to this method in one of my earlier posts and it is quite doable, but it is easier (ie, simpler code and less CPU) to calculate the required vessel frame directly. IMHO, that is :)
 
E

ex-orbinaut

Guest
tblaxland said:
The reason for that long-winded explanation is to demonstrate that the vector "heading" does not define a plane, it defines the direction the nose needs to point, measured against the in the ecliptic reference frame.

Yeah, that particular part was understood previously. Originally, when I first started tackling this subject, I was even thinking of "using" the reference body's latitude and longitude to calculate these angles, but did not waste time with it as things like the planet's rotation and obliquity make it a bit complex against the global frame (to somewhat understate the problem).

SetRotationMatrix requires a rotation matrix from the ecliptic frame to the vessel frame. HorizonInvRot will allow you to derive a rotation matrix from the local horizontal frame to the required vessel frame, but you will still need to derive a rotation matrix from the ecliptic frame to the local horizon frame. I alluded to this method in one of my earlier posts and it is quite doable, but it is easier (ie, simpler code and less CPU) to calculate the required vessel frame directly. IMHO, that is :)

There is little doubt I am going to have to agree with you, eventually, on all the the above. At present I am still at the stage of figuring out the relations of the various OAPI functions (which, amusingly, are also eventually going to be bypassed). Some seriously mind warping stuff in there.

For example, this...

Global variables...

Code:
VECTOR3 GlobX, GlobY, GlobZ; 
MATRIX3 RotMatrix;

In the clbkPreStep()...

Code:
GlobalRot(_V(1,0,0), GlobX); 
GlobalRot(_V(0,1,0), GlobY); 
GlobalRot(_V(0,0,1), GlobZ); 
 
GetRotationMatrix(RotMatrix);

In the clbkDrawHUD()

Code:
int x, y; 
char buffer[250]; 
 
x = int(hps->W * 0.05);    y = int(hps->H * 0.22); 
sprintf_s(buffer, sizeof(buffer), "GlobalRotX(x,y,z)........: %0.2f %0.2f %0.2f", GlobX.x, GlobX.y, GlobX.z); 
TextOut(hDC, x, y, buffer, strlen(buffer)); 
 
// etc with the TextOut... 
sprintf_s(buffer, sizeof(buffer), "GlobalRotY(x,y,z)........: %0.2f %0.2f %0.2f", GlobY.x, GlobY.y, GlobY.z); 
sprintf_s(buffer, sizeof(buffer), "GlobalRotZ(x,y,z)........: %0.2f %0.2f %0.2f", GlobZ.x, GlobZ.y, GlobZ.z); 
sprintf_s(buffer, sizeof(buffer), "RotMatrix1(x,y,z)........: %0.2f %0.2f %0.2f", RotMatrix.m11, RotMatrix.m12, RotMatrix.m13); 
sprintf_s(buffer, sizeof(buffer), "RotMatrix2(x,y,z)........: %0.2f %0.2f %0.2f", RotMatrix.m21, RotMatrix.m22, RotMatrix.m23); 
sprintf_s(buffer, sizeof(buffer), "RotMatrix3(x,y,z)........: %0.2f %0.2f %0.2f", RotMatrix.m31, RotMatrix.m32, RotMatrix.m33);

I honestly figured that the GlobalRot() would produce the same vectors as the Rotation Matrix rows (it made sense to assume so, it seemed) using positive normals. Yet some of them seem to be based on the -1, and not the positive, of an axis as I obtain them in the functions above. Identical vectors, but the other side of the number line. Why is the Rotation Matrix (or conversely, GlobalRot) done like this?

Again, it is all learning at present, in very quick snaps and snatches. I cannot (will not) implement your code without understanding it, or the basis that it is working with from Orbiter, or I am just asking to confuse myself. Some leave due to me in September, if I haven't clicked by then, that will be when it happens. Looking forward to it, many thanks again!
 

tblaxland

O-F Administrator
Administrator
Addon Developer
Webmaster
Joined
Jan 1, 2008
Messages
7,320
Reaction score
25
Points
113
Location
Sydney, Australia
There is little doubt I am going to have to agree with you, eventually, on all the the above.
We have ways... :lol:

I honestly figured that the GlobalRot() would produce the same vectors as the Rotation Matrix rows
Columns should be the same. So:
Code:
assert(GlobX.x == RotMatrix.m11); assert(GlobY.x == RotMatrix.m12); assert(GlobZ.x == RotMatrix.m13);
assert(GlobX.y == RotMatrix.m21); assert(GlobY.y == RotMatrix.m22); assert(GlobZ.y == RotMatrix.m23); 
assert(GlobX.z == RotMatrix.m31); assert(GlobY.z == RotMatrix.m32); assert(GlobZ.z == RotMatrix.m33);
should all evaluate true.

Also, try this:
Code:
VECTOR3 vesselZ = _V(1,0,0);

MATRIX3 vesselRot;
GetRotationMatrix(vesselRot);
VECTOR3 vesselZEcliptic1 = mul(vesselRot,vesselZ);

VECTOR3 vesselZEcliptic2;
GlobalRot(vesselZ,vesselZEcliptic2);

assert(vesselZEcliptic1 == vesselZEcliptic2);
should also evaluate true. (CAUTION: Code for illustration only, note possible danger comparing doubles: http://orbiter-forum.com/blog.php?b=346)
 
Last edited:

jedidia

shoemaker without legs
Addon Developer
Joined
Mar 19, 2008
Messages
10,842
Reaction score
2,105
Points
203
Location
between the planets
I don't mean to hijack the thread, but accidentaly I have a (hopefully simple) question that just fits into the topic...

I know how to receive a normalised orientation vector from a vessel, using VESSEL::GlobalRot

I then rotate this vector to get a vector into the new heading, now I should convert it back to Euler angles that I can feed to VESSEL::SetGlobalOrientation (or, more specific, output into the scenario file I'm using for switching my solar systems).

Is there a function somewhere in the API that lets me do this? I couldn't find anything yet.
 
E

ex-orbinaut

Guest
(CAUTION: Code for illustration only, note possible danger comparing doubles: http://orbiter-forum.com/blog.php?b=346)

tblaxland...

Good blog. Did not realize there was this potential problem.

Also, I know now where all those functions in your code are coming from: Found them in the 2010 Orbiter API. When I first saw them I thought they were from some obscure math_something.h or STL library! I have not had as much time to digest the new API manual as I did the 2006 API, and there's a good deal more of it to digest. However, it is excellent that they are now included. So, with that resolved, I tried your code and it does work a treat. That, and I was beginning to think I was being insulting by avoiding trying it. I have a slightly better grapple on this now to enable further progress. Still questions, but trying to answer them on my own first.

EDIT:
Hope you don't mind, I expanded the code a bit so that I could see what was going on. It is brilliant. First time in a while I have been able to put in a good 12 hours of C++. Likely be a while before I can do so again, too. Made for a good tutorial and gave credence to a "change being as good as a rest".

Many, many thanks for your time, expertise and attention! Till the next time, all the best.
:thumbup:

I don't mean to hijack the thread, but accidentaly I have a (hopefully simple) question that just fits into the topic...

I know how to receive a normalised orientation vector from a vessel, using VESSEL::GlobalRot

I then rotate this vector to get a vector into the new heading, now I should convert it back to Euler angles that I can feed to VESSEL::SetGlobalOrientation (or, more specific, output into the scenario file I'm using for switching my solar systems).

Is there a function somewhere in the API that lets me do this? I couldn't find anything yet.

No worries about hijacking. This is about having it out with those rotation functions, after all. Not too sure if what you are after is the matrix to Euler formula found on page 355 of the 2010 API manual? But surely, you MUST have already seen that, so I don't think I am being of much help here...
 
Last edited by a moderator:

jedidia

shoemaker without legs
Addon Developer
Joined
Mar 19, 2008
Messages
10,842
Reaction score
2,105
Points
203
Location
between the planets
Not too sure if what you are after is the matrix to Euler formula found on page 355 of the 2010 API manual?

ah no, I'm looking for a way to convert a directional vector back into Euler angles.
 

tblaxland

O-F Administrator
Administrator
Addon Developer
Webmaster
Joined
Jan 1, 2008
Messages
7,320
Reaction score
25
Points
113
Location
Sydney, Australia
ah no, I'm looking for a way to convert a directional vector back into Euler angles.
The direction vectors of the vessels +X, +Y and +Z axes form the three columns of the rotation matrix, as explained above. If you want to set the vessel orientation you can:
1. Use SetRotationMatrix
2. Use the rotation matrix to calculate the Euler angles and use SetGlobalOrientation. The API Reference for SetGlobalOrientation gives the Euler angles as a function of the rotation matrix terms.
 

jedidia

shoemaker without legs
Addon Developer
Joined
Mar 19, 2008
Messages
10,842
Reaction score
2,105
Points
203
Location
between the planets
ok, just to see wheather I got that right:

Code:
MATRIX3 MyMatrix;
VECTOR3 HeadVec;
vessel->GlobalRot(v_(0,0,1), HeadVec);

MyMatrix.m11 = HeadVec.x;
MyMatrix.m12 = HeadVec.y;
MyMatrix.m13 = HeadVec.z;

MyMatrix.m21 = HeadVec.x;
MyMatrix.m22 = HeadVec.y;
MyMatrix.m23 = HeadVec.z;

MyMatrix.m31 = HeadVec.x;
MyMatrix.m32 = HeadVec.y;
MyMatrix.m33 = HeadVec.z;

vessel->SetRotationMatrix(MyMatrix);
Is that it, or have I understoond everything completely wrong?

Edit: Nope, doesn't work...

Made some more modifications, but it still doesn't work. Major trouble is that I don't know what exactly I have to rotate by what, so here goes my code. The ships orientation should be rotated to galactic frame, and after that into the frame of the new ecliptic. It works for Velocity and Position, so the transformations are ok, but there I can work with vectors right away and don't have to bother about the angles. The ship should in the end point to the same direction in relation to the target star as it has before (which is usually right at it). So here goes the whole code:
Code:
                            VECTOR3 HeadX, HeadY, HeadZ;    
                            VECTOR3 mROT;
                            MATRIX3 HeadMatrix;

                            ship->GlobalRot(_V(1,0,0), HeadX);     
                            ship->GlobalRot(_V(0,1,0), HeadY);     
                            ship->GlobalRot(_V(0,0,1), HeadZ);     

                            double phi = data.SourceStar->EclipticRot.X *RAD;
                            double theta = data.SourceStar->EclipticRot.Y *RAD;
                            double lambda = data.SourceStar->EclipticRot.Z *RAD;    

                            double sint = sin(theta), cost = cos(theta);
                            double sinp = sin(phi), cosp = cos(phi);
                            double sinl = sin(lambda), cosl = cos(lambda);

                            MATRIX3 gal2ecl =  mul(mul(_M(cosp,0,sinp, 0,1,0, -sinp,0,cosp),
                                   _M(1,0,0, 0,cost,sint, 0,-sint,cost)),
                                   _M(cosl,0,-sinl, 0,1,0, sinl,0,cosl));
                            HeadX = tmul (gal2ecl, HeadX);        
                            HeadY = tmul (gal2ecl, HeadY);        
                            HeadZ = tmul (gal2ecl, HeadZ);        


                            phi = data.TargetStar->EclipticRot.X *RAD;
                            theta = data.TargetStar->EclipticRot.Y *RAD;
                            lambda = data.TargetStar->EclipticRot.Z *RAD;    

                            sint = sin(theta), cost = cos(theta);
                            sinp = sin(phi), cosp = cos(phi);
                            sinl = sin(lambda), cosl = cos(lambda);

                            gal2ecl =  mul(mul(_M(cosp,0,sinp, 0,1,0, -sinp,0,cosp),
                                   _M(1,0,0, 0,cost,sint, 0,-sint,cost)),
                                   _M(cosl,0,-sinl, 0,1,0, sinl,0,cosl));
                            HeadX = mul (gal2ecl, HeadX);    
                            HeadY = mul (gal2ecl, HeadY);    
                            HeadZ = mul (gal2ecl, HeadZ);    

                            HeadMatrix.m11 = HeadX.x;
                            HeadMatrix.m12 = HeadY.x;
                            HeadMatrix.m13 = HeadZ.x;

                            HeadMatrix.m21 = HeadX.y;
                            HeadMatrix.m22 = HeadY.y;
                            HeadMatrix.m23 = HeadZ.y;
                            
                            HeadMatrix.m31 = HeadX.z;
                            HeadMatrix.m32 = HeadY.z;
                            HeadMatrix.m33 = HeadZ.z;

                            ship->SetRotationMatrix(HeadMatrix);
                            ship->GetGlobalOrientation(mROT);

                            oapiWriteScenario_vec( ScenarioOut, "AROT", mROT);
 
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
Close. Two things:
1. Your single vector, HeadVec, does not contain enough information to completely describe the rotation from one reference frame to another. You need three vectors for that. (EDIT: Or an axis vector and an angle, but that is a different scenario to what we are trying to do here...)
2. You put the vector into the rotation matrix in rows when you should be using columns.

Like this:
Code:
MATRIX3 MyMatrix;
VECTOR3 HeadVecX, HeadVecY, HeadVecZ;
vessel->GlobalRot(_V(1,0,0), HeadVecX);
vessel->GlobalRot(_V(0,1,0), HeadVecY);
vessel->GlobalRot(_V(0,0,1), HeadVecZ);

MyMatrix.m11 = HeadVecX.x;
MyMatrix.m21 = HeadVecX.y;
MyMatrix.m31 = HeadVecX.z;

MyMatrix.m12 = HeadVecY.x;
MyMatrix.m22 = HeadVecY.y;
MyMatrix.m32 = HeadVecY.z;

MyMatrix.m13 = HeadVecZ.x;
MyMatrix.m23 = HeadVecZ.y;
MyMatrix.m33 = HeadVecZ.z;

vessel->SetRotationMatrix(MyMatrix);
 

jedidia

shoemaker without legs
Addon Developer
Joined
Mar 19, 2008
Messages
10,842
Reaction score
2,105
Points
203
Location
between the planets
Still doesn't work... the trouble is, I have to rotate the heading (see the second code I posted above), and I'll probably have to rotate the three vectors differently so they add up to something meaningfull in the end... the question is just how?
 
Top