Vector3D.rotateBy() wrong? --> Is correct

For test results, bug reports, announcements of new builds etc.

Moderators: winston, another_commander, Getafix

Post Reply
User avatar
Eric Walch
Slightly Grand Rear Admiral
Slightly Grand Rear Admiral
Posts: 5536
Joined: Sat Jun 16, 2007 3:48 pm
Location: Netherlands

Vector3D.rotateBy() wrong? --> Is correct

Post by Eric Walch »

It seems to me that the JS Vector3D command rotateBy() is broken. Or maybe I do not understand it well.

What is the problem. I have a ship with subentities and want to know the absolute position of the subentity. For the mother I can get the position but for the subentity I get the relative position as defined in shipData.

Okay, no problem I though, next function should do the trick were position is the relative position of the subentity. Rotate the relative vector according to the orientation of the main ship.:

Code: Select all

this.localToGlobal = function(position)
{
	return this.ship.position.add(position.rotateBy(this.ship.orientation));
}
But no, it gave wrong results. In buoyRepair.oxp I used a much more complex formula to calculate these positions by literally retransform the quaternion to 3 dimensional coordinates. Very intense in calculations but correct. I compared these correct results with a few variations and noticed when I first flip the w-component of the quaternion, the result becomes correct:

Code: Select all

this.localToGlobal = function(position)
{
	var orientation = this.ship.orientation
	orientation.w = -orientation.w
	return this.ship.position.add(position.rotateBy(orientation));
}
For me it seems logical that when I rotate a relative vector of an entity according to its quaternion, it should end up with its real position. But I fail to understand why I need to flip the w-component first. Or is it a bug in the underlying C function quaternion_rotate_vector in OOQuaternion.m ?

I noticed this function was added in oolite 1.70 (couldn't find it in 1.69) so it could be the normal game doesn't use it and therefor is never tested.
User avatar
Eric Walch
Slightly Grand Rear Admiral
Slightly Grand Rear Admiral
Posts: 5536
Joined: Sat Jun 16, 2007 3:48 pm
Location: Netherlands

Post by Eric Walch »

Oolites js rotateBy() is correct. I found on the wikipedia another formula to rotate a vector according to a quaternion: "Quaternions and spatial rotation".

From that info I constructed a rotateBy() of my own in JS code:

Code: Select all

this.rotateBy = function(position, orientation)
	{
	var t2, t3, t4, t5, t6, t7, t8, t9, t10;
	var result = new Vector3D();

	t2 =   orientation.w * orientation.x
	t3 =   orientation.w * orientation.y
	t4 =   orientation.w * orientation.z
	t5 =  -orientation.x * orientation.x
	t6 =   orientation.x * orientation.y
	t7 =   orientation.x * orientation.z
	t8 =  -orientation.y * orientation.y
	t9 =   orientation.y * orientation.z
	t10 = -orientation.z * orientation.z
	result.x = 2*( (t8 + t10)*position.x + (t6 -  t4)*position.y + (t3 + t7)*position.z ) + position.x
	result.y = 2*( (t4 +  t6)*position.x + (t5 + t10)*position.y + (t9 - t2)*position.z ) + position.y
	result.z = 2*( (t7 -  t3)*position.x + (t2 +  t9)*position.y + (t5 + t8)*position.z ) + position.z

	return result;
	}
This is formulated different than the one in oolites own C-code:

Code: Select all

Vector quaternion_rotate_vector(Quaternion q, Vector v)
{
	Quaternion				qv;
	
	qv.w = 0 - q.x * v.x - q.y * v.y - q.z * v.z;
	qv.x = q.w * v.x + q.y * v.z - q.z * v.y;
	qv.y = q.w * v.y + q.z * v.x - q.x * v.z;
	qv.z = q.w * v.z + q.x * v.y - q.y * v.x;
	// w is ignored.
	v.x = qv.w * -q.x + qv.x * q.w + qv.y * -q.z - qv.z * -q.y;
	v.y = qv.w * -q.y + qv.y * q.w + qv.z * -q.x - qv.x * -q.z;
	v.z = qv.w * -q.z + qv.z * q.w + qv.x * -q.y - qv.y * -q.x;
	return v;
}
The code from the wikipedia looks even faster as it uses 3 multiplication less and both use the same number of additions/subtractions

But both codes gives exact the same result. From that I can conclude both must be correct and there is no oolite bug.

When using a ships orientation both only gives correct results with an inverted w-component of the orientation. This w-inversion seems still strange to me but is apparently correct.
User avatar
DaddyHoggy
Intergalactic Spam Assassin
Intergalactic Spam Assassin
Posts: 8515
Joined: Tue Dec 05, 2006 9:43 pm
Location: Newbury, UK
Contact:

Post by DaddyHoggy »

I think I followed that.... :roll: :wink:
Selezen wrote:
Apparently I was having a DaddyHoggy moment.
Oolite Life is now revealed here
User avatar
Eric Walch
Slightly Grand Rear Admiral
Slightly Grand Rear Admiral
Posts: 5536
Joined: Sat Jun 16, 2007 3:48 pm
Location: Netherlands

Post by Eric Walch »

DaddyHoggy wrote:
I think I followed that.... :roll: :wink:
Looks more complex than it is. Original I used next formula to do the transformation of local subentity ship positions to global positions:

Code: Select all

this.localToGlobal = function(position)
{
    var newPosition = New Vector3D([0,0,0])
    newPosition = newPosition.add(this.ship.orientation.vectorRight().multiply(position.x))
    newPosition = newPosition.add(this.ship.orientation.vectorUp().multiply(position.y))
    newPosition = newPosition.add(this.ship.orientation.vectorForward().multiply(position.z))
    return this.ship.position.add(newPosition)
}
Looks much shorter but when writing out in the underlying calculations it probably takes 5 times as much multiplications.

I used it in buoyRepair.oxp and also noticed Frame is using it in his save-everywhere.oxp. But even calculating the forward vector alone from a quaternion, takes more calculations than the whole rotation calculation in my previous message. So I wanted to switch to using rotateBy().

It just strikes me as odd that I here use the orientation as it is while I have to invert the w-component with the other formula. This w-component contains the rotation part of the orientation and it is probably not defined unique if we have to call a left or a right rotation as positive.

For scripters it probably would have been easier when the formula itself would have used inverted w-components. With Thargoid there are now already 3 scripters using these transformations. Probably it is wise I put a remark on the wiki that rotateBy() needs an inverted w-component to work correctly with ship orientations.
another_commander
Quite Grand Sub-Admiral
Quite Grand Sub-Admiral
Posts: 6632
Joined: Wed Feb 28, 2007 7:54 am

Post by another_commander »

Eric, is this a player ship you were testing? I don't know what exactly you were trying to do, but the code has plenty of things like

Code: Select all

q1.w = -q1.w;   // player view is reversed remember!
Maybe what you saw is related to this?
Last edited by another_commander on Wed Apr 22, 2009 4:49 pm, edited 1 time in total.
User avatar
Thargoid
Thargoid
Thargoid
Posts: 5528
Joined: Thu Jun 12, 2008 6:55 pm

Post by Thargoid »

No, it's for an NPC (my new Hammerhead hauler and it's cargo sleds). I initially thought the same remembering back to that bug, but that only applied to player ships (?).

When in-flight the sleds are sub-ents of the main ship, but on arrival they swap for separate ships and fly off to dock with the station. But when I (and then we) tried that, we couldn't get the position co-ordinates to work using the initial formula Eric posted (although the longer one worked fine).
User avatar
Eric Walch
Slightly Grand Rear Admiral
Slightly Grand Rear Admiral
Posts: 5536
Joined: Sat Jun 16, 2007 3:48 pm
Location: Netherlands

Post by Eric Walch »

another_commander wrote:
Eric, is this a player ship you were testing? I don't know what exactly you were trying to do, but the code has plenty of things like

Code: Select all

q1.w = -q1.w;   // player view is reversed remember!
Maybe what you saw is related to this?
No it was a NPC ship but because I also remembered that w-inversion for he player, it was the fist thing I tried to solve the problem. When using other code to rotate a vector according to the quaternion, this flip was not necessary. I think it happens because there is no uniform definition for witch rotation direction is positive. Different formulas handle this different. That is probably also the reason why Ahruman placed a lot of remarks at the wiki page about quaternions about "left?" or "right?" with rotations.

I was just curious if this code is used elsewhere in Oolite itself as it clearly uses an other positive rotation direction as its internal quaternions.

EDIT:
Searching in the code, this rotation function of a vector according to a quaternion is only used once in all that line of code. In planetEntity.m to set the rotation axis of a planet. No idea if this axes are currently okay or suffer the same problem. When not okay, you should see it by not rotating along a vector through the poles.
And I remember vaguely some message of McLane from a few years back about planets he textured, not rotating right. here
One of the things he describes is planets not rotating through the poles.
Post Reply