Welcome to the Second Life Forums Archive

These forums are CLOSED. Please visit the new forums HERE

Stored rotation that adjusts to a new rotation accordingly.

Yingzi Xue
Registered User
Join date: 11 Jun 2008
Posts: 144
12-05-2008 05:35
Ugh, I hate rotation calculations. I need a quick snippet of code that adjusts my stored rotation with the current rotation, so that no matter what the new rotation is it still performs the rotation I have stored, but accordingly with the new rotation. I just need the line that calculates the rotation. Thanks. :)
Jeredin Denimore
Romani Ite Domum
Join date: 5 Jul 2008
Posts: 95
12-05-2008 06:13
From: Yingzi Xue
Ugh, I hate rotation calculations. I need a quick snippet of code that adjusts my stored rotation with the current rotation, so that no matter what the new rotation is it still performs the rotation I have stored, but accordingly with the new rotation. I just need the line that calculates the rotation. Thanks. :)


I think the examples on the wiki provide help...
CODE

// do a local rotation by multiplying a constant rotation by a world rotation
rotation localRot = new_rot * current_rot;
// do a global rotation by multiplying a world rotation by a constant rotation
rotation globalRot = current_rot * new_rot;


The above came from:
http://wiki.secondlife.com/wiki/Rotation

Basically, multiply your new * current if you want it rotated around the
local axis and multiply current * new if you want it rotated around the
region axis.

Now I'm no expert on rotations, so hopefully someone with more
experience can verify this is the case.
Yingzi Xue
Registered User
Join date: 11 Jun 2008
Posts: 144
12-05-2008 06:15
I've tried multiplying but it just rotates it by one quarter turn one direction and another. Weird. I've tried all kinds of stuff and I've been referencing both wikis. You would think someone would've posted something like this on the wiki a long time ago. *sigh* I'll keep trying.
Jeredin Denimore
Romani Ite Domum
Join date: 5 Jul 2008
Posts: 95
12-05-2008 06:18
From: Yingzi Xue
I've tried multiplying but it just rotates it by one quarter turn one direction and another. Weird. I've tried all kinds of stuff and I've been referencing both wikis. You would think someone would've posted something like this on the wiki a long time ago. *sigh* I'll keep trying.


Have you verified that the order of all your rotations are the intended effect as
per what I said above? IE local vs global based on operation order?
Yingzi Xue
Registered User
Join date: 11 Jun 2008
Posts: 144
12-05-2008 06:30
Yes. I am using a single prim. I'm assuming with a single non-linked prim I use global rotation (i.e. not local), correct? Here's what I'm doing...

On start the script waits for you to rotate your prim in the closed position. You then touch the prim to set it. Next, move the prim to a new rotation and touch the prim to set the open rotation. The script then toggles between open/close rotations and works fine if you use llSetRot(open_rot) and llSetRot(closed_rot) as long a you don't move your prim, but if you move the prim by rotating it to another rotation it doesn't adjust correctly to the new rotation using llGetRot() * open_rot (or closed_rot). What this does is seem to rotate the prim 1/4 turn in two directions.

I want to be able to move my prim any rotation and have it rotate as intended based on the store rotations in relation to the new rotation.

From: someone

integer toggle; // toggles between open and close
integer touches; // counter for open/close storage

rotation closed_rot;
rotation open_rot;

default
{
state_entry()
{
toggle = FALSE;
touches = 0;
}

touch_start(integer total_number)
{
//Store closed position
if (touches == 0) // store closed position
{
closed_rot = llGetRot();

llOwnerSay("Closed set.";);
touches = 1;
return;

} else if (touches == 1) // store open position
{
open_rot = llGetRot();

llOwnerSay("Open set.";);
touches = 2; // disable storage

//Set closed postion
llSetRot(closed_rot);
return;
}

// Toggle back and forth between open and closed positions
if (toggle == FALSE)
{
// Here's where the script fails to rotate correctly
llSetRot(llGetRot()*open_rot);
toggle = TRUE;

} else
{
// Here's where the script fails to rotate correctly
llSetRot(llGetRot()*closed_rot);
toggle = FALSE;
}
}
}

Jeredin Denimore
Romani Ite Domum
Join date: 5 Jul 2008
Posts: 95
12-05-2008 06:57
From: Yingzi Xue
Yes. I am using a single prim. I'm assuming with a single non-linked prim I use global rotation (i.e. not local), correct? Here's what I'm doing...

On start the script waits for you to position your prim in the closed position/rotation. You then touch the prim to set it. Next, move the prim to a new position/rotation and touch the prim to set the open position/rotation. The script then toggles between open/close positions and works fine if you use llSetRot(open_rot) and llSetRot(closed_rot) as long a you don't move your prim, but if you move the prim by rotating it elsewhere it doesn't adjust correctly to the new rotation using llGetRot() * open_rot (or closed_rot). What this does is seem to rotate the prim 1/4 turn in two directions.

I want to be able to move my prim any rotation and position and have it rotate as intended based on the new rotation and position.


Based off what I see, you're storing a global rotation in closed_rot and
another one in open_rot and you want to ping pong between them. If
that is the case, you shouldn't need to use llGetRot() at all in your
llSetRot() calls. Just use open_rot and closed_rot. You will also need to
store the open and closed positions and apply the offsets if the prim's
center is moved between the open and closed positions.

Basically store the closed global rotation and position and then the open
global rotation and position. To swap between them, set the stored position
and rotation without alteration.
Yingzi Xue
Registered User
Join date: 11 Jun 2008
Posts: 144
12-05-2008 07:01
Yes, that does work, but what if you rotate the prim 90 degrees (manually) to a face a different direction and you want the rotations you stored to adjust to that new rotation? The method you describe works fine if you want the prim to always use the same rotations regardless of the prim's current position (in your last post it would jump back to the previous 90 degrees it was facing and do the original rotations), but if you want it to adjust relative to the new rotation of the prim based on the store rotations then it doesn't work.
Jeredin Denimore
Romani Ite Domum
Join date: 5 Jul 2008
Posts: 95
12-05-2008 07:14
Well if you're asking them to store open and closed, I would use a listen
for a reset and reset the script so they can set the new open and closed
rotations and store them. Basically you've created a "store the rotations"
system and logically if they alter it manually after storage, you should
advise them to apply a reset. Another way to handle it is to check at
the end of each llSetRot if llGetRot()=open_rot or llGetRot=closed_rot
as appropriate and if they don't match, you know it's been moved, so
reset yourself with a message saying "prim moved, please store
new closed and open positions" or something similar.
Yingzi Xue
Registered User
Join date: 11 Jun 2008
Posts: 144
12-05-2008 07:36
The problem with that is I want to be able to sell items that don't require resets and readjustments by the customer to function properly. I know of at least one product being sold on XStreetSL that records like this and runs the stored movements (rotations) without having to reset, so it has to be possible.
Jeredin Denimore
Romani Ite Domum
Join date: 5 Jul 2008
Posts: 95
12-05-2008 07:42
Oh I'm sure it's possible. It's just my logical brain revolting at the concept
of storing an open/closed set of positions/rotations, but not forcing them
to restore them if they move it hehe ;)

I'll think about it more and see what I can come up with in case nobody
else answers :)
Yingzi Xue
Registered User
Join date: 11 Jun 2008
Posts: 144
12-05-2008 07:50
Since so many people have problems with rotations, something like this should be in the library and readily available. It would solve a lot of the struggles people have with rotations. I appreciate your help. Hopefully someone out there has an answer.
Hewee Zetkin
Registered User
Join date: 20 Jul 2006
Posts: 2,702
12-05-2008 10:15
Try this. :)

CODE

integer isOpen = FALSE;
integer nTouches = 0;

rotation initialClosedRot;
rotation closedToOpenRelRot;

open()
{
llSetRot(closedToOpenRelRot*llGetRot());
isOpen = TRUE;
}

close()
{
llSetRot((ZERO_ROTATION/closedToOpenRelRot)*llGetRot());
isOpen = FALSE;
}

default
{
touch_start(integer nDetected)
{
if (nTouches == 0)
{
initialClosedRot = llGetRot();
++nTouches;

llOwnerSay("Closed set.");
} else if (nTouches == 1)
{
closedToOpenRelRot = llGetRot()/initialClosedRot;
++nTouches;

llOwnerSay("Open set.");

close();
} else if (!isOpen)
{
open();
} else
{
close();
}
}
}


EDIT: Added llOwnerSay() messages from above script.
Yingzi Xue
Registered User
Join date: 11 Jun 2008
Posts: 144
12-05-2008 12:21
*hands Hewee a beer* Thanks so much. Do I have your permission to add this one to the library?
Hewee Zetkin
Registered User
Join date: 20 Jul 2006
Posts: 2,702
12-05-2008 14:29
From: Yingzi Xue
*hands Hewee a beer* Thanks so much. Do I have your permission to add this one to the library?

Sure. No problem. Enjoy. :)
Yingzi Xue
Registered User
Join date: 11 Jun 2008
Posts: 144
12-07-2008 05:29
Ok, now I'm trying to incorporate position into the mix for the unlinked prim. Here's what I have (same script as before, but now with position). When I use the llGetPos()+offset it works at the same rotation, but if I add * llGetRot() it jumps all over the place and doesn't stay where it needs to be. This is for an unlinked prim that moves as well as rotates. I just need to get the position offset calculation to work right no matter the new position and rotation.

From: someone

integer toggle = FALSE;
integer touches = 0;

rotation closed_rot;
rotation open_rot;
vector open_pos;
vector closed_pos;
vector offset;

open()
{
llSetPos(llGetPos()+offset*llGetRot());
llSetRot(open_rot*llGetRot());
toggle = TRUE;
}

close()
{
llSetPos(llGetPos()-offset*llGetRot());
llSetRot((ZERO_ROTATION/open_rot)*llGetRot());
toggle = FALSE;
}

default
{
touch_start(integer nDetected)
{
if (touches == 0)
{
closed_pos = llGetPos();
closed_rot = llGetRot();
++touches;

llOwnerSay("Closed set.";);
} else if (touches == 1)
{
open_pos = llGetPos();
offset = open_pos - closed_pos;
open_rot = llGetRot()/closed_rot;
llOwnerSay("c:"+(string)closed_pos+"o:"+(string)open_pos+"-/+"+(string)offset);
++touches;

llOwnerSay("Open set.";);

close();
} else if (!toggle)
{
open();
} else
{
close();
}
}
}
Hewee Zetkin
Registered User
Join date: 20 Jul 2006
Posts: 2,702
12-07-2008 08:30
The position offset also has to be calculated based on the prim's original rotation, and it has to be either the closed or the open position. Try this:

CODE

integer isOpen = FALSE;
integer nTouches = 0;

rotation initialClosedRot;
vector initialClosedPos;
rotation closedToOpenRelRot;
vector closedToOpenRelOffset;

open()
{
rotation closedRot = llGetRot();
llSetPrimitiveParams(
[ PRIM_POSITION, llGetPos()+closedToOpenRelOffset*closedRot,
PRIM_ROTATION, closedToOpenRelRot*closedRot ]);
isOpen = TRUE;
}

close()
{
rotation closedRot = (ZERO_ROTATION/closedToOpenRelRot)*llGetRot();
llSetPrimitiveParams(
[ PRIM_POSITION, llGetPos()-closedToOpenRelOffset*closedRot,
PRIM_ROTATION, closedRot ]);
isOpen = FALSE;
}

default
{
touch_start(integer nDetected)
{
if (nTouches == 0)
{
initialClosedRot = llGetRot();
initialClosedPos = llGetPos();
++nTouches;

llOwnerSay("Closed set.");
} else if (nTouches == 1)
{
closedToOpenRelRot = llGetRot()/initialClosedRot;
closedToOpenRelOffset = (llGetPos()-initialClosedPos)/initialClosedRot;
++nTouches;

llOwnerSay("Open set.");

close();
} else if (!isOpen)
{
open();
} else
{
close();
}
}
}
Yingzi Xue
Registered User
Join date: 11 Jun 2008
Posts: 144
12-07-2008 10:42
Awesome work Hewee. Thank you so much for your help with this. I have everything I need now. :)
Yingzi Xue
Registered User
Join date: 11 Jun 2008
Posts: 144
12-08-2008 15:31
Well, I guess I wasn't done. :P I decided to go ahead and attempt to store more than two positions and use the relative rotation and offset to calculate my position and rotation based on the initial position and rotation (UNLINKED prim, not linked, I already have a working script for that). This way I could have as many movements as I want (this script is limited to three).

I know there's something simple wrong with my calculations. Something is off. I tried to base them on the previously posted script but the prim doesn't follow the expected path. It runs off on me. lol I'll keep trying. I've been working on this thing for 12 hours now. *sigh*
Hewee Zetkin
Registered User
Join date: 20 Jul 2006
Posts: 2,702
12-08-2008 15:38
When you store the offsets and rotations, you calculate them all relative to the initial position. When you move the object, you will need to essentially calculate where the initial position should be given the current position, then go forward again to the new location. The math can be simplified a bit from that, but if you do one step at a time it might be clearer and easier to understand for now. Alternately, since you seem to always rotate through the positions in order, you could store each relative to the previous position rather than the first position. Hope that helps.
Yingzi Xue
Registered User
Join date: 11 Jun 2008
Posts: 144
12-08-2008 15:44
I was trying to do that initially... store based on the previous position, but it got too convoluted. I'll take your advice and try some more. Thanks. :)
Yingzi Xue
Registered User
Join date: 11 Jun 2008
Posts: 144
12-08-2008 17:32
Eureka!! I hit paydirt! It took much trial and error, but I finally got it. Please keep in mind this is a test script and thus was written quick and dirty (a lot of repetition, no optimization).

I initially was basing my position and rotation relative to the initial position and rotation, but I kept failing miserably. I then tried my position and rotation on the previous position and rotation and things just fell into place. Here it is... a script that stores three positions and rotations of an unlinked prim and performs the forward and reverse animations correctly in relation to the position and rotation of the object. You can move it and rotate it and it still does the animation correctly at the new position and rotation.

Thanks for the help Hewee. I really appreciate it.

From: someone

integer toggle;
integer acquire=1;
rotation initial_rot;
vector initial_pos;
integer move_count=0;

vector pos1;
vector pos2;
vector pos3;
rotation rot1;
rotation rot2;
rotation rot3;
rotation rel1;
rotation rel2;
rotation rel3;
vector off1;
vector off2;
vector off3;


store()
{
move_count = move_count + 1;
if (move_count == 1)
{
pos1 = llGetPos();
rot1 = llGetRot();
rel1 = llGetRot()/initial_rot;
off1 = (llGetPos()-initial_pos)/initial_rot;

} else if (move_count == 2)
{
pos2 = llGetPos();
rot2 = llGetRot();
rel2 = llGetRot()/rot1;
off2 = (llGetPos()-pos1)/rot1;

} else if (move_count == 3)
{
pos3 = llGetPos();
rot3 = llGetRot();
rel3 = llGetRot()/rot2;
off3 = (llGetPos()-pos2)/rot2;

}

llOwnerSay("Stored "+(string)move_count+" of 3";);
acquire++;
}

default
{
state_entry()
{
initial_rot = llGetRot();
initial_pos = llGetPos();
toggle = FALSE;
llOwnerSay("Initial position/rotation stored. Please move your object and touch to store each position/rotation. Three will be stored, then when touched the animation will move forward. When touched again it will move backward.";);
}

touch_start(integer touches)
{
if (acquire == 1)
{
store();
return;
} else if (acquire == 2)
{
store();
return;
} else if (acquire == 3)
{
store();
acquire++;
}

if (acquire == 4)
{
llOwnerSay("Storage complete. Moved to original position. Touch prim to animate forward. Touch again to animate backward.";);
llSetPos(initial_pos);
llSetRot(initial_rot);
acquire++;
return;

} else if (acquire == 5)
{
if (toggle == FALSE)
{
//Animate forward
rotation temp_rot = llGetRot();
llSetPrimitiveParams([ PRIM_POSITION, llGetPos()+off1*temp_rot,PRIM_ROTATION,rel1*temp_rot]);
llSleep(.2);

temp_rot = llGetRot();
llSetPrimitiveParams([ PRIM_POSITION, llGetPos()+off2*temp_rot ,PRIM_ROTATION,rel2*temp_rot]);
llSleep(.2);

temp_rot = llGetRot();
llSetPrimitiveParams([ PRIM_POSITION, llGetPos()+off3*temp_rot ,PRIM_ROTATION,rel3*temp_rot]);

toggle = TRUE;
return;
}
else if (toggle == TRUE)
{
// Reverse the animation
rotation temp_rot = (ZERO_ROTATION/rel3)*llGetRot();
llSetPrimitiveParams([ PRIM_POSITION, llGetPos()-off3*temp_rot,PRIM_ROTATION, temp_rot]);
llSleep(.2);

temp_rot = (ZERO_ROTATION/rel2)*llGetRot();
llSetPrimitiveParams([ PRIM_POSITION, llGetPos()-off2*temp_rot,PRIM_ROTATION, temp_rot]);
llSleep(.2);

temp_rot = (ZERO_ROTATION/rel1)*llGetRot();
llSetPrimitiveParams([ PRIM_POSITION, llGetPos()-off1*temp_rot ,PRIM_ROTATION,temp_rot]);

toggle = FALSE;
}
}
}
}