# Simplize or shorten my script?

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

## Recommended Posts

I've had a complicated problem to solve with my script for over a week now and I can't come up with a way to calculate the result without spelling it all out in a long script. Can somebody find a way to simpilize this to make it much more efficiant and shorter?

```vector RoundRot;
rotation MyRot=llGetRot();
vector Scale=llGetScale();
RoundRot=<RoundNinty(r.x),RoundNinty(r.y),RoundNinty(r.z)>;
if (RoundRot==<0,0,0> || RoundRot==<180,0,0> || RoundRot==<0,180,0> || RoundRot==<0,0,180>)
{
if (llRound(Scale.x) % 2 == 0) Xoffset=0.5; else Xoffset=0;
if (llRound(Scale.y) % 2 == 0) Yoffset=0.5; else Yoffset=0;
if (llRound(Scale.z) % 2 == 0) Zoffset=0.5; else Zoffset=0;
}
else if (RoundRot==<0,0,90> || RoundRot==<0,0,-90> || RoundRot==<-180,0,-90> || RoundRot==<180,0,90> || RoundRot==<180,0,-90> || RoundRot==<-180,0,90>)
{
if (llRound(Scale.x) % 2 == 0) Yoffset=0.5; else Yoffset=0;
if (llRound(Scale.y) % 2 == 0) Xoffset=0.5; else Xoffset=0;
if (llRound(Scale.z) % 2 == 0) Zoffset=0.5; else Zoffset=0;
}
else if (RoundRot==<90,0,0> || RoundRot==<-90,0,0> || RoundRot==<-90,0,-180> || RoundRot==<90,0,180> || RoundRot==<90,0,-180> || RoundRot==<-90,0,180>)
{
if (llRound(Scale.y) % 2 == 0) Zoffset=0.5; else Zoffset=0;
if (llRound(Scale.z) % 2 == 0) Yoffset=0.5; else Yoffset=0;
if (llRound(Scale.x) % 2 == 0) Xoffset=0.5; else Xoffset=0;
}
else if (RoundRot==<0,90,0> || RoundRot==<0,-90,0> || RoundRot==<0,-90,-180> || RoundRot==<0,90,180> || RoundRot==<0,-90,180> || RoundRot==<0,90,-180>)
{
if (llRound(Scale.z) % 2 == 0) Xoffset=0.5; else Xoffset=0;
if (llRound(Scale.x) % 2 == 0) Zoffset=0.5; else Zoffset=0;
if (llRound(Scale.y) % 2 == 0) Yoffset=0.5; else Yoffset=0;
}
else if (RoundRot==<0,90,90> || RoundRot==<0,-90,-90> || RoundRot==<0,-90,90> || RoundRot==<0,90,-90>)
{
if (llRound(Scale.z) % 2 == 0) Xoffset=0.5; else Xoffset=0;
if (llRound(Scale.x) % 2 == 0) Yoffset=0.5; else Yoffset=0;
if (llRound(Scale.y) % 2 == 0) Zoffset=0.5; else Zoffset=0;
}
else if (RoundRot==<90,0,90> || RoundRot==<-90,0,-90> || RoundRot==<90,0,-90> || RoundRot==<-90,0,90>)
{
if (llRound(Scale.z) % 2 == 0) Yoffset=0.5; else Yoffset=0;
if (llRound(Scale.x) % 2 == 0) Zoffset=0.5; else Zoffset=0;
if (llRound(Scale.y) % 2 == 0) Xoffset=0.5; else Xoffset=0;
}
else if (RoundRot==<0,-90,-180> || RoundRot==<0,90,-180>)
{
if (llRound(Scale.z) % 2 == 0) Xoffset=0.5; else Xoffset=0;
if (llRound(Scale.x) % 2 == 0) Zoffset=0.5; else Zoffset=0;
if (llRound(Scale.y) % 2 == 0) Yoffset=0.5; else Yoffset=0;
}```

This part of my script just basically sets an offset of 0 or 0.5 depending on the rotation of the prim, which is rounded to the nearest 90 degrees. It works PERFECT but I feel like it shouldn't be this complicated!

##### Share on other sites

Personally, I think your script is easier to understand the way it is. In othe languages this is a good case for using the terniary operator, which LSL doesn't have. Here's my suggestion, picking just one of your processes.

`// consider you have a global vector offset if (RoundRot==<0,0,0> || RoundRot==<180,0,0> || RoundRot==<0,180,0> || RoundRot==<0,0,180>)    {       offset = < 0.5 *  (float) (llRound(Scale.x) % 2 == 0),                        0.5 * (float) (llRound(Scale.y) % 2 == 0),                        0,5 * (float) (llRound(Scale.z) % 2 == 0)                     >;    }// the trick here is multiplying 0.5 by a truth value TRUE or FALSE, which are implemented as 1 and 0. // so what you get for each vector component is 0.5 or 0.0 depending on the effective multiplier`

The (float) casts are probably redundant, but I find I need to do things like this so that in a year's time I don't look at the code and have my eyes glaze over,

Standard disclaimer about my propensity to typos applies.

##### Share on other sites

The other thing you can do is exploit the fact that in rotations as quaternions as opposed to vectors, 0 and 180 degrees come out as 0.o and 1.0, therefore the test for X, Y Z being either 0 or 180 degrees , when applied to a rotation, would be

`rotation testMe;if( testMe.s == 0.000000 || testMe.s == 1.000000){    // we are at 0 degrees, or 180 degrees on any of the three axes   // because ZERO_ROTATION is <0.0, 0.0, 0.0, 1.0>   // X 180 degrees is <1.0, 0.0, 0.0, 0.0>   // Y 180 degrees is <0.0, 1.0, 0.0, 0.0>   // Z 180 degrees is <0.0, 0.0, 1.0, 0.0>   // therefore interogate testMe.x, y, z for 0.0 or 1.0 to look for 0 or 180 alignment   doStuff();}`

Again, the problem here is that your code is easier to understand for somebody (like me) who doesn't naturally understand quaternions or SL rotations. I don't know if my two suggestions would actually run faster, or consume less memory.

ETA experimeting inworld shows that as has already been pointed out in another thread, you do need to specify at least 5 digits of precision to make sure that 0.0001 gets excluded from the success test.

##### Share on other sites

another way is can use a lookup table approach. Something like maybe

`    list Vectors =     [        <0.0.0>,     <180,0,0>,  <0,180,0>.    <0.0.180>,        <0,0,90>,    <0,0,-90>,  <-180,0,-90>, <180,0,90>, <180,0,-90>, <-180,0,90>,        <90,0,0>,    <-90,0,0>,  <-90,0,-180>, <90,0,180>, <90,0,-180>, <-90,0,180>,        <0,90,0>,    <0,-90,0>,  <0,-90,-180>, <0,90,180>, <0,-90,180>, <0,90,-180>,        <0,90,90>,   <0,-90,-90>,<0,-90,90>,   <0,90,-90>,        <90,0,90>,   <-90,0,-90>,<90,0,-90>,   <-90,0,90>,        <0,-90,-180>,<0,90,-180>    ];        float x = 0.5 * (llRound(Scale.x) & 1);    float y = 0.5 * (llRound(Scale.y) & 1);    float z = 0.5 * (llRound(Scale.z) & 1);         integer p = llListFindList(Vectors, [RoundRot]);        if (~p)    {        if (p < 4)        {            Xoffset = x; Yoffset = y; Zoffset = z;        }        else if (p < 10)        {            Xoffset = y; Yoffset = x; Zoffset = z;        }        else if (p < 16)        {            Xoffset = x; Yoffset = z; Zoffset = y;        }        else if (p < 22)        {            Xoffset = z; Yoffset = y; Zoffset = x;        }        else if (p < 26)        {            Xoffset = z; Yoffset = x; Zoffset = y;        }        else if (p < 30)        {            Xoffset = y; Yoffset = z; Zoffset = x;        }          else         {            Xoffset = z; Yoffset = y; Zoffset = x;                   }      }    `

+

eta: dunno if you noticed but there is only 6 assignment sets in x.y.z ( 3 * 2 * 1 = 6)

the last (7th) is the same as a earlier one. the 22 set. So can combine them for 1 less "if"

##### Share on other sites

I like this a lot. I was going to suggest something similar, but hideously obscure, in which the degree vectors were flattened into integers with 2 bits each for x, y, and z multiples of 90 degrees, then using those integers as substring indices into a long string of condition flags. But then I got distracted by the fact that there would be 4 x 4 x 4 = 64 such integers, yet here we're testing for just half that many discrete rotations.

I'll bet there's some kind of 3D mirror-symmetry here, such that half the possible rotations are really identical to the other half, but I'm not geometer enough myself to know the details.

##### Share on other sites

i think OP is maybe understanding about mirroring. they only got 32 out of the 64 possible. Altho some of the ones they have got are dups

my main thing with it is that I am not seeing what is the mappings OP is using

some of them dont map others in the sets at all. and some map some in other sets and some map to some in same set. So dunno really

bc dups then I think OP still working out what the mappings is

##### Share on other sites

Do you know how to tell which are dups of which? Or, similarly, how to generate only the unique rotations? Or even how to describe what we're talking about here in such a way that Google finds relevant text?

##### Share on other sites

it depends on how we want to map it pretty much

which is why I am not understanding the OP. bc is no map that I can work out

+
i make some codes so is more easy for me to explain

here is a mirror map. where the mirror is the opposite

<0,0,0> ~ <180,180,180>
<0,0,90> ~ <180,180,270>
<90,90,180> ~ <270,270,0>

and so on

can make a map that mirror by 90deg or 270deg

like 0 ~ 90, 180 ~ 270, 270 ~ 180

or any other constant. like 45deg or 60 or whichever

example:

`const MAP 180vec3 mirror(vec3 v){   return <(v.x + MAP) % 360, (v.y + MAP) % 360, (v.z + MAP) % 360>;   }v = mirror(<0,0,0>)v = <180,180,180>v = mirror(<180,180,180>)v = <0,0,0>`
+
can also make more complex maps. where each x.y.z have its own const

example:

`const MAPX = 45const MAPY = 90const MAPZ = 60vec3 mirror(vec3 v){   return <(v.x + MAPX) % 360, (v.y + MAPY) % 360, (v.z + MAPZ) % 360>;   }`
in this case the mapset is:

<0,0,0>~<45,90,60>~<90,180,120>~ ... ~<225,90,180>~<270,180,240>~<315,270,300>

there are 24 vectors in this map set

+

in the case of a set like

<1,0,0> <0,1,0> <0,0,1>

then can make a swap function. example:

`vec3 mirror(vec3 v){  int n = v.x;  v.x = v.y;  v.y = v.z;  v.z = n;  return v;}`

should note that with swap mapping that <0,0,0> always return <0,0,0> unless make a condition for it in the function

same any other symetricals. like <1,1,1>, <2,2,2> etc

+

basically when know that a vector belongs to a mapset then can manipulate the vectors (indivdually or as a whole set) according to whichever rules we want to apply

also

in the 24 set above we can know that

indice of <0,0,0> is 0
indice of <270,180,240> is 22

so can fetch then a bit faster in a lookup table if maintain a index. or can brute force algo calculate it if have no lookup table

+

can know what mapset a vector belongs to by modulo it with the map. example (using above const map)

`bool inMap(vec3 v, vec3 m){  return !((v.x % m.x) && (v.y % m.y) && (v.z % m.z));}b = inMap(<225,90,180>, <MAPX, MAPY, MAPZ>);b = TRUE;`
+

the main thing is that all the vectors in a set have some constant common to them all

like they not just random drawn, so easier to work with

altho if do need more random-looking then can use a feistel network algo to make 'random' sets that way

+

so after all that

can pretty much make any vector maps we want for own use case

i just dunno what is the map OP is using

+
eta;  swap function

i should of called it swapwrongmirror()

(:

##### Share on other sites

In case it's not obvious, I have zero background here and am just guessing about all this stuff. Regarding  the "symmetry" thing: in the Build Tool some rotations never appear in the Object tab. For example, if you try to orient the object to <90, 90, 90> it will instead show <0, 90, 180>. Similarly <90, 90, 0> shows as <0, 90, 90>, and <0, 180, 90> shows as <180, 0, 270>. I don't think this depends on any symmetry in the object itself, it's just ... I guess a canonical way of expressing equivalent orientations. Or rather that's what I've naively assumed, but I could be misunderstanding on a very basic level here.

##### Share on other sites

I think the issue here is conversion between the Euler representation you see in the build floater and the internal representation as a quaternion. If you feed 90, 90, 90 into a rot variable, then convert that rot variable back into a vector expressed as degrees, you get 0, 90, -180 reported as the values. The rotation itself is <0.70711, 0.0, 0.70711, 0.0>, (whick my early tables suggest is 90 degrees X, 0 degrees y, 90 degrees z),  so I suspect there is some internal process of simplifying the rotations along each of the three axes. Why it should say -180 is a bit of a puzzle to me, it suggests to me that when converting from rot back to Euler and then degrees, there should perhaps be a normalisation stage where negative values are subtracted from 360.

##### Share on other sites

i check the SL viewer build tool and made a table. (i hope I got it right)

```every vec     sl maps to
<  0,  0,  0> <  0,  0,  0>
<  0,  0, 90> <  0,  0, 90>
<  0,  0,180> <  0,  0,180>
<  0,  0,270> <  0,  0,270>
<  0, 90,  0> <  0, 90,  0>
<  0, 90, 90> <  0, 90, 90>
<  0, 90,180> <  0, 90,180>
<  0, 90,270> <  0, 90,270>
<  0,180,  0> <  0,  0,  0>
<  0,180, 90> <  0,  0, 90>
<  0,180,180> <  0,  0,180>
<  0,180,270> <  0,  0,270>
<  0,270,  0> <  0,270,  0>
<  0,270, 90> <  0,270, 90>
<  0,270,180> <  0,270,180>
<  0,270,270> <  0,270,270>
< 90,  0,  0> < 90,  0,  0>
< 90,  0, 90> < 90,  0, 90>
< 90,  0,180> < 90,  0,180>
< 90,  0,270> < 90,  0,270>
< 90, 90,  0> <  0, 90,  0>
< 90, 90, 90> <  0, 90, 90>
< 90, 90,180> <  0, 90,180>
< 90, 90,270> <  0, 90,270>
< 90,180,  0> < 90,  0,  0>
< 90,180, 90> < 90,  0, 90>
< 90,180,180> < 90,  0,180>
< 90,180,270> < 90,  0,270>
< 90,270,  0> <  0,270,  0>
< 90,270, 90> <  0,270, 90>
< 90,270,180> <  0,270,180>
< 90,270,270> <  0,270,270>
<180,  0,  0> <180,  0,  0>
<180,  0, 90> <180,  0, 90>
<180,  0,180> <180,  0,180>
<180,  0,270> <180,  0,270>
<180, 90,  0> <  0, 90,  0>
<180, 90, 90> <  0, 90, 90>
<180, 90,180> <  0, 90,180>
<180, 90,270> <  0, 90,270>
<180,180,  0> <  0,  0,180>
<180,180, 90> <180,  0, 90>
<180,180,180> <180,  0,180>
<180,180,270> <270,  0,180>
<180,270,  0> <  0,270,  0>
<180,270, 90> <  0,270, 90>
<180,270,180> <  0,270,180>
<180,270,270> <  0,270,270>
<270,  0,  0> <270,  0,  0>
<270,  0, 90> <270,  0, 90>
<270,  0,180> <270,  0,180>
<270,  0,270> <270,  0,270>
<270, 90,  0> <  0, 90,  0>
<270, 90, 90> <  0, 90, 90>
<270, 90,180> <  0, 90,180>
<270, 90,270> <  0, 90,270>
<270,180,  0> <270,  0,  0>
<270,180, 90> <180,  0, 90>
<270,180,180> <270,  0,180>
<270,180,270> <270,  0,270>
<270,270,  0> <  0,270,  0>
<270,270, 90> <  0,270, 90>
<270,270,180> <  0,270,180>
<270,270,270> <  0,270,270>```

remove all the vecs that dont map to themself. Leaves 24 vecs

```<  0,  0,  0>
<  0,  0, 90>
<  0,  0,180>
<  0,  0,270>
<  0, 90,  0>
<  0, 90, 90>
<  0, 90,180>
<  0, 90,270>
<  0,270,  0>
<  0,270, 90>
<  0,270,180>
<  0,270,270>
< 90,  0,  0>
< 90,  0, 90>
< 90,  0,180>
< 90,  0,270>
<180,  0,  0>
<180,  0, 90>
<180,  0,180>
<180,  0,270>
<270,  0,  0>
<270,  0, 90>
<270,  0,180>
<270,  0,270>```

am pretty sure 24 is right (is what i meant before about dups)

if the LSL rot2euler functions is the same as in the viewer (?!?) then should only get 1 of these 24 vectors

which size maps to the x.y.z offsets

[x.y.z] = 3*2*1 = 6

[0.90.180.270] = 4

6 * 4 = 24

which is right. A cube has 6 sides that can be orient in 4 ways

+

depending on use case then will be possible to make some functions to make mirrors out of these, now that know what the actual elements of the table are

like Prof mention will have to normalise the euler

OP was doing this already with their RoundNinety. just retaining the neg. like -90 instead of normalise to 270. Altho -90 can work as well for a lookup. Can be bit of a pain tho if is both negs and poss in a mapping function

or can just do the lookup table approach like before

+

probably the most interesting thing is the absence of 180 on the y

##### Share on other sites

OMG thank you all for your answers! I'm not sure that some of my rotations are really missing because some "mirrors" SL automatically fixes, so the script will never detect <180,90,0> for example, SL changes it then detects it as <0,90,180>

I'll have to try the codes provided within the first few replies. Thank you for the continued help!

##### Share on other sites

in that case then the LSL scripting engine vector table map is not quite the same as the viewer vector table map

as a thought. The viewer table is pretty screwy really. I would have thought that it would return equal quantities of each [0.90.180.270] on the x y z. Like 6 of each on the X, on the Y and the Z. So that is a symmetry/balance in the table

but still is ok

can make a script to cycle thru the vectors returned by the script engine. Then normalise the returns to whichever mapping you are using in own table. Which only needs to be 24 vectors in total

+

if was me doing this then I would normalise so that own table is symmetrical. To make it simpler to write functions for

also as you mention

if pass a vector to the LSL rot then the script engine will automagic re-map it to a value that it uses. So dont need worry about that really. Just only have to pass a own map vector value which mirrors the one the script engine uses

##### Share on other sites

irihapeti wrote:

in that case then the LSL scripting engine vector table map is not quite the same as the viewer vector table map

as a thought. The viewer table is pretty screwy really. I would have thought that it would return equal quantities of each [0.90.180.270] on the x y z. Like 6 of each on the X, on the Y and the Z. So that is a symmetry/balance in the table

but still is ok

can make a script to cycle thru the vectors returned by the script engine. Then normalise the returns to whichever mapping you are using in own table. Which only needs to be 24 vectors in total [...]

Right. I stumbled onto this page yesterday, which also makes intuitive the 24 unique orientations with the six sides x 4 ways, as in your earlier post, and finally that part makes sense to me. I'm a little puzzled how the 32 conditions in the OP's post arose to begin with, and whether we can be sure all results are "normalized" into just 24, without doing a lookup ourselves.

I realize my "string index" look-up idea would stick with the 64-character string, even though all but 24 of them are made redundant by the "normalization"; there's no obvious way to reduce the string to 32 by chopping one bit out of a low integer representation of these quantized rotations. Not sure I'll get time to sketch out that code any time soon, anyway.

##### Share on other sites

I've also been intruiged by what the script is actually trying to do. The sort of thing I can see it being useful for is making a dice that is set to physical when tossed, and bounces around a while. When it finally stops bouncing it needs to then be settled onto whichever of the six faces has the closest orientation to the flat plane.

##### Share on other sites

So I made a little script to see how scripts map the rotations, and the result seems unintuitively different from the viewer findings. Not sure what this means, but in case it's useful:

`default{    state_entry()    {        list foundRots;        list foundEulers;        integer numTried;        integer xPiBy2s;        integer yPiBy2s;        integer zPiBy2s;        for (xPiBy2s = 0; xPiBy2s < 4; ++xPiBy2s)            for (yPiBy2s = 0; yPiBy2s < 4; ++yPiBy2s)                for (zPiBy2s = 0; zPiBy2s < 4; ++zPiBy2s)                {                    ++numTried;                    vector euler = <xPiBy2s * PI_BY_TWO, yPiBy2s * PI_BY_TWO, zPiBy2s * PI_BY_TWO>;                    rotation rot = llEuler2Rot(euler);                    if (-1 == llListFindList(foundRots, [rot]))                        foundRots += rot;                    vector foundEulerDeg = llRot2Euler(rot)*RAD_TO_DEG;                    vector eulerDeg = euler*RAD_TO_DEG;                    llOwnerSay(                        "< "+(string)((integer)eulerDeg.x)+                        ", "+(string)((integer)eulerDeg.y)+                        ", "+(string)((integer)eulerDeg.z)+" > =?= "+                        "< "+(string)(((integer)foundEulerDeg.x + 360) % 360)+                        ", "+(string)(((integer)foundEulerDeg.y + 360) % 360)+                        ", "+(string)(((integer)foundEulerDeg.z + 360) % 360)+" >"                        );                    if (-1 == llListFindList(foundEulers, [foundEulerDeg]))                        foundEulers += foundEulerDeg;                };        llOwnerSay("Tried "+(string)numTried + " eulers and found "+(string)llGetListLength(foundRots)+" rotations and "            +(string)llGetListLength(foundEulers)+" back-converted eulers");    }}`
`< 0, 0, 0 > =?= < 0, 0, 0 >< 0, 0, 90 > =?= < 0, 0, 90 >< 0, 0, 180 > =?= < 0, 0, 180 >< 0, 0, 270 > =?= < 0, 0, 270 >< 0, 90, 0 > =?= < 0, 90, 0 >< 0, 90, 90 > =?= < 0, 90, 90 >< 0, 90, 180 > =?= < 0, 90, 180 >< 0, 90, 270 > =?= < 0, 90, 270 >< 0, 180, 0 > =?= < 180, 0, 180 >< 0, 180, 90 > =?= < 180, 0, 270 >< 0, 180, 180 > =?= < 180, 0, 0 >< 0, 180, 270 > =?= < 180, 0, 90 >< 0, 270, 0 > =?= < 0, 270, 0 >< 0, 270, 90 > =?= < 0, 270, 90 >< 0, 270, 180 > =?= < 0, 270, 180 >< 0, 270, 270 > =?= < 0, 270, 270 >< 90, 0, 0 > =?= < 90, 0, 0 >< 90, 0, 90 > =?= < 90, 0, 90 >< 90, 0, 180 > =?= < 90, 0, 180 >< 90, 0, 270 > =?= < 90, 0, 270 >< 90, 90, 0 > =?= < 0, 90, 90 >< 90, 90, 90 > =?= < 0, 90, 180 >< 90, 90, 180 > =?= < 0, 90, 270 >< 90, 90, 270 > =?= < 0, 90, 0 >< 90, 180, 0 > =?= < 270, 0, 180 >< 90, 180, 90 > =?= < 270, 0, 270 >< 90, 180, 180 > =?= < 270, 0, 0 >< 90, 180, 270 > =?= < 270, 0, 90 >< 90, 270, 0 > =?= < 0, 270, 270 >< 90, 270, 90 > =?= < 0, 270, 0 >< 90, 270, 180 > =?= < 0, 270, 90 >< 90, 270, 270 > =?= < 0, 270, 180 >< 180, 0, 0 > =?= < 180, 0, 0 >< 180, 0, 90 > =?= < 180, 0, 90 >< 180, 0, 180 > =?= < 180, 0, 180 >< 180, 0, 270 > =?= < 180, 0, 270 >< 180, 90, 0 > =?= < 0, 90, 180 >< 180, 90, 90 > =?= < 0, 90, 270 >< 180, 90, 180 > =?= < 0, 90, 0 >< 180, 90, 270 > =?= < 0, 90, 90 >< 180, 180, 0 > =?= < 0, 0, 180 >< 180, 180, 90 > =?= < 0, 0, 270 >< 180, 180, 180 > =?= < 0, 0, 0 >< 180, 180, 270 > =?= < 0, 0, 90 >< 180, 270, 0 > =?= < 0, 270, 180 >< 180, 270, 90 > =?= < 0, 270, 270 >< 180, 270, 180 > =?= < 0, 270, 0 >< 180, 270, 270 > =?= < 0, 270, 90 >< 270, 0, 0 > =?= < 270, 0, 0 >< 270, 0, 90 > =?= < 270, 0, 90 >< 270, 0, 180 > =?= < 270, 0, 180 >< 270, 0, 270 > =?= < 270, 0, 270 >< 270, 90, 0 > =?= < 0, 90, 270 >< 270, 90, 90 > =?= < 0, 90, 0 >< 270, 90, 180 > =?= < 0, 90, 90 >< 270, 90, 270 > =?= < 0, 90, 180 >< 270, 180, 0 > =?= < 90, 0, 180 >< 270, 180, 90 > =?= < 90, 0, 270 >< 270, 180, 180 > =?= < 90, 0, 0 >< 270, 180, 270 > =?= < 90, 0, 90 >< 270, 270, 0 > =?= < 0, 270, 90 >< 270, 270, 90 > =?= < 0, 270, 180 >< 270, 270, 180 > =?= < 0, 270, 270 >< 270, 270, 270 > =?= < 0, 270, 0 >Tried 64 eulers and found 24 rotations and 24 back-converted eulers`

The first difference I see is at <0, 180, 0>, which my script maps to <180, 0, 180> but your listing shows <0, 0, 0>.  (When I try it myself in the viewer, at first it seems to show <180, 0, 0> but then eventually "correct" itself to <180, 0, 180>, so I'm not sure what I'm looking at with the Build Tool anymore.)

##### Share on other sites

it depends on the order they entered

sometimes takes me 4 or 5 or 6 goes to work out the entry order to get the values to stick

but it do stick for all when get the order right. and the box is still oriented as it should

then I click off the box and then reselect. It then shows the value that it (the viewer code) defaults to

+

i might of made a mistake on some of them when I was doing it. bc was really annoying. I never swear at it tho. Even if it deserved it (:

+

ps

i just now check the <0,180,0>

the order for that one from <0,0,0> is:

Y enter 180

changes to <180,180,180>

X enter 0

Z enter 0

click off box. reselect. shows <0,0,0>

eta: Z even
##### Share on other sites

i think that what you did (the script) is pretty good

is the script returns that are the most important to know about

if is a dif between the viewer edit mapping and the script mapping then is only a pain when using the viewer as a debug tool

which is still pretty painful when you think about it

##### Share on other sites

will save bunches of if this and if that and if another thingys

and the techniques can lend itself more easy to other similar situations

so I had a more think (:

+

can reduce all vectors (rounded to 90deg) to a indice in [0..63]

can reduce the scale to a indice in [0..7]

so the lookup table can have max 512 (64 * 8) entries for the offset

if map the 64 downto 24 then 24 * 8 = 192 entries

+

a way it can be done is with 2 lookup tables. One of 192 and the other of 64. 192 + 64 = 256. So half the max

some pcodes as example

`int reduce(vec3 v, vec3 s){  // normalise any vector (v) (incl. negatives) to round 90deg then   // reduce and stuff into pointer (p)  int p = (round((round(v.x) + 360) % 360 / 90) << 4) |          (round((round(v.y) + 360) % 360 / 90) << 2) |          (round((round(v.z) + 360) % 360 / 90));  // map of 64 vector indices downto 24 vector indices  // can write other function/script to compute these and stick in  list m = [0...23, 0..23, 0..15];     // get the map reduction of p  p = m[p];  // reduce the scale (s) and add to p  p = (p << 3) |      (round(s.x) & 1 << 2) |      (round(s.y) & 1 << 1) |      (round(s.z) & 1);  return p; // is in range [0..191] 24 * 8 = 192}...// is a list of the 192 offsets from the set //   [<0.0,0.0,0.0>..<0.5,0.5,0.5>] // can write other function/script to compute these and stick inlist offsets = [ ... ] ...the main proggy...vec3 v = <92,-179, -12>;int p = reduce(v, getScale() );vec3 offset = list2vec(offsets, p);`

##### Share on other sites

I feel like I'm in a room of mathematicians and everything is so far above my head lol. I was expecting to get somebody to mention a math equasion that would eliminate the need for so many if statements but it sounds like I've done it one of the most simplistic ways already.

So it sounds like I just have too many and need to eliminate the redundant ones? Then I'm good?

By the way I purposly left out what the project is since it's so difficult to explain, it'd make the whole thing even more complicated. You all can contact me in-world if you want to see it in action to fully understand what it is. Catch me sometime when I'm online if interested.

##### Share on other sites

Maths equations are fine for continuously-varying relationships, but you have touched on an area where there are special significances to some of the values, such as 0, 90, 180, 270, and in effect you have moved from what is linear solving to integer solving. There are discontinuities created by the special-significance values that cannot be easily handled by normal functions.

As I said right at the beginning, I thought your code was find as it was, and the only simolification I saw was to the cauclation of the offsets.

The list-based lookup table that the other posters have discussed is actually a better solution in that much of the calculations can be done at an initialisation stage and not on the fly, so it would improve run-time performance.

I probably will pop across and see what you're working on, it's got my curiousity ramped up past cat-mode, I'm active UK time so possibly a couple of hours ahead of this time tomorrow, it that's OK with you?

##### Share on other sites

i just say that the reason why is no simple equation yet is that there is no relationship (that we aware of in your OP) between the Scale and the Rotation

that each (Scale and Rotation) is independent of the other. So the arithmetic:

64 Rotations * 8 Scales = 512 max combinations

is what Qie was suggest when he said working with the full 64 vectors (which is the general case) is the way he would go

the mapping down to 24 is a specific case. Meaning that the inputs (as rotations) are coming from a 3D cube in a specific source (the LL script engine)

the general case is that the inputs can come from any source. Like they might be generated by another function altogether. Like another function of the program that moves the cube itself, rather than say the LL physics engine for example

+

is very possible that in a specific use case that there is a relationship between the Scale and Rotation, and so the lookup tables (if any) can be shorten quite considerable. Or even that there can be a equation/algo that can translate the Scale and Rotation into Offset depending on how the program manipulates the behaviour of the cube/object

so basically when working thru this kinda stuff then work out what is the general case. make some codes for that. and library it, so can reuse later for other things

then reduce/simplify the codes down for the specific use cases
##### Share on other sites

irihapeti wrote:

i just say that the reason why is no simple equation yet is that there is no relationship (that we aware of in your OP) between the Scale and the Rotation

Yes, and I expect Prof will discover there's some simple "rule" that relates scale and rotation to the desired offset, once the application is known. We might be able to "discover" that by studying different scales of objects in all the possible rotations, categorized according to which offset manipulation is to be applied. But I'm far too lazy for that.

I nonetheless feel compelled to tie-up a loose end here, so here's a little script that (in very cursory testing) seems to do the same thing as the script in the original post:

`list offsetAsgns = [    // Index / Value    / Derivation    /*   0  */  273,     // = 100 010 001  = X offset from x scale, Y from y, Z from z    /*   1  */  161,     // = 010 100 001  = X offset from y scale, Y from x, Z from z    /*   2  */  266,     // = 100 001 010  = X offset from x scale, Y from z, Z from y    /*   3  */   84,     // = 001 010 100  = X offset from z scale, Y from y, Z from x    /*   4  */   98,     // = 001 100 010  = X offset from z scale, Y from x, Z from y    /*   5  */  140      // = 010 001 100  = X offset from y scale, Y from z, Z from x    ];string rotClasses = "0101343401013434252543432525434301013434010134342525434325254343";default{    state_entry()    {        vector Scale = llGetScale();                float x = 0.5 * !(llRound(Scale.x) & 1);    // Evens? So, opposite of irhapeti's first post?        float y = 0.5 * !(llRound(Scale.y) & 1);        float z = 0.5 * !(llRound(Scale.z) & 1);        vector myEuler = llRot2Euler(llGetRot());        integer quantizedEulerX = (llRound(myEuler.x / PI_BY_TWO) + 4) % 4;        integer quantizedEulerY = (llRound(myEuler.y / PI_BY_TWO) + 4) % 4;        integer quantizedEulerZ = (llRound(myEuler.z / PI_BY_TWO) + 4) % 4;        llSetRot(llEuler2Rot(< (float)quantizedEulerX, (float)quantizedEulerY, (float)quantizedEulerZ >            * PI_BY_TWO));        integer rotClassIdx =             16 * (integer)quantizedEulerX +             4 * (integer)quantizedEulerY +                 (integer)quantizedEulerZ;        integer rotClass = (integer)llGetSubString(rotClasses, rotClassIdx, rotClassIdx);        integer oBits = llList2Integer(offsetAsgns, rotClass);        vector offset = // Could be separate X-, Y-, and Z-offsets, but guessing will be used as a vector:            <   x * (oBits>>8 & 1) +                y * (oBits>>7 & 1) +                z * (oBits>>6 & 1)             ,   x * (oBits>>5 & 1) +                y * (oBits>>4 & 1) +                z * (oBits>>3 & 1)            ,   x * (oBits>>2 & 1) +                y * (oBits>>1 & 1) +                z * (oBits & 1)            >;        llOwnerSay((string)offset);    }}`

The six-element offsetAsgns table derived from the categories of offset-adjustment in the original post (where the category listed last  is merged with category 3 here). The values inside are nine-bit integers, where the high-order 3 bits code how the X offset is determined (bit 0 for z-scale dependency, bit 1 for y-scale, bit 2 for x-scale), the next 3 bits similarly for Y-offset, and the bottom 3 bits for Z-offset.

The string of 64 rotClasses could as well be a 64-element list of the offsetAsgns integers themselves, instead of indices into that little table. That would save one string-indexing at the cost of more memory in the 64-integer list than in a 64-character string and a 6-integer list.

Either way, though, it's far from intuitive. So why would anybody ever do such a thing?

The idea is to avoid conditionals and table lookups. Most importantly, it's much faster to index directly into a list (or string) than to first match an element in that list. Here, the value we retrieve is a bit vector we can use to do the funky offset calculation in a closed-form assignment, without needing any conditionals at all.

Does this save a lot? Probably not, unless this code runs many copies, constantly. Also, because we don't really know much about how the LSL compiler turns statements into executable instructions, we can't be sure how much we win, without testing.

##### Share on other sites

I don't do the "  Prof will discover there's some simple "rule" that relates scale and rotation to the desired offse", I do the "get hit on the head by debris falling from the shattered hypotheses". I'm more interested in when exactly these flips occur. Running a script yesterday I was getting the feeling that X leads it, as soon as an X value is reached for which there is a simpler set of XYZ eulers, the re-arrangement occurs. I've got to turn the loops around and run the Y or the Z first to see if that hypothesis stands or falls.

If you haven''t done so, I do suggest popping over to see what Yamil's been doing.

##### Share on other sites

i like this

specially this bit

integer quantizedEulerX = (llRound(myEuler.x / PI_BY_TWO) + 4) % 4;
integer quantizedEulerY = (llRound(myEuler.y / PI_BY_TWO) + 4) % 4;
integer quantizedEulerZ = (llRound(myEuler.z / PI_BY_TWO) + 4) % 4;

is way better (faster and elegant) than what I had in my pcodes