Welcome to the Second Life Forums Archive

These forums are CLOSED. Please visit the new forums HERE

detecting rotation

Icey Fluffball
Registered User
Join date: 18 Oct 2005
Posts: 5
11-30-2005 19:35
i am trying to make a script to allow me to detect the rotation of an object then do other things if it is rotated in a certain direction (every 45*), if i can get the basic parts going i can finish the rest on my own. currently i have the rest of the script in full working order but i am having a problem with the following code:

myfunc() {
llSay(0, (string)rotate.z);
erotate = llRot2Euler(rotate);
llSay(0, (string)erotate.z);
if(erotate.z == PI)
{
//other code
}
else if (erotate.z == 0)
{
//other code
}
else
{
llSay(0, "error no valid rotation detected");
}
}

i used the llSay to help me determin if the actual number of the rotation is what i had it compairing to, currently i have an object whos z rotation si 180* but when i run this code it does the final else statment. now i am a begining scripter (have C++ experience) but am i doing something wrong? can anyone help me?

thanks in advanced!

Icey Fluffball
Kala Bijoux
Material Squirrel
Join date: 16 Nov 2004
Posts: 112
11-30-2005 20:34
It's usually a bad idea to compare floats directly, because erotate.z might be 3.141592, and if the LSL value for PI is 3.141593, they won't be equal. So things like

CODE


float a = 1.0;
float b = 3.0;

float c = a / b; // Will be 0.333333
float d = c * b; // Will most probably be 0.999999

if (a == d)
...


... will fail. In this example d = a / b * b, which in normal math is the same as a, but not when you're dealing with floating point math on a computer.

The solution? Instead of checking for equality, check for "close enough". This is true for any situation where you've arrived at the same calculation using two different 'routes', and you always need this when doing vector math, because the multiplication/division never leaves you with the exact same number. Also, since you don't know which number will be greater, you need to use the absolute value of the difference (to get rid of any negative sign).

CODE

float a = 1.0;
float b = 3.0;

float c = a / b; // Will be 0.333333
float d = c * b; // Will most probably be 0.999999

float diff = a - d; // Will be 0.000001, but in a different situation, could have been -0.000001
float posDiff = llFabs(diff); // This will be 0.000001, no matter what

float margin = 0.001; // Your error limit, so if the difference is less than this, you'll consider the two floats to be equal

if (posDiff < margin)


Or in general, when working with floats, you replace:

CODE

if (a == b)


With:

CODE

if (llFabs(a - b) < myErrorMargin)
Icey Fluffball
Registered User
Join date: 18 Oct 2005
Posts: 5
erf
12-02-2005 09:07
well that does make sense and help a little, but i got it partly working, the object is turned down by 90* then all the other rotations will be around the z axis. tho yours would work for just testing one direction, i need N, S, E, W, NE, NW, SE, SW. i would just do it in one direction but that wouldnt do anythign for what i need. if i knew how (if it were possible) to move an object 1 meter away from another when touched for 2 mins, and allow that object to be in any direction that would be eaiser. but alas their is no llMovePrimAway type of function (that i have seen).

this is my script so far, if anyone can modify it a bit to make it work better that would be appreciated:

erotate = llRot2Euler(rotate);
llSay(0, (string)erotate.z+ " euler rotation z";);
a =(llRound(RAD_TO_DEG * erotate.z));
llSay(0, (string)a+ " direction of object z";);
b =(llRound(RAD_TO_DEG * erotate.x));
llSay(0, (string)b+ " direction of object x";);
c =(llRound(RAD_TO_DEG * erotate.y));
llSay(0, (string)c+ " direction of object y";);
if (((a == 90) || (a == -270)) && (( c == 0) || (c == 360)) && (( b == 270) || (b == -90)))// 360
{
//other
}

else if (((a == -270) || (a == 90) )&& ((c == 45) || (c == -315))) //45*
{
//other
}

else if (((a == 0) || (a == 3600)) &&;( ( c == 90) || (c == -270)) && (( b == 0) || (b == 360))) //90
{
//other
}

else if (((a == -90) || (a == 270)) && ((c == 45) || (c == -315)))//135*
{
//other
}

else if(((a == 270) || (a == -90) )&& ((c == 360) || (c == 0)) && ((b == 90) || (b == -270))) //180
{
npos.y = opos.y + size.z / 2;
llSetPrimitiveParams([PRIM_POSITION, npos]);
}

else if (((a == -90) || (a == 270) )&& ((c == -45) || (c == 315)))//225*
{
//other
}

else if ((llAbs(a) == 180) && (( c == -90) || (c == 270)) && (( b == 0) || (b == 360))) //270
{
//other
}

else if (((a == -270) || (a == 90) )&& ((c == -45) || (c == 315))) //315*
{
//other
}

else
{
llSay(0, "error no valid rotation";);
}
}
Rickard Roentgen
Renaissance Punk
Join date: 4 Apr 2004
Posts: 1,869
12-02-2005 10:10
I'm not entirely sure what you're trying to do? a full description of your project would make it easier to propose solutions.
_____________________
Eloise Pasteur
Curious Individual
Join date: 14 Jul 2004
Posts: 1,952
12-02-2005 12:12
all those == look for precise equality. If you're only moving in 45ยบ rotations you can afford a 'lazy' test - the nearest degree.

So if you go through and wherever it says x==90 replace with llFabs(x-90)<1, etc. you should get what you're looking for. Similarly for x==-270 replace with llFabs(x+270)<1.

I'm sorry I can't be bothered to go all the way through replacing the relevant a, b, c and all the numbers for you - but hopefully that gives the idea?

The problem you're facing is the floating point one. Taking a rot and converting it to an euler will give some errors in the last place(s), converting from radians to degrees exacerbates that, so the chances of you getting exactly pi/2, then converting that to 90.0000000 (which is what 90 will default to evaluating against for a float) is essentially 0.