Difference between revisions of "Category talk:LSL Vector"

From Second Life Wiki
Jump to navigation Jump to search
 
(5 intermediate revisions by 2 users not shown)
Line 41: Line 41:
===Useful Snippets===
===Useful Snippets===


The IsVector function fails for vectors whose z element is negative, at least under Mono. (It also does not work on other grids because the cast to vector and back to string eliminates negative zero there.)
The IsVector function fails for vectors whose z element is negative, at least under Mono. (It also does not work on other grids because the cast to vector and back to string eliminates negative zero there.)<br>
'''Edit:''' It does work, see Correction below...


I tried the following:
I tried the following:
Line 77: Line 78:
With this function, the above tests work. It tests for number of elements and then lets the compiler decide what it accepts as vector. Only for ZERO_VECTOR, special treatment is necessary. Therefore, it checks that only zeros and decimal points are in the remaining string. The compiler itself accepts missing ">" and it would also accept more than 3 elements - that's why the function checks the number of elements before.
With this function, the above tests work. It tests for number of elements and then lets the compiler decide what it accepts as vector. Only for ZERO_VECTOR, special treatment is necessary. Therefore, it checks that only zeros and decimal points are in the remaining string. The compiler itself accepts missing ">" and it would also accept more than 3 elements - that's why the function checks the number of elements before.


It's probably not the most efficient way to do it and also accepts more than is actually valid (esp. for ZERO_VECTOR), but it does accept all valid vactors (I hope ^^). Discussion and improvements are welcome. For IsRotation, the implementation would be almost the same, except checking for 4 elements instead of 3.
It's probably not the most efficient way to do it and also accepts more than is actually valid (esp. for ZERO_VECTOR), but it does accept all valid vectors (I hope ^^). Discussion and improvements are welcome. For IsRotation, the implementation would be almost the same, except checking for 4 elements instead of 3.


[[User:Shuichi Shinji|Shuichi Shinji]] 01:13, 31 March 2014 (PDT)
[[User:Shuichi Shinji|Shuichi Shinji]] 01:13, 31 March 2014 (PDT)
:It's going to give false positives on things with multiple periods. And it doesn't handle zero vectors expressed in hex or scientific notation. I applaud your efforts thus far. -- '''[[User:Strife_Onizuka|Strife]]''' <sup><small>([[User talk:Strife_Onizuka|talk]]|[[Special:Contributions/Strife_Onizuka|contribs]])</small></sup> 13:16, 31 March 2014 (PDT)
<lsl>
llOwnerSay( "IsVector(<.,.,.>) -> 0: "                          + (string)IsVector( "<.,.,.>" ) );//BTW: breaks LSL Editor
llOwnerSay( "IsVector(<.......,0,0>) -> 0: "                    + (string)IsVector( "<.......,0,0>" ) );//BTW: breaks LSL Editor
llOwnerSay( "IsVector(<0x0.0,0x0p+1,-0x0p-1>) -> 1: "            + (string)IsVector( "<0x0.0,0x0.p+1,-0x0.p-1>" ) );
llOwnerSay( "IsVector(<0.0e1,0.0e+1,-0.0e-1>) -> 1: "            + (string)IsVector( "<0.0e1,0.0e+1,-0.0e-1>" ) );
</lsl>
::Right. I don't know how bad false positives are; the other 2 could be solved by adding 1,x,e,p to the split list, but also adding more false positives, which is not nice. But just adding a "-" to the split list in the original implementation would solve that it's not working for negative z's yet. Of course, it would also add some false positives, such as "1.2--3", but so it already did with "1.2  3" (spaces inside the number) - maybe one line from my proposal could be added so that it properly checks non-ZERO_VECTORs, at least. -- [[User:Shuichi Shinji|Shuichi Shinji]] 08:30, 4 April 2014 (PDT)
<lsl>
integer IsVector(string s)
{
    list split = llParseString2List(s, [" ", "-"], ["<", ">", ","]);
    if(llGetListLength(split) != 7)//we must check the list length, or the next test won't work properly.
        return FALSE;
    if((vector)s != ZERO_VECTOR)//parsing error or real ZERO_VECTOR lead to ZERO_VECTOR
        return TRUE;
    return !((string)((vector)s) == (string)((vector)((string)llListInsertList(split, ["-"], 5))));
    //it works by trying to flip the sign on the Z element of the vector,
    //if it works or breaks the vector then the values won't match.
    //if the vector was already broken then the sign flip will have no affect and the values will match
    //we cast back to string so we can catch negative zero which allows for support of ZERO_VECTOR
}
</lsl>
----
====Correction====
Ok, your function '''does''' work for negative z's, I must have made a mistake when I first checked it - sorry for the confusion. However, I have a few improvements:
* don't filter out spaces during the split, because e.g. "  < 1 , 2 , 3 > " is not a valid vector (the leading spaces are the problem): <lsl>list split = llParseString2List( s, [], ["<", ">", ","] );</lsl>
* for rotations, don't add the "-" for the s member, but for z (I had problems with s)
With these, the following checks all work (in SL; LSLeditor interprets it a bit differently in some cases):
<lsl>
llOwnerSay( "IsVector(<0.47,0.149, 1.001>) -> 1: "              + (string)IsVector( "<0.47,0.149, 1.001>" ) );
llOwnerSay( "IsVector(<0.47,0.149, 1.001,3>) -> 0: "            + (string)IsVector( "<0.47,0.149, 1.001,3>" ) );
llOwnerSay( "IsVector(<0.47,0.149,-1.001>) -> 1: "              + (string)IsVector( "<0.47,0.149,-1.001>" ) );
llOwnerSay( "IsVector(<0.47,0.149,+1.001>) -> 1: "              + (string)IsVector( "<0.47,0.149,+1.001>" ) );
llOwnerSay( "IsVector(<  0.47, 0.149,    -1.001  >) -> 1: "    + (string)IsVector( "<  0.47, 0.149,    -1.001  >" ) );
llOwnerSay( "IsVector(  <  0.47, 0.149,    -1.001  > ) -> 0: " + (string)IsVector( "  <  0.47, 0.149,    -1.001  > " ) );
llOwnerSay( "IsVector(<0.47,0.1A9,-1.001>) -> 0: "              + (string)IsVector( "<0.47,0.1A9,-1.001>" ) );
llOwnerSay( "IsVector(<0.47,0.149,;-1.001>) -> 0: "              + (string)IsVector( "<0.47,;0.149,-1.001>" ) );
llOwnerSay( "IsVector(<0.47,0.149,-1.001) -> 0: "                + (string)IsVector( "<0.47,0.149,-1.001" ) );
llOwnerSay( "IsVector(<0,0.000,0>) -> 1: "                      + (string)IsVector( "<0,0.000,0>" ) );
llOwnerSay( "IsVector(<0,0.000,0,0>) -> 0: "                    + (string)IsVector( "<0,0.000,0,0>" ) );
llOwnerSay( "IsVector(<+0,-0.000,-0>) -> 1: "                    + (string)IsVector( "<+0,-0.000,-0>" ) );
llOwnerSay( "IsVector(<0x0.0,0x0p+1,-0x0p-1>) -> 1: "            + (string)IsVector( "<0x0.0,0x0.p+1,-0x0.p-1>" ) );
llOwnerSay( "IsVector(<0.0e1,0.0e+1,-0.0e-1>) -> 1: "            + (string)IsVector( "<0.0e1,0.0e+1,-0.0e-1>" ) );
llOwnerSay( "IsRotation(<0.47,0.149,-1.001>) -> 0: "            + (string)IsRotation( "<0.47,0.149,-1.001>" ) );
llOwnerSay( "IsRotation(<0.47,0.149,-1.001,3>) -> 1: "          + (string)IsRotation( "<0.47,0.149,-1.001,3>" ) );
llOwnerSay( "IsRotation(<0.47,0.149,+1.001,3>) -> 1: "          + (string)IsRotation( "<0.47,0.149,+1.001,3>" ) );
llOwnerSay( "IsRotation(<  0.47, 0.149,  0.99,3  >) -> 1: "    + (string)IsRotation( "<  0.47, 0.149,  0.99,3  >" ) );
llOwnerSay( "IsRotation(  <  0.47, 0.149,  0.99,3  > ) -> 0: "  + (string)IsRotation( "  <  0.47, 0.149,  0.99,3  > " ) );
llOwnerSay( "IsRotation(<0.47,0.1A9,-1.001,3>) -> 0: "          + (string)IsRotation( "<0.47,0.1A9,-1.001,3>" ) );
llOwnerSay( "IsRotation(<0.47,0.149,-1.001,;3>) -> 0: "          + (string)IsRotation( "<0.47,;0.149,-1.001,3>" ) );
llOwnerSay( "IsRotation(<0.47,0.149,-1.001,3) -> 0: "            + (string)IsRotation( "<0.47,0.149,-1.001,3" ) );
llOwnerSay( "IsRotation(<0,0.000,0>) -> 0: "                    + (string)IsRotation( "<0,0.000,0>" ) );
llOwnerSay( "IsRotation(<0,0.000,0,0>) -> 1: "                  + (string)IsRotation( "<0,0.000,0,0>" ) );
llOwnerSay( "IsRotation(<+0,-0.000,-0,-0>) -> 1: "              + (string)IsRotation( "<+0,-0.000,-0,-0>" ) );
</lsl>
'''Not relevant for SL, just a remark:''' For grids where the "-" approach does not work because negative zeros are filtered out during the casts, the following slightly less elegant works instead:
<lsl>
// vector
if ( (vector)((string)llListReplaceList( split, [1], 5, 5 )) == ZERO_VECTOR ) return FALSE;  // parsing error in x or y
return ((vector)((string)llListReplaceList( split, [1], 3, 3 )) != ZERO_VECTOR);            // parsing error in z
// rotation
if ( (rotation)((string)llListReplaceList( split, [2], 7, 7 )) == ZERO_ROTATION ) return FALSE;  // parsing error in x, y or z
return ((rotation)((string)llListReplaceList( split, [1], 5, 5 )) != ZERO_ROTATION);              // parsing error in s
</lsl>
[[User:Shuichi Shinji|Shuichi Shinji]] 01:20, 10 April 2014 (PDT)

Latest revision as of 00:20, 10 April 2014

<lsl> //******************************* //IMPOSSIBLE TO GET A ZERO_VECTOR //*******************************

vector c = <0.0, 0.0, 0.1>;

default {

   touch_start(integer total_number)
   {
       c -= <0.0, 0.0, 0.025>;
       llSay(0, (string)c);
       if (c == ZERO_VECTOR) llSay(0, "ZERO_VECTOR"); // never c is a ZERO_VECTOR
   }

} </lsl> <lsl> //********************** //IN THIS WAY IT RUNS... //**********************

vector c = <0.0, 0.0, 0.1>;

default {

   touch_start(integer total_number)
   {
       c -= <0.0, 0.0, 0.025>;
       llSay(0, (string)c);
       if ((string)c == "<0.00000, 0.00000, 0.00000>") llSay(0, "ZERO_VECTOR");
   }

} </lsl> —The preceding unsigned comment was added on 06:29, 29 April 2012 by Zohan Galewind


The above is caused by how floating point math works. 0.1 does not fall on an exact boundary as a float, nor does 0.025. Furthermore the rounding on the two values do not exactly line up, so (4 * 0.025) != 0.1. This is not a bug but a caveat of using floating point math. -- Strife (talk|contribs) 11:00, 29 April 2012 (PDT)

Useful Snippets

The IsVector function fails for vectors whose z element is negative, at least under Mono. (It also does not work on other grids because the cast to vector and back to string eliminates negative zero there.)
Edit: It does work, see Correction below...

I tried the following:

<lsl> // After the "->" is the expected result (for the proposed new function), after the ":" the actual one llOwnerSay( "IsVector(<0.47,0.149, 1.001>) -> 1: " + (string)IsVector( "<0.47,0.149, 1.001>" ) ); llOwnerSay( "IsVector(<0.47,0.149, 1.001,3>) -> 0: " + (string)IsVector( "<0.47,0.149, 1.001,3>" ) ); llOwnerSay( "IsVector(<0.47,0.149,-1.001>) -> 1: " + (string)IsVector( "<0.47,0.149,-1.001>" ) ); llOwnerSay( "IsVector(<0.47,0.149,+1.001>) -> 1: " + (string)IsVector( "<0.47,0.149,+1.001>" ) ); llOwnerSay( "IsVector( < 0.47, 0.149, -1.001 > ) -> 0: " + (string)IsVector( " < 0.47, 0.149, -1.001 > " ) ); llOwnerSay( "IsVector(<0.47,0.1A9,-1.001>) -> 0: " + (string)IsVector( "<0.47,0.1A9,-1.001>" ) ); llOwnerSay( "IsVector(<0.47,;0.149,-1.001>) -> 0: " + (string)IsVector( "<0.47,;0.149,-1.001>" ) ); llOwnerSay( "IsVector(<0.47,0.149,-1.001) -> 1: " + (string)IsVector( "<0.47,0.149,-1.001" ) ); llOwnerSay( "IsVector(<0,0.000,0>) -> 1: " + (string)IsVector( "<0,0.000,0>" ) ); llOwnerSay( "IsVector(<0,0.000,0,0>) -> 0: " + (string)IsVector( "<0,0.000,0,0>" ) ); llOwnerSay( "IsVector(<+0,-0.000,-0>) -> 1: " + (string)IsVector( "<+0,-0.000,-0>" ) ); </lsl>

I propose the following change:

<lsl> // Returns whether the given string contains a vector. // Accepts what the compiler accepts and checks ZERO_VECTOR separately. integer IsVector ( string s ) {

   list split = llParseString2List( s, ["<", ">", ",", " ", "-", "+"], [] );  // not allowed to be inside numbers
   if ( llGetListLength( split ) != 3 ) return FALSE;  // must be 3 elements
   if ( (vector)s != ZERO_VECTOR ) return TRUE;  // parsing error or real ZERO_VECTOR lead to ZERO_VECTOR
   split = llParseString2List( (string)split, ["0", "."], [] );
   return (split == []);

} </lsl>

With this function, the above tests work. It tests for number of elements and then lets the compiler decide what it accepts as vector. Only for ZERO_VECTOR, special treatment is necessary. Therefore, it checks that only zeros and decimal points are in the remaining string. The compiler itself accepts missing ">" and it would also accept more than 3 elements - that's why the function checks the number of elements before.

It's probably not the most efficient way to do it and also accepts more than is actually valid (esp. for ZERO_VECTOR), but it does accept all valid vectors (I hope ^^). Discussion and improvements are welcome. For IsRotation, the implementation would be almost the same, except checking for 4 elements instead of 3.

Shuichi Shinji 01:13, 31 March 2014 (PDT)

It's going to give false positives on things with multiple periods. And it doesn't handle zero vectors expressed in hex or scientific notation. I applaud your efforts thus far. -- Strife (talk|contribs) 13:16, 31 March 2014 (PDT)

<lsl> llOwnerSay( "IsVector(<.,.,.>) -> 0: " + (string)IsVector( "<.,.,.>" ) );//BTW: breaks LSL Editor llOwnerSay( "IsVector(<.......,0,0>) -> 0: " + (string)IsVector( "<.......,0,0>" ) );//BTW: breaks LSL Editor llOwnerSay( "IsVector(<0x0.0,0x0p+1,-0x0p-1>) -> 1: " + (string)IsVector( "<0x0.0,0x0.p+1,-0x0.p-1>" ) ); llOwnerSay( "IsVector(<0.0e1,0.0e+1,-0.0e-1>) -> 1: " + (string)IsVector( "<0.0e1,0.0e+1,-0.0e-1>" ) ); </lsl>

Right. I don't know how bad false positives are; the other 2 could be solved by adding 1,x,e,p to the split list, but also adding more false positives, which is not nice. But just adding a "-" to the split list in the original implementation would solve that it's not working for negative z's yet. Of course, it would also add some false positives, such as "1.2--3", but so it already did with "1.2 3" (spaces inside the number) - maybe one line from my proposal could be added so that it properly checks non-ZERO_VECTORs, at least. -- Shuichi Shinji 08:30, 4 April 2014 (PDT)

<lsl> integer IsVector(string s) {

   list split = llParseString2List(s, [" ", "-"], ["<", ">", ","]);
   if(llGetListLength(split) != 7)//we must check the list length, or the next test won't work properly.
       return FALSE;
   if((vector)s != ZERO_VECTOR)//parsing error or real ZERO_VECTOR lead to ZERO_VECTOR
       return TRUE;
   return !((string)((vector)s) == (string)((vector)((string)llListInsertList(split, ["-"], 5))));
   //it works by trying to flip the sign on the Z element of the vector,
   //if it works or breaks the vector then the values won't match.
   //if the vector was already broken then the sign flip will have no affect and the values will match
   //we cast back to string so we can catch negative zero which allows for support of ZERO_VECTOR

} </lsl>


Correction

Ok, your function does work for negative z's, I must have made a mistake when I first checked it - sorry for the confusion. However, I have a few improvements:

  • don't filter out spaces during the split, because e.g. " < 1 , 2 , 3 > " is not a valid vector (the leading spaces are the problem): <lsl>list split = llParseString2List( s, [], ["<", ">", ","] );</lsl>
  • for rotations, don't add the "-" for the s member, but for z (I had problems with s)

With these, the following checks all work (in SL; LSLeditor interprets it a bit differently in some cases):

<lsl> llOwnerSay( "IsVector(<0.47,0.149, 1.001>) -> 1: " + (string)IsVector( "<0.47,0.149, 1.001>" ) ); llOwnerSay( "IsVector(<0.47,0.149, 1.001,3>) -> 0: " + (string)IsVector( "<0.47,0.149, 1.001,3>" ) ); llOwnerSay( "IsVector(<0.47,0.149,-1.001>) -> 1: " + (string)IsVector( "<0.47,0.149,-1.001>" ) ); llOwnerSay( "IsVector(<0.47,0.149,+1.001>) -> 1: " + (string)IsVector( "<0.47,0.149,+1.001>" ) ); llOwnerSay( "IsVector(< 0.47, 0.149, -1.001 >) -> 1: " + (string)IsVector( "< 0.47, 0.149, -1.001 >" ) ); llOwnerSay( "IsVector( < 0.47, 0.149, -1.001 > ) -> 0: " + (string)IsVector( " < 0.47, 0.149, -1.001 > " ) ); llOwnerSay( "IsVector(<0.47,0.1A9,-1.001>) -> 0: " + (string)IsVector( "<0.47,0.1A9,-1.001>" ) ); llOwnerSay( "IsVector(<0.47,0.149,;-1.001>) -> 0: " + (string)IsVector( "<0.47,;0.149,-1.001>" ) ); llOwnerSay( "IsVector(<0.47,0.149,-1.001) -> 0: " + (string)IsVector( "<0.47,0.149,-1.001" ) ); llOwnerSay( "IsVector(<0,0.000,0>) -> 1: " + (string)IsVector( "<0,0.000,0>" ) ); llOwnerSay( "IsVector(<0,0.000,0,0>) -> 0: " + (string)IsVector( "<0,0.000,0,0>" ) ); llOwnerSay( "IsVector(<+0,-0.000,-0>) -> 1: " + (string)IsVector( "<+0,-0.000,-0>" ) ); llOwnerSay( "IsVector(<0x0.0,0x0p+1,-0x0p-1>) -> 1: " + (string)IsVector( "<0x0.0,0x0.p+1,-0x0.p-1>" ) ); llOwnerSay( "IsVector(<0.0e1,0.0e+1,-0.0e-1>) -> 1: " + (string)IsVector( "<0.0e1,0.0e+1,-0.0e-1>" ) ); llOwnerSay( "IsRotation(<0.47,0.149,-1.001>) -> 0: " + (string)IsRotation( "<0.47,0.149,-1.001>" ) ); llOwnerSay( "IsRotation(<0.47,0.149,-1.001,3>) -> 1: " + (string)IsRotation( "<0.47,0.149,-1.001,3>" ) ); llOwnerSay( "IsRotation(<0.47,0.149,+1.001,3>) -> 1: " + (string)IsRotation( "<0.47,0.149,+1.001,3>" ) ); llOwnerSay( "IsRotation(< 0.47, 0.149, 0.99,3 >) -> 1: " + (string)IsRotation( "< 0.47, 0.149, 0.99,3 >" ) ); llOwnerSay( "IsRotation( < 0.47, 0.149, 0.99,3 > ) -> 0: " + (string)IsRotation( " < 0.47, 0.149, 0.99,3 > " ) ); llOwnerSay( "IsRotation(<0.47,0.1A9,-1.001,3>) -> 0: " + (string)IsRotation( "<0.47,0.1A9,-1.001,3>" ) ); llOwnerSay( "IsRotation(<0.47,0.149,-1.001,;3>) -> 0: " + (string)IsRotation( "<0.47,;0.149,-1.001,3>" ) ); llOwnerSay( "IsRotation(<0.47,0.149,-1.001,3) -> 0: " + (string)IsRotation( "<0.47,0.149,-1.001,3" ) ); llOwnerSay( "IsRotation(<0,0.000,0>) -> 0: " + (string)IsRotation( "<0,0.000,0>" ) ); llOwnerSay( "IsRotation(<0,0.000,0,0>) -> 1: " + (string)IsRotation( "<0,0.000,0,0>" ) ); llOwnerSay( "IsRotation(<+0,-0.000,-0,-0>) -> 1: " + (string)IsRotation( "<+0,-0.000,-0,-0>" ) ); </lsl>

Not relevant for SL, just a remark: For grids where the "-" approach does not work because negative zeros are filtered out during the casts, the following slightly less elegant works instead:

<lsl> // vector if ( (vector)((string)llListReplaceList( split, [1], 5, 5 )) == ZERO_VECTOR ) return FALSE; // parsing error in x or y return ((vector)((string)llListReplaceList( split, [1], 3, 3 )) != ZERO_VECTOR); // parsing error in z // rotation if ( (rotation)((string)llListReplaceList( split, [2], 7, 7 )) == ZERO_ROTATION ) return FALSE; // parsing error in x, y or z return ((rotation)((string)llListReplaceList( split, [1], 5, 5 )) != ZERO_ROTATION); // parsing error in s </lsl>

Shuichi Shinji 01:20, 10 April 2014 (PDT)