Jump to content

Can I Combine Offset Rotation and Regular Rotation?


BrownBoxStudio
 Share

You are about to reply to a thread that has been inactive for 3155 days.

Please take a moment to consider if this thread is worth bumping.

Recommended Posts

And what I've learned from this is that the LSL wiki is excellent at showing you how to use the built-in functions, but the examples it gives aren't always the best solutions to a problem.

This problem was decomposable into

1) Get an Object which can seat several avatars on it. Fairly straightforward.

2) Spin it on it's own Z axis - straightforward using llTargetOmega

3) rotate it in a circle around a centre point. Here, the wiki provides an example using several vectors, rotations, and transformation/translations.

 

The wiki solution for 3) is far too complicated. The simple solution is to use the trignonemtric functions Sine and Cosine. So for a centre point X,Y, the calculation for the position of an object rotating around it at radius R becomes as simple as

myX = X + R * Cos(theta) and myY = Y + R *Sin(theta) where theta, in radians, varies between 0 and Two PI

 

In fact, for speed, the best way to calculate theta is to have a global float set to PI / 180, which is therefore 1 degree expressed in radians, and an integer counter which increments from 0 to 360, then returns to 0. the counter value times the float gives theta in radians, and the amount by which the counter variable increments can be 1, 5, 10, 30, and so on, depending on how fine a circle you wish.

So to do this with four seats requires all seats to have the function in them that, given Centre X and centre Y, Radius R and theta, calculates and sets the object position, then make one of them the master, and have it chat on a channel the value of theta it has just used, the others the other seats listen,  add a preset number (90, 180, 270) to that angle, trim it to be within 0 and 360, and then calculate and set their own positions.

So my lookup table method here was also an over-complication. Just goes to show, we all fall in love with working out how many angles can dance on the head of a pin sometimes.

  • Like 2
Link to comment
Share on other sites

I was tongue-in-cheek about the dented hat, I'll post full scripts when I can sense the OP will be better off tweaking a simple working example rather than adding snippets into a script. When it comes to reading other people's scripts ghowever, I am TL;DR personified.

 I've ripped these scripts out of the benches by removing the chunks which implement the multi-sit, becuase I think the major problem we all experienced earlier on was trying to contemnplate too many issues at once.

Here's the master seat script, ripped from the main bench seat

// Master script for objects rotating around a fixed point on the Z axis// there will be other scripts within the object to handle multip-sits, those scripts should not try// to affect pos or rot of the object at allinteger benchChan;       // define as requiredvector myPos;rotation myRot;integer spinning = 0;    // set to 1 if llTargetOmega is in force, 0 otherwisevector centre = <120.0, 176.0, 28.848>;     // location about which to rotatefloat radius = 3.0;                         // distance to keep from centrefloat angle = 0.0;                          // start from 0 radians and increase to TWO_PI radiansfloat degree;                               // calculate as 1 degree in radiansrotation deg1;                              // calculate as 1 degree Z rotationrotation turnRot;                           // keeps track of actual rotation and is applied if spinning == 0integer count;                              // varies from 0 to 360newPos()    // calculate a new X and Y based omn angle, X = centre + R*Cos, Y = centre + RSin{    ++count;               // if rotating by more than 1 degree at a time, use count += amount;    if( count >= 360)     {        count -= 360;    }    angle = degree * (float) count;    llSay(benchChan, llList2CSV(["angle", count]) );  // tell the slave seats where we are    float newX = centre.x + radius*llCos(angle);    float newY = centre.y + radius*llSin(angle);        turnRot *= deg1;                                  //  if not spinning, adjust our rotation to this    list params = [PRIM_POSITION, <newX, newY, myPos.z>];    if( !spinning) params += [PRIM_ROTATION, turnRot];        llSetLinkPrimitiveParamsFast(LINK_THIS, params);}default{    state_entry()    {        llSetPos(<centre.x + radius, centre.y, 25.64094>);       // for angle 0, cos is 1, sin is 0        llSetRot(<0.00000, 0.00000, 0.00000, 1.00000>);        myPos = llGetPos();        myRot = llGetRot();        turnRot = myRot;        degree = PI / 180;        deg1 = llEuler2Rot(<0.0, 0.0, degree>);        count = 0;        llSay(benchChan, llList2CSV(["angle", count]) );  // tell the slave seats where we are        llTargetOmega(<0.0, 0.0, 0.0>, 0.0, 0.0);        spinning = 0;        llSetTimerEvent(0.2);    // off we go    }    touch_start(integer touches)    {        if( !spinning)        {            llTargetOmega(<0.0, 0.0, 1.0>, 1.0, 1.0);            spinning = 1;        }        else        {            llTargetOmega(<0.0, 0.0, 0.0>, 0.0, 0.0);            spinning = 0;            llSetRot(turnRot);     // and turn ourselves to face where we actually would be facing        }     }    timer()    {        newPos();    }}

 

 

And here's one of the two slave seats, the other is identical but uses 240 as it's offset angle

 

// script to go in a slave seat, in this instance one of three to be spaced 120 degrees around, a third will be at 240 degreesinteger benchChan;       // set as per main scriptinteger bhandle;vector myPos;rotation myRot;integer spinning = 0;vector centre = <120.0, 176.0, 28.848>;     // location about which to rotatefloat radius = 3.0;                         // distance to keep from centrefloat angle = 0.0;                          // start from 0 radians and increase to TWOPI radiansfloat degree;                               // calculate as 1 degrerotation deg1;                              // calculate as 1 degree Z rotationrotation turnRot;integer count;integer myAngle = 120;                      // set as appropriatenewPos()    // calculate a new X and Y based on angle, X = centre + R*Cos, Y = centre + R*Sin{    if( count >= 360)     {        count -= 360;     }    angle = degree * (float) count;    float newX = centre.x + radius*llCos(angle);    float newY = centre.y + radius*llSin(angle);        turnRot *= deg1;            list params = [PRIM_POSITION, <newX, newY, myPos.z>];        if( !spinning) params += [PRIM_ROTATION, turnRot];        llSetLinkPrimitiveParamsFast(LINK_THIS, params);}default{    state_entry()    {        degree = PI / 180;        count = myAngle;        deg1 = llEuler2Rot(<0.0, 0.0, degree>);        llSetPos(<centre.x + radius*llCos(degree*count), centre.y + radius*llSin(degree*count), 25.64094>);        llSetRot(llEuler2Rot(<0.0, 0.0, degree * (float) myAngle>));        myPos = llGetPos();        myRot = llGetRot();        turnRot = myRot;        llTargetOmega(<0.0, 0.0, 0.0>, 0.0, 0.0);        spinning = 0;        bhandle = llListen(benchChan, "", "", "");    }    touch_start(integer touches)    {        if( !spinning)        {            llTargetOmega(<0.0, 0.0, 1.0>, 1.0, 1.0);            spinning = 1;        }        else        {            llTargetOmega(<0.0, 0.0, 0.0>, 0.0, 0.0);            spinning = 0;            llSetRot(turnRot);        }    }    listen(integer ch, string name, key id, string msg)    {        list temp = llCSV2List(msg);        if( llList2String(temp, 0) == "angle")        {            count = myAngle + (integer) llList2String(temp, 1);            newPos();        }    }}

Usual warning about my propensity to typo applies

 

  • Like 1
Link to comment
Share on other sites

Thanks.   That and your previous post make it so much clearer.   I've long thought it should be possible to do something like this, but whenever I've tried my lack of attention all those years ago in trig classes has come back to bite me.    I'll certainly be playing round with your method in the near future.

Link to comment
Share on other sites

And yet you understand global vs local rotations, where I go rushing to the wiki every time :)

Here's the lookup table method I was first proposing, and a fascinating insight. The savings on running time are all of 0.002 milliseconds for pre-calculating the vectors (0.025 vs 0.027), and a doubling in script memory, for no visible alteration in motion.

It shows that I was initially proposing a too-heavy solution. Mind you, in the steam locomotive I have running on the island, the six wheels, two crank axles and two coupling rods that are moved around all the time really do show a saving over run-time calculations.

 

// Master script for objects rotating around a fixed point on the Z axis// there will be other scripts within the object to handle multip-sits, those scripts should not try// to affect pos or rot of the object at allinteger benchChan;       // define as requiredvector myPos;rotation myRot;integer spinning = 0;    // set to 1 if llTargetOmega is in force, 0 otherwiselist posAndRot = [];    // strided list of vector and rotation for each angle from 0 to 359 degreesrotation turnRot;                           // keeps track of actual rotation and is applied if spinning == 0integer count;                              // varies from 0 to 360setup(){    vector centre = <120.0, 184.0, 25.743>;     // location about which to rotate    float radius = 3.0;                         // distance to keep from centre    float angle = 0.0;                          // start from 0 radians and increase to TWO_PI radians    float degree = PI / 180;;                               // calculate as 1 degree in radians    rotation deg1 = llEuler2Rot(<0.0, 0.0, degree>);        // calculate as 1 degree Z rotation    turnRot = ZERO_ROTATION;    integer ii;        for( ii = 0; ii < 360; ++ii)    {         posAndRot += <centre.x + radius * llCos(angle), centre.y + radius * llSin(angle), centre.z>;         posAndRot += turnRot;         angle += degree;         turnRot *= deg1;    } }newPos()    // calculate a new X and Y based omn angle, X = centre + R*Cos, Y = centre + RSin{    ++count;               // if rotating by more than 1 degree at a time, use count += amount;    if( count >= 360)     {        count -= 360;    }    llSay(benchChan, llList2CSV(["angle", count]) );  // tell the slave seats where we are    vector newPos = llList2Vector(posAndRot, (count*2));    turnRot = llList2Rot(posAndRot, (count*2) + 1);    list params = [PRIM_POSITION, newPos];    if( !spinning) params += [PRIM_ROTATION, turnRot];        llSetLinkPrimitiveParamsFast(LINK_THIS, params);}default{    state_entry()    {        setup();        count = 0;        llSetPos(llList2Vector(posAndRot, count*2));        llSetRot(llList2Rot(posAndRot, count*2 + 1));         turnRot = llGetRot();        llSay(benchChan, llList2CSV(["angle", count]) );  // tell the slave seats where we are        llTargetOmega(<0.0, 0.0, 0.0>, 0.0, 0.0);        spinning = 0;        llSetTimerEvent(0.2);    // off we go    }    touch_start(integer touches)    {        if( !spinning)        {            llTargetOmega(<0.0, 0.0, 1.0>, 1.0, 1.0);            spinning = 1;        }        else        {            llTargetOmega(<0.0, 0.0, 0.0>, 0.0, 0.0);            spinning = 0;            llSetRot(turnRot);     // and turn ourselves to face where we actually would be facing        }            }    timer()    {        newPos();    }}

 

Link to comment
Share on other sites

I want to say thanks to everyone who has helped me. I got the ride to work thanks to you guys, was way over my head but I now understand. Profaitchikenz and his equations for getting the center axis really helped. I changed things up a bit compared to his examples but these are my results. Everything runs off of the center beam, getting location and z.angle every tick. This way you can move the ride while it is spinning and the seating will snap to it's relative location, within 100 meters. The script in the seating grabs it's own location based off of it's name.

Gif is too large to show here: https://i.gyazo.com/aa0abab4d51f1b939b91f7712a644fb1.gif

 

I'd really show my scripts but I kind of want to keep my edits a secret for now since the project isn't even released yet. If someone really wants to see they can IM me inworld and I would be glad to show.  Although a solution was already given and it works great. Thanks again everyone!

Link to comment
Share on other sites

You are about to reply to a thread that has been inactive for 3155 days.

Please take a moment to consider if this thread is worth bumping.

Please sign in to comment

You will be able to leave a comment after signing in



Sign In Now
 Share

×
×
  • Create New...