Jump to content

problems setting two links to absolute degree position


VirtualKitten
 Share

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

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

Recommended Posts

I was trying out a bunch of things and after I got something working, I was able to reduce it down to this: (@Rolig Loon, look!)

rotate(vector axis, float angle)
{
    vector V = axis * DEG_TO_RAD;
    V.z += angle * DEG_TO_RAD;

    llSetText((string)["V ", V, "\n"], <1,1,1>, 1);

    llSetLinkPrimitiveParamsFast(0, [PRIM_ROT_LOCAL, llEuler2Rot(V)]);
}

Calling this function multiple times with the same input will keep the object static.

Seems to work with every angle:

default
{
    state_entry()
    {
        while (1)
        {
            rotate(<-39.442190, -34.623080, -37.278190>, llGetTime()*RAD_TO_DEG);
            llSleep(0.066);
        }
    }
}

Output: https://puu.sh/G3F8q/8a8252cab3.mp4

So with a couple minor changes (like changing the function to return a rotation instead), you can make it rotate two linked prims without affecting the root (or other links) :

rotation rotate(vector axis, float angle)
{
    vector V = axis * DEG_TO_RAD;
    V.z += angle * DEG_TO_RAD;
    return llEuler2Rot(V);
}

default
{
    state_entry()
    {
        while (1)
        {
            rotation r = rotate(<-39.442190, -34.623080, -37.278190>, llGetTime()*RAD_TO_DEG);
            vector box1pos = ZERO_VECTOR;
            vector box2pos = <0.25, 0, 0> * r;
            rotation box1rot = r;
            rotation box2rot = r;
            llSetLinkPrimitiveParamsFast(1, [
                PRIM_LINK_TARGET, 2,
                    PRIM_POS_LOCAL, box1pos, PRIM_ROT_LOCAL, box1rot,
                PRIM_LINK_TARGET, 3,
                    PRIM_POS_LOCAL, box2pos, PRIM_ROT_LOCAL, box2rot
            ]);
            llSleep(0.066);
        }
    }
}

Output: https://puu.sh/G3Fm9/98e6ecc449.mp4 (The grey pyramid and two cubes are one linkset.)

You could get rid of the DEG_TO_RAD calculations if you made sure your input was already in radians. And honestly, the way I figured this out was just from trying to create the "spinning" effect by hand through the edit window.

Edit:

13 hours ago, Mollymews said:

I also really like how you went about it. You ignored all of the conventional wisdom and went with observation, then coded up what you observed.

To be fair, I tried to do all kinds of rotation-based things first. Conventional wisdom didn't work so I went back to basics. In hindsight the solution is extremely obvious. I inadvertently even explained how my solution works, earlier.

23 hours ago, Wulfie Reanimator said:
On 7/4/2020 at 3:02 PM, VirtualKitten said:

rotation rotClick_inRootFrame = llAxisAngle2Rot(axisAxis, rotClickAngle *DEG_TO_RAD);
rotation rotClick_inRootFrame = llEuler2Rot(<0, 0, rotClickAngle> *DEG_TO_RAD);

The difference in those two bits of code is that one uses a specific axis to rotate around (axisAxis), while the second always rotates around the world Z axis (axisAxis = <0,0,1>).

  • When you imagine a vector representing a rotation, the vector's "local space" is such that the Z axis points straight up. This means when you change the Z angle, you are causing the vector to "roll" or spin around itself rather than tilting into any direction.
  • Think of when you have an object at ZERO_ROTATION. Changing the Z angle will cause the object to spin horizontally. The same applies when you turn the object upside down at a weird angle. If you change the Z angle of the rotation, the object will still spin "horizontally" in its own "local space," not region coordinates.
  • Also, llAxisAngle2Rot doesn't do what you might assume. If you give it an angle of 0, you will always get ZERO_ROTATION, because llAxisAngle2Rot returns the rotation required to reach that destination. 0 change = ZERO_ROTATION.
Edited by Wulfie Reanimator
  • Like 1
Link to comment
Share on other sites

1 hour ago, Wulfie Reanimator said:

I was trying out a bunch of things and after I got something working

Output: https://puu.sh/G3Fm9/98e6ecc449.mp4 (The grey pyramid and two cubes are one linkset.)

And honestly, the way I figured that out was just from trying to create the "spinning" effect by hand through the edit window.

this is really impressive Wulfie. I would never have thought to do it like this

I also really like how you went about it. You ignored all of the conventional wisdom and went with observation, then coded up what you observed. I like

  • Thanks 1
Link to comment
Share on other sites

Thanks for your input Wulfie , it is impressive Molly  and  it looks very neat and short ,however I note you are not showing us where <-39.442190, -34.623080, -37.278190> comes from to make the code portable.  I presume this is a PRIM_POS_ LOCAL request on prim 1 or your axis cone. What transformation have you done to it please which is hidden in your example ?

 

Link to comment
Share on other sites

1 hour ago, VirtualKitten said:

Thanks for your input Wulfie , it is impressive Molly  and  it looks very neat and short ,however I note you are not showing us where <-39.442190, -34.623080, -37.278190> comes from to make the code portable.  I presume this is a PRIM_POS_ LOCAL request on prim 1 or your axis cone. What transformation have you done to it please which is hidden in your example ?

 

<-39.442190, -34.623080, -37.278190> is just an arbitrary axis I used as an example / for testing. It's the orientation of the pink cone (which isn't linked to the script).
Basically: llRot2Euler(llGetRot()) * RAD_TO_DEG;

You can use any vector to any direction you want. The code will always make the object spin around the given vector.

For example, I'll write a couple lines of code to create a vector that constantly changes direction: https://puu.sh/G3Q3b/975a29d29d.mp4

default
{
    state_entry()
    {
        vector initial = <1,1,1>;
        while (1)
        {
            rotation axang = llAxisAngle2Rot(initial, llGetTime());
            llSetText((string)[axang], <1,1,1>, 1);

            llSetLinkPrimitiveParamsFast(0, [PRIM_ROT_LOCAL, axang]);
            llSleep(0.066);
        }
    }
}

Then we just add that into our previous "rotating cubes" code:

rotation axang = llAxisAngle2Rot(<1,1,1>, llGetTime());
vector axis = llRot2Euler(axang);

rotation r = rotate(axis*RAD_TO_DEG, llGetTime()*RAD_TO_DEG);

Now we have two cubes that are spinning around an axis that also spins around... https://puu.sh/G3Q5E/896477dbe0.mp4

Edited by Wulfie Reanimator
Link to comment
Share on other sites

Hmm  Wulfie  does not  GetRot() provide a quaternion  PRIM_ROTATION not a PRIM_ROT_LOCAL? so it would be akin to  rotation r = rotate((llRot2Euler( llList2Rot(llGetLinkPrimitiveParams(axis, [PRIM_ROTATION]), 0))) * RAD_TO_DEG, llGetTime()*RAD_TO_DEG); which gives an error on the console  "llSetPrimitiveParams error running rule #2 (PRIM_POS_LOCAL): arg #1 vector expected but quaternion given". Or have i missed something,  as am so pleased yours is working i wanted to try for myself :).

Link to comment
Share on other sites

16 minutes ago, VirtualKitten said:

Hmm  Wulfie  does not  GetRot() provide a quaternion  PRIM_ROTATION not a PRIM_ROT_LOCAL? so it would be akin to  rotation r = rotate((llRot2Euler( llList2Rot(llGetLinkPrimitiveParams(axis, [PRIM_ROTATION]), 0))) * RAD_TO_DEG, llGetTime()*RAD_TO_DEG); which gives an error on the console  "llSetPrimitiveParams error running rule #2 (PRIM_POS_LOCAL): arg #1 vector expected but quaternion given". Or have i missed something,  as am so pleased yours is working i wanted to try for myself :).

PRIM_ROTATION / PRIM_ROT_LOCAL are just different coordinate spaces. They both want quaternions, they just have different uses and aren't directly related to llGetRot. Don't think about it too much, I used _ROT_LOCAL because I want the final positions of the two cubes to always be relative to the root.

Besides, your code works for me: https://puu.sh/G3Qdq/aaaa291e26.mp4

rotation r = rotate( llRot2Euler(llList2Rot(llGetLinkPrimitiveParams(4, [PRIM_ROTATION]), 0)) * RAD_TO_DEG, llGetTime()*RAD_TO_DEG );

 

Edited by Wulfie Reanimator
Link to comment
Share on other sites

Sabrina , thanks for popping by in world and a pleasure to meet you  I saw yours working but it stores default values at startup. I intend to rotate this as well i don't think that will work. I tried wulfies  attempt but could not replicate his movement this is the code  I tried this after obtaining box numbers else where with llGetLinkName():

 

integer input = 10;

rotation rotate(vector axis, float angle)
{
    vector V = axis * DEG_TO_RAD;
    V.z += angle * DEG_TO_RAD;
    return llEuler2Rot(V);
}

 

default
{
    state_entry()
    {
        llSetTimerEvent(.05);
    }
     timer()
        {
            rotation r = rotate((llRot2Euler( llList2Rot(llGetLinkPrimitiveParams(axis, [PRIM_ROTATION]), 0))) * RAD_TO_DEG, input*RAD_TO_DEG);
            vector box1pos = ZERO_VECTOR;
            vector box2pos = <0.25, 0, 0>;
            rotation box1rot = r;
            rotation box2rot = r;
            llSetLinkPrimitiveParamsFast(1, [
                PRIM_LINK_TARGET, center_box,
                    PRIM_POS_LOCAL, box1pos, PRIM_ROT_LOCAL, box1rot,
                PRIM_LINK_TARGET, outer_box,
                    PRIM_POS_LOCAL, box2pos*r, PRIM_ROT_LOCAL, box2rot
            ]);
           input+=10;
           if(input>360) input = 10;
        }

   }

Link to comment
Share on other sites

5 hours ago, VirtualKitten said:

I tried wulfies  attempt but could not replicate his movement this is the code  I tried this after obtaining box numbers else where with llGetLinkName():

The main problem is that your input is already in degrees but you still had input*RAD_TO_DEG, which converts radians to degrees. You were essentially scaling up the degrees by a lot, making it spin way too fast. Here's a fixed version of your code:

integer input = 10;

rotation rotate(vector axis, float angle)
{
    vector V = axis * DEG_TO_RAD;
    V.z += angle * DEG_TO_RAD;
    return llEuler2Rot(V);
}

default
{
    state_entry()
    {
        llSetTimerEvent(.05);
    }

    timer()
    {
        // Remember to change these.
        integer center_box = 2;
        integer outer_box = 3;
        integer axis = 4;

        rotation r = rotate(llRot2Euler( llList2Rot(llGetLinkPrimitiveParams(axis, [PRIM_ROTATION]), 0)) * RAD_TO_DEG, input);
        vector box1pos = ZERO_VECTOR;
        vector box2pos = <0.25, 0, 0> * r;
        rotation box1rot = r;
        rotation box2rot = r;
        llSetLinkPrimitiveParamsFast(1, [
            PRIM_LINK_TARGET, center_box,
                PRIM_POS_LOCAL, box1pos, PRIM_ROT_LOCAL, box1rot,
            PRIM_LINK_TARGET, outer_box,
                PRIM_POS_LOCAL, box2pos, PRIM_ROT_LOCAL, box2rot
        ]);
        input += 10;
        if(input > 360) input = 10;
    }
}

I should also point out that all of the LSL functions return rotations expressed in radians. So llRot2Euler(some_rotation) would return a vector where all of the three values are in the range between about -3.14 to 3.14. That's -180 to 180 degrees, so you can see how radians are a much smaller unit. (Specifically, one degree is about 0.0174 radians. Very small!) That's why we have the DEG_TO_RAD and RAD_TO_DEG constants to convert between the two types of units.

So, because it's much more intuitive for humans to think in degrees (because that's what we commonly use), I initially wrote my function to expect degrees, because I assumed you wanted to type in the angle and vector yourself. But if you're going to get the input directly from another object with the rotation functions, You could change things a bit like this:

rotation rotate(vector axis, float angle)
{
    axis.z += angle * DEG_TO_RAD;
    return llEuler2Rot(axis);
}

...

timer()
{
    rotation r = rotate(llRot2Euler( llList2Rot(llGetLinkPrimitiveParams(axis, [PRIM_ROTATION]), 0)), input);

Now the code is simplified even further, since we don't need to convert the values related to the axis at all -- only the angle that's getting added.

Edited by Wulfie Reanimator
Link to comment
Share on other sites

1 hour ago, VirtualKitten said:

Hi Wulfie if you run the changed script you gave me it just rotate one prim i will send it to you in world to see 

Look, I like helping. But the script I've given you is incredibly simple to edit, there's even a comment for the part you need to change.

I'm looking at the object you sent me and two of the links are spinning, just not the ones you want. You only need to change one link number. If you can't pay enough attention to notice/fix that on your own, I lose motivation and interest.

Look at the script for one minute. Think about it.

Edited by Wulfie Reanimator
Link to comment
Share on other sites

Dear  Wolfie I was working yesterday so didn't have much time with it either , I will take another look I am incredibly grateful of your help as in world this knowledge is rare and I am eager to learn . Thank you for your help you was not using box positions in your script for position and I note this now too. I apologize to you as I confess should have payed more attention :)

Link to comment
Share on other sites

There was another typo in the script! Here is the fixed version:

 

integer link_axis; 
integer link_box1; 
integer link_box2;
float rotClickAngle = 15;

rotation rotRoot2Axis;
vector posRoot2Axis;
vector axisAxis;
vector offsetBody_inRootFrame;
vector offsetBeam_inRootFrame;

rotation rotRoot2Body;
vector posRoot2Body;
    
rotation rotRoot2Beam;
vector posRoot2Beam;

integer listener;
integer chan = -55555;

do_rotate(float angle){
    rotation rotClick_inRootFrame = llAxisAngle2Rot(axisAxis, angle *DEG_TO_RAD);
    
    // for body.
    rotation newrotRoot2Body = rotRoot2Body * rotClick_inRootFrame;
    vector newoffsetBody_inRootFrame = offsetBody_inRootFrame* rotClick_inRootFrame;
       //Beam.
    rotation newrotRoot2Beam = rotRoot2Beam * rotClick_inRootFrame;
    vector newoffsetBeam_inRootFrame = offsetBeam_inRootFrame * rotClick_inRootFrame;
    
    llSetLinkPrimitiveParamsFast(1,[
         PRIM_LINK_TARGET,link_box1,PRIM_ROT_LOCAL,newrotRoot2Body,
         PRIM_LINK_TARGET, link_box2,PRIM_ROT_LOCAL, newrotRoot2Beam,PRIM_POS_LOCAL, posRoot2Axis + newoffsetBeam_inRootFrame]);
} 

integer rotating = FALSE;

integer link_by_name(string linkName) {
    integer N=llGetNumberOfPrims();
    integer i;
    for(i=1;i<=N;i++) {
        if (llGetLinkName(i)==linkName) {
            llOwnerSay(linkName + " : " + (string)i);
            return i;
        }
    }
    llOwnerSay(linkName + " not found");
    return -99;
}


reset()
{
    llSetLinkPrimitiveParamsFast(1,[
     PRIM_LINK_TARGET,link_box1,PRIM_ROT_LOCAL,rotRoot2Body,PRIM_POS_LOCAL, posRoot2Body,
     PRIM_LINK_TARGET, link_box2,PRIM_ROT_LOCAL, rotRoot2Beam,PRIM_POS_LOCAL, posRoot2Beam]);

}

default
{
    state_entry()
    {
        
        link_axis = link_by_name("axis");
        link_box1 = link_by_name("box1");
        link_box2 = link_by_name("box2");      
        
        list L = llGetLinkPrimitiveParams(link_axis,[PRIM_ROT_LOCAL, PRIM_POS_LOCAL]);
        rotRoot2Axis = llList2Rot(L,0);
        posRoot2Axis = llList2Vector(L,1);
        axisAxis=<0,0,1>*rotRoot2Axis;

        L = llGetLinkPrimitiveParams(link_box1,[PRIM_ROT_LOCAL, PRIM_POS_LOCAL]);
        rotRoot2Body = llList2Rot(L,0);
        posRoot2Body = llList2Vector(L,1);
    
        L = llGetLinkPrimitiveParams(link_box2,[PRIM_ROT_LOCAL, PRIM_POS_LOCAL]);
        rotRoot2Beam = llList2Rot(L,0);
        posRoot2Beam = llList2Vector(L,1);
        offsetBody_inRootFrame = posRoot2Body - posRoot2Axis;
        offsetBeam_inRootFrame = posRoot2Beam - posRoot2Axis;
        
        listener = llListen(chan, "", NULL_KEY, "") ;
        llTextBox(llGetOwner(), "What angle would you like?", chan) ;
        
    

    }

    listen(integer chan, string name, key id, string text)
    {
        llListenRemove(listener) ;
        float angle = (float)text ;
        llOwnerSay("angle = " + (string)angle) ;
        do_rotate(angle) ;
        llOwnerSay("Done. Touch me for movement.");
    }

    touch_start(integer total_number)
    {
        llOwnerSay("this is link "+ (string)llDetectedLinkNumber(total_number)) ;
        if (!rotating) {
            rotating = TRUE ;     
            reset() ;   
            llSetTimerEvent(1.0) ;
        }
        else {
            rotating = FALSE ;        
            llSetTimerEvent(0.0) ;
            
            reset() ;
        }            
    }
    
    timer() 
    {
        rotClickAngle += 5 ;
        if (rotClickAngle > 359.0) {
            rotClickAngle = 0;
        }
        
        do_rotate(rotClickAngle) ;
    }    
}

 

Link to comment
Share on other sites

You are about to reply to a thread that has been inactive for 1427 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...