Welcome to the Second Life Forums Archive

These forums are CLOSED. Please visit the new forums HERE

Edge Rotate Function

Bloodsong Termagant
Manic Artist
Join date: 22 Jan 2007
Posts: 615
03-10-2007 16:54
heyas;

ged wrote a nifty little function that rotates an object on its z edge. which will no doubt work for my flappy flexi wings.... ::has to get back to that sometime soon!:: but, i thought maybe i could expand it and... well, make it do more.

so i did, and this is what i came up with. HOWEVER, i only works if the prim is not rotated, or sometimes if it is only rotated on one axis. once it starts getting rotated more, simple x rotations start getting translated into y rotations and other crap which i just can't handle.
if anybody wants to tinker with it and make it work perfectly all the time -- good luck! but that would be nice.


CODE

//--edge rotate originally by ged
//--expanded by bloodsong
//--not very reliable unless prims aren't rotated much to start

//--side constants. pos is towards arrow point, neg is towards arrow butt
integer X_POS = 1;
integer X_NEG = 2;
integer Y_POS = 3;
integer Y_NEG = 4;
integer Z_POS = 5;
integer Z_NEG = 6;

//--axis constants
integer X_AXIS = 1;
integer Y_AXIS = 2;
integer Z_AXIS = 3;

//--RotFromEdge: (angle, edge, axis)
//-- input your degrees in normal everyday degrees
//-- input what edge you want the axis on
//-- and which axis you want to rotate about
RotFromEdge(float fAngle, integer iSide, integer iAxis)
{
//--part one initial setup
vector size = llGetScale(); //--gets length of sides to find edges.
vector currentRot = llRot2Euler(llGetLocalRot());

rotation desiredRot;
vector rotOriginBefore;

//--adjust for different axes and edges
if(iAxis == X_AXIS)
{
currentRot.x = fAngle*DEG_TO_RAD;
desiredRot = llEuler2Rot(currentRot);
}
else if (iAxis == Y_AXIS)
{
currentRot.y = fAngle*DEG_TO_RAD;
desiredRot = llEuler2Rot(currentRot);
}
else if (iAxis == Z_AXIS)
{
currentRot.z = fAngle*DEG_TO_RAD;
desiredRot = llEuler2Rot(currentRot);
}


if(iSide == X_POS)
{
rotOriginBefore = (llRot2Fwd(llGetLocalRot()) * size.x / 2.0);
}
else if (iSide == Y_POS)
{
rotOriginBefore = (llRot2Left(llGetLocalRot()) * size.y / 2.0);
}
else if (iSide == Z_POS)
{
rotOriginBefore = (llRot2Up(llGetLocalRot()) * size.z / 2.0);
}
else if (iSide == X_NEG)
{
rotOriginBefore = (llRot2Fwd(llGetLocalRot()) * (size.x / -2));
}
else if (iSide == Y_NEG)
{
rotOriginBefore = (llRot2Left(llGetLocalRot()) * (size.y / -2));
}
else if (iSide == Z_NEG)
{
rotOriginBefore = (llRot2Up(llGetLocalRot()) * (size.z / -2));
}

//--part two, more calculations
rotation newLocalRot = desiredRot * llGetLocalRot();
vector rotOriginAfter;

//--change from defaults, if needed
if(iSide == X_POS)
{
rotOriginAfter = (llRot2Fwd(newLocalRot) * size.x / 2.0);
}
else if (iSide == Y_POS)
{
rotOriginAfter = (llRot2Left(newLocalRot) * size.y / 2.0);
}
else if (iSide == Z_POS)
{
rotOriginAfter = (llRot2Up(newLocalRot) * size.z / 2.0);
}
else if (iSide == X_NEG)
{
rotOriginAfter = (llRot2Fwd(newLocalRot) * (size.x / -2));
}
else if (iSide == Y_NEG)
{
rotOriginAfter = (llRot2Left(newLocalRot) * (size.y / -2));
}
else if (iSide == Z_NEG)
{
rotOriginAfter = (llRot2Up(newLocalRot) * (size.z / -2));
}


//--part 3, apply the rotation
llSetPrimitiveParams([PRIM_POSITION, llGetLocalPos() + rotOriginBefore - rotOriginAfter, PRIM_ROTATION, newLocalRot]);

}



default
{
touch_start(integer num)
{
//--this is just a test to see if it works. this loops it around in a complete circle.
integer n;

for (n=0; n<12; ++n)
{
RotFromEdge(30.0, Z_NEG, X_AXIS);
}

}
}


Ged Larsen
thwarted by quaternions
Join date: 4 Dec 2006
Posts: 294
03-10-2007 17:54
The main reason I never expanded my code snippet was that it's very difficult to make generalizable. Sizes in the X, Y, and, Z dimensions are no longer accurate, if you have prim cuts / twists / skews, etc.

Calculating prim dimensions and the relative change of the "prim center" based on the primitive parameters -- now, that would be the true challenge.
_____________________
- LoopRez, flexi prim skirt generating tool
- LinkRez, a necklace chain generator
Bloodsong Termagant
Manic Artist
Join date: 22 Jan 2007
Posts: 615
03-15-2007 07:07
heh;

well, if i could cut the prim in half, i wouldn't have to rotate it from the edge now, would i? ;) but yeah, finding an edge on a mutated prim would be a pain. and calculating it from cuts and twists and... WAY too much math for me!
Bloodsong Termagant
Manic Artist
Join date: 22 Jan 2007
Posts: 615
Edge Rotation Fixed (almost works, but...)
03-16-2007 06:20
heyas;

okay, i found a MAJOR flaw in my function, which has to do with the start values for calculating the rots. ged just used 0's on his non-active axes, and i thought that would only work if the object wasn't rotated to start. and that i would have to start with the current rotation. well, turns out i was wrong.

only one line change:
vector currentRot = <0.0,0.0,0.0>;


now it works, no matter how you rotate the fool prim to start. yay!

the bad news is, it TOTALLY fails to work right if the prim is a child of anything. ::sob::

also as noted above, not 100% accurate for figuring 'edge' of cut/twisted/sheared/etc prims.


CODE

//--edge rotate originally by ged
//--expanded by bloodsong
//--not very reliable unless prims aren't rotated much to start

//--side constants. pos is towards arrow point, neg is towards arrow butt
integer X_POS = 1;
integer X_NEG = 2;
integer Y_POS = 3;
integer Y_NEG = 4;
integer Z_POS = 5;
integer Z_NEG = 6;

//--axis constants
integer X_AXIS = 1;
integer Y_AXIS = 2;
integer Z_AXIS = 3;

//--RotFromEdge: (angle, edge, axis)
//-- input your degrees in normal everyday degrees
//-- input what edge you want the axis on
//-- and which axis you want to rotate about
RotFromEdge(float fAngle, integer iSide, integer iAxis)
{
//--part one initial setup
vector size = llGetScale(); //--gets length of sides to find edges.
vector currentRot = <0.0,0.0,0.0>;

rotation desiredRot;
vector rotOriginBefore;

//--adjust for different axes and edges
if(iAxis == X_AXIS)
{
currentRot.x = fAngle*DEG_TO_RAD;
desiredRot = llEuler2Rot(currentRot);
}
else if (iAxis == Y_AXIS)
{
currentRot.y = fAngle*DEG_TO_RAD;
desiredRot = llEuler2Rot(currentRot);
}
else if (iAxis == Z_AXIS)
{
currentRot.z = fAngle*DEG_TO_RAD;
desiredRot = llEuler2Rot(currentRot);
}


if(iSide == X_POS)
{
rotOriginBefore = (llRot2Fwd(llGetLocalRot()) * size.x / 2.0);
}
else if (iSide == Y_POS)
{
rotOriginBefore = (llRot2Left(llGetLocalRot()) * size.y / 2.0);
}
else if (iSide == Z_POS)
{
rotOriginBefore = (llRot2Up(llGetLocalRot()) * size.z / 2.0);
}
else if (iSide == X_NEG)
{
rotOriginBefore = (llRot2Fwd(llGetLocalRot()) * (size.x / -2));
}
else if (iSide == Y_NEG)
{
rotOriginBefore = (llRot2Left(llGetLocalRot()) * (size.y / -2));
}
else if (iSide == Z_NEG)
{
rotOriginBefore = (llRot2Up(llGetLocalRot()) * (size.z / -2));
}

//--part two, more calculations
rotation newLocalRot = desiredRot * llGetLocalRot();
vector rotOriginAfter;

//--change from defaults, if needed
if(iSide == X_POS)
{
rotOriginAfter = (llRot2Fwd(newLocalRot) * size.x / 2.0);
}
else if (iSide == Y_POS)
{
rotOriginAfter = (llRot2Left(newLocalRot) * size.y / 2.0);
}
else if (iSide == Z_POS)
{
rotOriginAfter = (llRot2Up(newLocalRot) * size.z / 2.0);
}
else if (iSide == X_NEG)
{
rotOriginAfter = (llRot2Fwd(newLocalRot) * (size.x / -2));
}
else if (iSide == Y_NEG)
{
rotOriginAfter = (llRot2Left(newLocalRot) * (size.y / -2));
}
else if (iSide == Z_NEG)
{
rotOriginAfter = (llRot2Up(newLocalRot) * (size.z / -2));
}


//--part 3, apply the rotation
llSetPrimitiveParams([PRIM_POSITION, llGetLocalPos() + rotOriginBefore - rotOriginAfter, PRIM_ROTATION, newLocalRot]);

}



default
{
touch_start(integer num)
{
//--this is just a test to see if it works. this loops it around in a complete circle.
integer n;

for (n=0; n<12; ++n)
{
RotFromEdge(30.0, Z_NEG, X_AXIS);
}

}
}
Bloodsong Termagant
Manic Artist
Join date: 22 Jan 2007
Posts: 615
It Works!!!!!!!!!!!!!
04-09-2007 16:38
okay, after SCOURING the forums here for anything to do with rotations, i found this Very Important Bit of Information:
/54/c1/94705/1.html

in short, llsetlocalrot and llsetprimparameters is bugged. now why didn't somebody just SAY so? come to think of it, why doesnt the WIKI say so? this seems a crucial workaround, here. nobody knows it???



okay, two functions here, which is probably overkill if all you want to do is rotate a flexiprim on its stable edge.

RotFromEdge, which works for single, root, or child prims but NOT on attachments (actually, a root on an attachment should work)

AttachedRotFromEdge, which works for child prims in an attachment, but you must pass it the root's local rotation.

enjoy!


CODE

//--ged larsson's edge rotation script, expanded to a function
//--to rotate on any edge/axis combination
//--fixed for child/attached prims with info from lex neva
//--compiled by bloodsong termagant

//--side constants. pos is towards arrow point, neg is towards arrow butt
integer X_POS = 1;
integer X_NEG = 2;
integer Y_POS = 3;
integer Y_NEG = 4;
integer Z_POS = 5;
integer Z_NEG = 6;

//--axis constants
integer X_AXIS = 1;
integer Y_AXIS = 2;
integer Z_AXIS = 3;

//--RotFromEdge: (angle, edge, axis)
//-- input your degrees in normal everyday degrees
//-- input what edge you want the axis on
//-- and which axis you want to rotate about
RotFromEdge(float fAngle, integer iSide, integer iAxis)
{
//--part one initial setup
vector size = llGetScale(); //--gets length of sides to find edges.
//--NOTE: does not work for cut or twisted prims
vector currentRot = <0.0,0.0,0.0>; //do not use the local rot! start at zero to add to current rotation (multiply, do weird quarternion math with, whatever)

rotation desiredRot; //--we will build this from our single angle
vector rotOriginBefore; //--starting origin position rotation

//--adjust for different axes and edges
//--insert our angle into the desired rotation
if(iAxis == X_AXIS)
{
currentRot.x = fAngle*DEG_TO_RAD;
desiredRot = llEuler2Rot(currentRot);
}
else if (iAxis == Y_AXIS)
{
currentRot.y = fAngle*DEG_TO_RAD;
desiredRot = llEuler2Rot(currentRot);
}
else if (iAxis == Z_AXIS)
{
currentRot.z = fAngle*DEG_TO_RAD;
desiredRot = llEuler2Rot(currentRot);
}


//--this gets the rotation times half (or negative half) side of the thing.
//--this is ged's part, i have no idea what it really means :X
if(iSide == X_POS)
{
rotOriginBefore = (llRot2Fwd(llGetLocalRot()) * size.x / 2.0);
}
else if (iSide == Y_POS)
{
rotOriginBefore = (llRot2Left(llGetLocalRot()) * size.y / 2.0);
}
else if (iSide == Z_POS)
{
rotOriginBefore = (llRot2Up(llGetLocalRot()) * size.z / 2.0);
}
else if (iSide == X_NEG)
{
rotOriginBefore = (llRot2Fwd(llGetLocalRot()) * (size.x / -2));
}
else if (iSide == Y_NEG)
{
rotOriginBefore = (llRot2Left(llGetLocalRot()) * (size.y / -2));
}
else if (iSide == Z_NEG)
{
rotOriginBefore = ( (size.z / -2) * llRot2Up(llGetLocalRot()));
}

//--part two, more calculations
//--our new rotation will be our desired change mixed with the current rotation
rotation newLocalRot = desiredRot * llGetLocalRot(); // llGetRot(); //--not llGetLocalRot() *
vector rotOriginAfter; //--as it rotates, the origin will change to something new

//--change for different edges
//--same as before, but with our new rotation
if(iSide == X_POS)
{
rotOriginAfter = (llRot2Fwd(newLocalRot) * size.x / 2.0);
}
else if (iSide == Y_POS)
{
rotOriginAfter = (llRot2Left(newLocalRot) * size.y / 2.0);
}
else if (iSide == Z_POS)
{
rotOriginAfter = (llRot2Up(newLocalRot) * size.z / 2.0);
}
else if (iSide == X_NEG)
{
rotOriginAfter = (llRot2Fwd(newLocalRot) * (size.x / -2));
}
else if (iSide == Y_NEG)
{
rotOriginAfter = (llRot2Left(newLocalRot) * (size.y / -2));
}
else if (iSide == Z_NEG)
{
rotOriginAfter = ( (size.z / -2) * llRot2Up(newLocalRot));
}


//--part 3, apply the rotation
//--but FIRST... find out if we are attached (in which case, this wont work), or a child, in which case, we need to divide by the root rot

if(llGetAttached() != 0)
{//--need a new function for this, with the roots rotation passed to it
llOwnerSay("Error: Edge Rotate does not work on attachments.");
return;
}

if(llGetLinkNumber() > 1)
{//--if not lone (0) or root (1), use this formula
rotation R = llGetRootRotation();
llSetPrimitiveParams([PRIM_POSITION, llGetLocalPos() + rotOriginBefore - rotOriginAfter, PRIM_ROTATION, newLocalRot/R]);
return;
}
//--else it'll work fine. use normal.
llSetPrimitiveParams([PRIM_POSITION, llGetLocalPos() + rotOriginBefore - rotOriginAfter, PRIM_ROTATION, newLocalRot]);

}



default
{
touch_start(integer num)
{
integer n;



for (n=0; n<6; ++n)
{
RotFromEdge(45, Z_NEG, X_AXIS);
llSleep(1.0);
RotFromEdge(-45, Z_NEG, X_AXIS);
llSleep(1.0);
}


}
}

Frank Northmead
Registered User
Join date: 24 Oct 2006
Posts: 13
workaorund for attached rotation?
05-05-2007 17:53
I have tried this sript and it works fine except when attached. I have added passing in the local rot of the root (I am rotating a child) and tried that but can not get it to work.

I am making a locket on a necklace that opens - all is fine when not attached.

When attached I get weird rotations:

Here is my change in the attached rotation test:

if(llGetAttached() != 0)
{//--need a new function for this, with the roots rotation passed to it
rotation R = llGetRootRotation();
llSetPrimitiveParams([PRIM_POSITION, (llGetLocalPos() + rotOriginBefore - rotOriginAfter)/root_rot, PRIM_ROTATION, newLocalRot/R]);
return;
}

Could someone post the wrokaround for attached rotation of a child prim?

TIA,

Frank
Bloodsong Termagant
Manic Artist
Join date: 22 Jan 2007
Posts: 615
05-07-2007 07:46
heyas frank!

okay, the problem is that on an attachment, llGetRotRotation gets the AVATAR's rotation, not the root prim, which is what we need.

what i usually do for attachment children is on rez, have the root prim link message its rotation to the children. (change the rotation to a string and pass it via the string section of the message.)

then in the child i want to rotate, in the link message event, i decode the rotation string and set it to my RR (or your R in this case).

then just use that variable when you want to rotate the child.


ps: i have no idea what would happen if the user changes the rotation of the attachment while wearing it. probably blows it up again. ::sigh::
Anthony Hocken
Registered User
Join date: 16 Apr 2006
Posts: 121
05-10-2007 16:09
From: Bloodsong Termagant

ps: i have no idea what would happen if the user changes the rotation of the attachment while wearing it. probably blows it up again. ::sigh::


In that scenario you might be able to catch the rotation with the moving_end() event handler and update the variable which stores the root rotation via linked message.
Bloodsong Termagant
Manic Artist
Join date: 22 Jan 2007
Posts: 615
05-11-2007 07:14
doesn't moving_end (and start) also happen when the avatar just walks around, though? does it happen if an attachment is on your arm and the avatar waves the arm?

i know some attachments 'sense' motion/speed of an avatar. or themselves ON an avatar.

wouldn't it be like changed and.... something? :/ i haven't run into it as a problem yet, that's why i dont know ;D
Anthony Hocken
Registered User
Join date: 16 Apr 2006
Posts: 121
05-11-2007 08:22
You can not use the changed() event for this as far as I know.
DrFran Babcock
Registered User
Join date: 30 Apr 2006
Posts: 69
Please help a poor, math-challenged avie
05-11-2007 10:27
So, does this thing work or not?
And if it works, which of the multitude of snippets of scripts works?
/me shakes her head in self-pity
Lee Ponzu
What Would Steve Do?
Join date: 28 Jun 2006
Posts: 1,770
05-11-2007 12:26
From: Bloodsong Termagant
in short, llsetlocalrot and llsetprimparameters is bugged. now why didn't somebody just SAY so? come to think of it, why doesnt the WIKI say so? this seems a crucial workaround, here. nobody knows it???



Good question...did you modify the WIKI to add this important info? You can, you know.
Bloodsong Termagant
Manic Artist
Join date: 22 Jan 2007
Posts: 615
05-12-2007 06:54
the only wiki i use is rpg stats, and rpgstats says not to make edits to the wiki, because it's going to re-download from somewhere else.

so, no.


ive seen "if(changed & change_somekindorother)" but only in passing. as you can tell, im not exactly sure how/where this goes. and i still haven't tested any of this. i know, i get distracted by -- ooh, lookit that neat avatar!


dr fran, the LAST and LATEST script is the one that works, of course. ;) gotta get the latest version.
_____________________
Why Johnny Can't Rotate:
http://forums.secondlife.com/showthread.php?t=94705
Ratus Waydelich
Registered User
Join date: 7 Mar 2007
Posts: 14
09-14-2007 00:47
Hi.
I just opened a thred to discuss methods how to optain the local rotation of the root object:
/54/07/210449/1.html#post1676079