<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
	<id>https://wiki.secondlife.com/w/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Timmy+Foxclaw</id>
	<title>Second Life Wiki - User contributions [en]</title>
	<link rel="self" type="application/atom+xml" href="https://wiki.secondlife.com/w/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Timmy+Foxclaw"/>
	<link rel="alternate" type="text/html" href="https://wiki.secondlife.com/wiki/Special:Contributions/Timmy_Foxclaw"/>
	<updated>2026-07-27T11:53:00Z</updated>
	<subtitle>User contributions</subtitle>
	<generator>MediaWiki 1.42.1</generator>
	<entry>
		<id>https://wiki.secondlife.com/w/index.php?title=User:Timmy_Foxclaw/About_Coordinate_Systems_and_Rotations&amp;diff=1195684</id>
		<title>User:Timmy Foxclaw/About Coordinate Systems and Rotations</title>
		<link rel="alternate" type="text/html" href="https://wiki.secondlife.com/w/index.php?title=User:Timmy_Foxclaw/About_Coordinate_Systems_and_Rotations&amp;diff=1195684"/>
		<updated>2015-02-28T23:39:08Z</updated>

		<summary type="html">&lt;p&gt;Timmy Foxclaw: Replace broken &amp;lt;lsl&amp;gt; tag with &amp;lt;syntaxhighlight lang=&amp;quot;lsl2&amp;quot;&amp;gt;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== About Coordinate Systems and Rotations ==&lt;br /&gt;
&lt;br /&gt;
=== The four coordinate systems ===&lt;br /&gt;
&lt;br /&gt;
There are four coordinate systems that are related to LSL programming:&lt;br /&gt;
# World coordinates&lt;br /&gt;
# Region coordinates&lt;br /&gt;
# Object coordinates (root prim coordinates)&lt;br /&gt;
# Child prim coordinates (coordinates relative to the prim that the script is in, or refered to by link number)&lt;br /&gt;
&lt;br /&gt;
The World coordinates refer to the map, and allow to include the sim&lt;br /&gt;
in the coordinates, or refer to void water.&lt;br /&gt;
&lt;br /&gt;
Region coordinates are relative to a given sim.&lt;br /&gt;
The origin is in the South/West corner at height 0.&lt;br /&gt;
The North/East corner then is 256, 256 and a Z coordinate&lt;br /&gt;
for the height up to 4096 meter (on opensim you can go even&lt;br /&gt;
higher).&lt;br /&gt;
&lt;br /&gt;
Object coordinates are relative to the root prim. Hence, if the object&lt;br /&gt;
is moved or rotated then the orientation of a child prim, when given&lt;br /&gt;
in object coordinates, doesn&#039;t change. In LSL &amp;quot;local position&amp;quot; and&lt;br /&gt;
&amp;quot;local rotation&amp;quot; refer to this coordinate system. &amp;quot;local&amp;quot; means&lt;br /&gt;
relative to the root prim.&lt;br /&gt;
&lt;br /&gt;
Prim Coordinates are relative to a given prim. If this prim is the root&lt;br /&gt;
prim then the Prim Coordinates are the same as the Object Coordinates.&lt;br /&gt;
For example, if a child prim is a cube with a size of 1,1,1 and one&lt;br /&gt;
red surface where the center of that surface is at 0.5,0,0 then it will&lt;br /&gt;
still be at 0.5,0,0 no matter how you move or rotate that child prim&lt;br /&gt;
(relative to the other linked prims).&lt;br /&gt;
&lt;br /&gt;
=== Positions ===&lt;br /&gt;
&lt;br /&gt;
A different position of the origin of a coordinate system is easy to understand:&lt;br /&gt;
You can think of positions as vectors that start in the origin of the&lt;br /&gt;
coordinate system that they are given in and end in the point that they&lt;br /&gt;
refer to. While the length of the vector is independent of the rotation of&lt;br /&gt;
the coordinate system, the three coordinates are not; but a mental picture&lt;br /&gt;
of an arrow doesn&#039;t have little numbers for three coordinates, so that&lt;br /&gt;
picture works independent of the rotation too.&lt;br /&gt;
&lt;br /&gt;
Since the rotation of the World Coordinate system and the Region Coordinate&lt;br /&gt;
system is the same (X, Y and Z axis are parallel of both), and since&lt;br /&gt;
World Coordinates aren&#039;t used in many LSL functions to begin with, we&lt;br /&gt;
will ignore World Coordinates for now and only refer to Region Coordinates,&lt;br /&gt;
or say &amp;quot;global&amp;quot; when we mean Region Coordinates.&lt;br /&gt;
&lt;br /&gt;
=== Rotations ===&lt;br /&gt;
&lt;br /&gt;
An LSL rotation internally stores a vector that is the axis around which&lt;br /&gt;
to rotate and the angle of the rotation around that axis.&lt;br /&gt;
Let &#039;&#039;&#039;V&#039;&#039;&#039; = &amp;amp;lt;u, v, w&amp;amp;gt; be the normalized vector (that is, with length 1) around&lt;br /&gt;
which we rotate and let &amp;amp;alpha; (alpha) be the angle around which we have to rotate.&lt;br /&gt;
Then the LSL rotation is a quaternion stored as r = &amp;amp;lt;x, y, z, s&amp;amp;gt; = &amp;amp;lt; &#039;&#039;&#039;V&#039;&#039;&#039; * sin(&amp;amp;alpha;/2), cos(&amp;amp;alpha;/2) &amp;amp;gt;.&lt;br /&gt;
Thus, r.x = x * sin(&amp;amp;alpha;/2), and r.s = cos(&amp;amp;alpha;/2) etc. Note that the quaternion&lt;br /&gt;
is also normalized.&lt;br /&gt;
Also note that there is a duality here because inverting &#039;&#039;&#039;V&#039;&#039;&#039; (making it point the&lt;br /&gt;
opposite way) and inverting the angle gives the same rotation; r and -r have&lt;br /&gt;
different values but are the same rotation.&lt;br /&gt;
Also note that if you don&#039;t rotate at all (&amp;amp;alpha; == 0) then it doesn&#039;t matter&lt;br /&gt;
what axis &#039;&#039;&#039;V&#039;&#039;&#039; you pick, which is apparent because &#039;&#039;&#039;V&#039;&#039;&#039; drops out since sin(0) = 0.&lt;br /&gt;
The quaternion &amp;amp;lt;0, 0, 0, 1&amp;amp;gt; is the ZERO_ROTATION quaternion.&lt;br /&gt;
&lt;br /&gt;
The point of this technical story is to show that for an LSL rotation to&lt;br /&gt;
make sense in terms of orientation, you need to be able to express a vector&lt;br /&gt;
in three coordinates (u, v, w above): the axis around which we rotate is&lt;br /&gt;
expressed relative to the X-, Y- and Z-axes of the coordinate system. Hence,&lt;br /&gt;
it is the orientation of the X-, Y- and Z-axes that defines the meaning&lt;br /&gt;
of a rotation in LSL.&lt;br /&gt;
&lt;br /&gt;
In terms of a mental picture the origin with the (orientation of the) three axis,&lt;br /&gt;
the red X-axis, the green Y-axis and the blue Z-axis is all the reference&lt;br /&gt;
we need, combined with a vector for position or a quaternion for rotation.&lt;br /&gt;
&lt;br /&gt;
When you edit an object, the viewer shows either &#039;World&#039; (meaning Region here) or &#039;Local&#039; axes, but&lt;br /&gt;
really the &#039;World&#039; (region) axes show the wrong origin, shifted to an averaged center&lt;br /&gt;
of the object, because if the origin was drawn at (0, 0, 0) you&#039;d most likely&lt;br /&gt;
not see it. The &#039;Local&#039; ruler shows the correct coordinate system for the&lt;br /&gt;
selected prim as its Prim Coordinate System. Selecting the root prim with&lt;br /&gt;
&#039;Local&#039; ruler on then shows the Object Coordinate System.&lt;br /&gt;
&lt;br /&gt;
=== The dimension of rotations ===&lt;br /&gt;
&lt;br /&gt;
As said before, given some coordinate system, any point in space can&lt;br /&gt;
be represented with a vector. Obviously space is three dimensional,&lt;br /&gt;
and thus vectors exists of three real values:&lt;br /&gt;
one needs three distinct floating point numbers, the x coordinate,&lt;br /&gt;
the y coordinate and the z coordinate to uniquely&lt;br /&gt;
identify a position in a given coordinate system.&lt;br /&gt;
&lt;br /&gt;
However, if one limits oneself to only normalized vectors, vectors&lt;br /&gt;
with a length of one, then those represent all points on the surface&lt;br /&gt;
of a sphere with radius 1.&lt;br /&gt;
A surface is obviously two dimensional, so it should be possible to&lt;br /&gt;
uniquely identify any point on the surface of such a sphere with&lt;br /&gt;
only two floating point numbers.&lt;br /&gt;
&lt;br /&gt;
One might think that selecting just two coordinates of the three of&lt;br /&gt;
the vector will suffice because the third is fixed by the length requirement,&lt;br /&gt;
but that only works for half spheres; for example, if x and y are known&lt;br /&gt;
then z can still be either plus the square root of x squared plus y squared,&lt;br /&gt;
&#039;&#039;or&#039;&#039; minus that value.&lt;br /&gt;
&lt;br /&gt;
Instead, a better choice would be the [http://mathworld.wolfram.com/SphericalCoordinates.html spherical coordinate system]&lt;br /&gt;
and express the unit vectors with the two angular coordinates &amp;amp;phi; (phi) and &amp;amp;theta; (theta),&lt;br /&gt;
where &amp;amp;phi; is the angle between the vector and the positive Z axis, and&lt;br /&gt;
&amp;amp;theta; the angle that the projection of the vector on to the X,Y plane makes&lt;br /&gt;
with the positive X axis. In other words, starting with a unit vector&lt;br /&gt;
along the positive Z-axis, one can obtain the required point on&lt;br /&gt;
the surface of the sphere by first rotating this vector around the&lt;br /&gt;
Y axis (towards the positive X axis) by an angle of &amp;amp;phi; and then rotating&lt;br /&gt;
the result around the Z-axis by an angle of &amp;amp;theta;. Note that in both cases&lt;br /&gt;
the rotations are counter-clockwise when one looks at it from the positive&lt;br /&gt;
side of the axis that one rotates around (towards the origin).&lt;br /&gt;
&lt;br /&gt;
What we just did was expressing a unit vector in terms of two rotations:&lt;br /&gt;
one around the Z axis and one around the Y axis; and indeed every rotation&lt;br /&gt;
can be expressed as two rotations around those two axis (or really, any&lt;br /&gt;
two arbitrary axes, as long as they are independent (not parallel)).&lt;br /&gt;
&lt;br /&gt;
It is therefore possible to represent unit vectors (aka, a &#039;&#039;direction&#039;&#039;)&lt;br /&gt;
with a rotation, as both are two dimensional. The mental picture here is&lt;br /&gt;
that any unit vector can be expressed as some fixed unit vector (for example&lt;br /&gt;
the one pointing along the positive Z axis, but any other would do as well)&lt;br /&gt;
and the rotation needed to turn that &#039;starting vector&#039; into the unit vector&lt;br /&gt;
that one wants to represent. The other way around almost works as well, with the&lt;br /&gt;
exception of the starting vector itself, as that can be expressed by any arbitrary&lt;br /&gt;
rotation around itself, so that information was lost and it is not possible&lt;br /&gt;
to know which of those rotations was used. In fact, any vector&lt;br /&gt;
close to the starting vector would give inaccurate results in the light&lt;br /&gt;
of floating point round off errors and is not a good way to represent&lt;br /&gt;
a rotation. Of course, the two dimensional vector (&amp;amp;theta;, &amp;amp;phi;) would be excellent&lt;br /&gt;
to represent both: the unit vector, as well as any rotation; but LSL stores&lt;br /&gt;
vectors in x, y, z coordinates, not in spherical coordinates.&lt;br /&gt;
&lt;br /&gt;
=== Converting between coordinate systems ===&lt;br /&gt;
&lt;br /&gt;
Consider a child prim of an object that is not the root prim and express&lt;br /&gt;
its position with the vector pos_oc, and its orientation with the rotation rot_oc,&lt;br /&gt;
both relative to the Object Coordinates system.&lt;br /&gt;
&lt;br /&gt;
A script inside that prim can easily obtain those values:&lt;br /&gt;
&lt;br /&gt;
 vector pos_oc = [[llGetLocalPos]]();&lt;br /&gt;
 rotation rot_oc = [[llGetLocalRot]]();&lt;br /&gt;
&lt;br /&gt;
The postfix &#039;_oc&#039; stands for Object Coordinates and is used to make clear&lt;br /&gt;
relative to which coordinate system the x, y and z values of both&lt;br /&gt;
variables are. Remember that also the rotation contains a vector&lt;br /&gt;
(the axis around which we rotate), so from now on we&#039;ll talk about&lt;br /&gt;
&#039;coordinates&#039; relative to a coordinate system for both, the position&lt;br /&gt;
as well as the rotation, where the coordinates refer to the x, y and z&lt;br /&gt;
components of the position and the rotation. For example, the first&lt;br /&gt;
sentence of this paragraph will read &amp;quot;...express its position with the&lt;br /&gt;
vector pos_oc, and its orientation with the rotation rot_oc, &#039;&#039;both in Object Coordinates&#039;&#039;.&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Note that&#039;&#039;&#039; one has to be careful here, because a script in the&lt;br /&gt;
root prim of the object will &#039;&#039;&#039;&#039;&#039;not&#039;&#039;&#039;&#039;&#039; obtain&lt;br /&gt;
Object Coordinates but instead Region Coordinates!&lt;br /&gt;
The reason is that the &#039;Local&#039; functions return coordinates relative to&lt;br /&gt;
the &#039;parent&#039; coordinate system, where the parent of a non-root prim is the root prim,&lt;br /&gt;
but the parent of the root prim is the region (or avatar in case&lt;br /&gt;
of an attachment). The position and rotation of the root prim in&lt;br /&gt;
Object Coordinates is trivial (ZERO_VECTOR and ZERO_ROTATION respectively).&lt;br /&gt;
&lt;br /&gt;
Back to the script in the child prim. It can also easily obtain its position&lt;br /&gt;
and rotation in Region Coordinates:&lt;br /&gt;
&lt;br /&gt;
 vector pos_rc = [[llGetPos]]();&lt;br /&gt;
 rotation rot_rc = [[llGetRot]]();&lt;br /&gt;
&lt;br /&gt;
Both sets, (pos_oc, rot_oc) and (pos_rc, rot_rc) refer to the same thing,&lt;br /&gt;
so it should be possible to convert them into each other.&lt;br /&gt;
&lt;br /&gt;
One can do this by looking at the orientation (position and rotation) of&lt;br /&gt;
one coordinate system relative to the other and expressed&lt;br /&gt;
in the coordinates of that other. The position and rotation&lt;br /&gt;
of the Object Coordinate System relative to the Region Coordinate&lt;br /&gt;
System, and in Region Coordinates, could be obtained as follows:&lt;br /&gt;
&lt;br /&gt;
 vector oc_pos_rc = [[llGetRootPosition]]();&lt;br /&gt;
 rotation oc_rot_rc = [[llGetRootRotation]]();&lt;br /&gt;
&lt;br /&gt;
As indicated by the &#039;_rc&#039; postfix, these are again in Region Coordinates.&lt;br /&gt;
&lt;br /&gt;
Having the relative orientation of the Object Coordinate System in Region Coordinates, it is&lt;br /&gt;
possible to convert Object Coordinates into Region Coordinates. More&lt;br /&gt;
abstractly put, if you have two coordinate systems A and B, and you have&lt;br /&gt;
their relative orientation expressed in A then you can convert orientations&lt;br /&gt;
expressed in B into A.&lt;br /&gt;
&lt;br /&gt;
The formula is as follows:&lt;br /&gt;
&lt;br /&gt;
 &#039;&#039;&#039;vector   pos_A = pos_B * B_rot_A + B_pos_A;            (1)&#039;&#039;&#039;&lt;br /&gt;
 &#039;&#039;&#039;rotation rot_A = rot_B * B_rot_A;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
The order of the multiplications is important; swapping the B_rot_A to the front will not work!&lt;br /&gt;
&lt;br /&gt;
Note that the B_*_A are the position and rotation of the coordinate system B expressed&lt;br /&gt;
in terms of the coordinate system A. The reason that I use the prefix and postfix in&lt;br /&gt;
this order is directly related to the order enforced for rotation multiplications.&lt;br /&gt;
Written this way, the left-hand postfix of a multiplication must match the right-hand prefix&lt;br /&gt;
and conviently short-circuits the notation:&lt;br /&gt;
&lt;br /&gt;
 something_A = something&#039;&#039;&#039;_B&#039;&#039;&#039; * &#039;&#039;&#039;B_&#039;&#039;&#039;rot_A&lt;br /&gt;
&lt;br /&gt;
the two B&#039;s &#039;connect&#039; and drop out (along with the &#039;_rot_&#039;) to give something_ ... A.&lt;br /&gt;
This &#039;&#039;only&#039;&#039; works when the postfix (_A or _B) refers to the coordinate system that the variables&lt;br /&gt;
are in, and the prefix is whatever is described by the variable, possibly another&lt;br /&gt;
coordinate system (B_ in this example).&lt;br /&gt;
&lt;br /&gt;
A complete example script follows:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lsl2&amp;quot;&amp;gt;&lt;br /&gt;
default&lt;br /&gt;
{&lt;br /&gt;
    touch(integer num_detected)&lt;br /&gt;
    {&lt;br /&gt;
        llSay(0, &amp;quot;---------&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
        // Get the pos and rot in Object Coordinates.&lt;br /&gt;
        vector pos_oc = llGetLocalPos();&lt;br /&gt;
        rotation rot_oc = llGetLocalRot();&lt;br /&gt;
        &lt;br /&gt;
        // Fix these values when this script is in the root prim!&lt;br /&gt;
        if (llGetLinkNumber() &amp;lt;= 1)&lt;br /&gt;
        {&lt;br /&gt;
            pos_oc = ZERO_VECTOR;&lt;br /&gt;
            rot_oc = ZERO_ROTATION;&lt;br /&gt;
        }&lt;br /&gt;
        &lt;br /&gt;
        // Get the pos and rot in Region Coordinates.&lt;br /&gt;
        vector pos_rc = llGetPos();&lt;br /&gt;
        rotation rot_rc = llGetRot();&lt;br /&gt;
        &lt;br /&gt;
        // Get the pos and rot of the Object Coordinate System in Region Coordinates.&lt;br /&gt;
        vector oc_pos_rc = llGetRootPosition();&lt;br /&gt;
        rotation oc_rot_rc = llGetRootRotation();&lt;br /&gt;
        &lt;br /&gt;
        // Print the values of the positions (the rotations are too hard to understand).&lt;br /&gt;
        llSay(0, &amp;quot;oc_pos_rc = &amp;quot; + (string)oc_pos_rc);&lt;br /&gt;
        llSay(0, &amp;quot;pos_os = &amp;quot; + (string)pos_os);&lt;br /&gt;
        llSay(0, &amp;quot;pos_rc = &amp;quot; + (string)pos_rc);&lt;br /&gt;
        &lt;br /&gt;
        // Calculate pos_rc and rot_rc from pos_oc and rot_oc : converting between _oc and _rc.&lt;br /&gt;
        vector   pos2_rc = pos_oc * oc_rot_rc + oc_pos_rc;&lt;br /&gt;
        rotation rot2_rc = rot_oc * oc_rot_rc;&lt;br /&gt;
        &lt;br /&gt;
        // Print the result for the position, and show the difference with what llGetPos() and llGetRot() returned.&lt;br /&gt;
        llSay(0, &amp;quot;pos2_rc = &amp;quot; + (string)pos2_rc);&lt;br /&gt;
        // These values should be ZERO_VECTOR and ZERO_ROTATION (or -ZERO_ROTATION).&lt;br /&gt;
        llSay(0, &amp;quot;pos_rc - pos2_rc = &amp;quot; + (string)(pos_rc - pos2_rc));&lt;br /&gt;
        llSay(0, &amp;quot;rot_rc / rot2_rc = &amp;quot; + (string)(rot_rc / rot2_rc));&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Obviously there is no preference for one coordinate system over the other for this conversion;&lt;br /&gt;
one can equally as well convert orientations in A into B:&lt;br /&gt;
&lt;br /&gt;
 vector   pos_B = pos_A * A_rot_B + A_pos_B;&lt;br /&gt;
 rotation rot_B = rot_A * A_rot_B;&lt;br /&gt;
&lt;br /&gt;
The question arises then how to obtain the A_*_B values; there is no LSL function that returns directly&lt;br /&gt;
the position or rotation of the region relative to a prim (aka, rc_*_oc).&lt;br /&gt;
&lt;br /&gt;
Intuitively one would say that it has to be possible to express A_*_B in B_*_A on grounds of symmetry, and that&lt;br /&gt;
is indeed the case.&lt;br /&gt;
&lt;br /&gt;
To show how this works, lets just take the formula for pos_A and rot_A (see (1) above) and rework&lt;br /&gt;
them to get pos_B and rot_B on the left-hand side. This results first in&lt;br /&gt;
&lt;br /&gt;
 pos_B * B_rot_A = pos_A - B_pos_A&lt;br /&gt;
 rot_B * B_rot_A = rot_A&lt;br /&gt;
&lt;br /&gt;
Then divide both sides by B_rot_A to get:&lt;br /&gt;
&lt;br /&gt;
 pos_B = pos_A / B_rot_A - B_pos_A / B_rot_A&lt;br /&gt;
 rot_B = rot_A / B_rot_A&lt;br /&gt;
&lt;br /&gt;
from which we can conclude that&lt;br /&gt;
&lt;br /&gt;
 &#039;&#039;&#039;A_pos_B = - B_pos_A / B_rot_A                           (2)&#039;&#039;&#039;&lt;br /&gt;
 &#039;&#039;&#039;A_rot_B = ZERO_ROTATION / B_rot_A&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Note how A_rot_B is the inverse of B_rot_A: A_rot_B * B_rot_A = ZERO_ROTATION.&lt;br /&gt;
As per our notation convention you&#039;d expect A_rot_B * B_rot_A to be A_rot_A, and that is&lt;br /&gt;
actually the case as A_rot_A means the relative orientation of coordinate system A&lt;br /&gt;
expressed in A&#039;s coordinates, which is the trivial ZERO_VECTOR and ZERO_ROTATION as&lt;br /&gt;
we saw before for the root prim orientation expressed in Object Coordinates.&lt;br /&gt;
&lt;br /&gt;
And for fun, note that if we do this inversion again we get:&lt;br /&gt;
&lt;br /&gt;
 B_pos_A = - A_pos_B / A_rot_B = - (- B_pos_A / B_rot_A) / (ZERO_ROTATION / B_rot_A) = B_pos_A / B_rot_A * B_rot_A = B_pos_A&lt;br /&gt;
 B_rot_A = ZERO_ROTATION / A_rot_B = ZERO_ROTATION / (ZERO_ROTATION / B_rot_A) = B_rot_A&lt;br /&gt;
&lt;br /&gt;
as expected.&lt;br /&gt;
&lt;br /&gt;
We can now also convert Region Coordinates to Object Coordinates.&lt;br /&gt;
&lt;br /&gt;
One could first calculate,&lt;br /&gt;
&lt;br /&gt;
 vector rc_pos_oc = - llGetRootPosition() / llGetRootRotation();&lt;br /&gt;
 rotation rc_rot_oc = ZERO_ROTATION / llGetRootRotation();&lt;br /&gt;
&lt;br /&gt;
and then convert as usual:&lt;br /&gt;
&lt;br /&gt;
 vector   pos_oc = pos_rc * rc_rot_oc + rc_pos_oc;&lt;br /&gt;
 rotation rot_oc = rot_rc * rc_rot_oc;&lt;br /&gt;
&lt;br /&gt;
or if you don&#039;t want to calculate the intermediate rc_*_oc values, you could do immediately:&lt;br /&gt;
&lt;br /&gt;
 vector   pos_oc = (pos_rc - llGetRootPosition()) / llGetRootRotation();&lt;br /&gt;
 rotation rot_oc = rot_rc / llGetRootRotation();&lt;br /&gt;
&lt;br /&gt;
To verify this, you could extend the above script with&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lsl2&amp;quot;&amp;gt;&lt;br /&gt;
        // Calculate pos_oc and rot_oc from pos_rc and rot_rc.&lt;br /&gt;
        vector   pos2_oc = (pos_rc - llGetRootPosition()) / llGetRootRotation();&lt;br /&gt;
        rotation rot2_oc = rot_rc / llGetRootRotation();&lt;br /&gt;
        &lt;br /&gt;
        llSay(0, &amp;quot;pos2_oc = &amp;quot; + (string)pos2_oc);&lt;br /&gt;
        // These values should again be ZERO_VECTOR and +/- ZERO_ROTATION.&lt;br /&gt;
        llSay(0, &amp;quot;pos_oc - pos2_oc = &amp;quot; + (string)(pos_oc - pos2_oc));&lt;br /&gt;
        llSay(0, &amp;quot;rot_oc / rot2_oc = &amp;quot; + (string)(rot_oc / rot2_oc));&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
More in general, if you want to convert from B to A, but you only have A_*_B instead of B_*_A, then (combining (1) and (2))&lt;br /&gt;
you can do:&lt;br /&gt;
&lt;br /&gt;
 &#039;&#039;&#039;vector   pos_A = (pos_B - A_pos_B) / A_rot_B;           (3)&#039;&#039;&#039;&lt;br /&gt;
 &#039;&#039;&#039;rotation rot_A = rot_B / A_rot_B;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
=== Cascading coordinate systems ===&lt;br /&gt;
&lt;br /&gt;
Imagine you have a castle object where the floor is the root prim. Everything is linked because you&lt;br /&gt;
want it to be easy to move the castle around. One of the child prims is a sculpty representing the hinges&lt;br /&gt;
around which you want to rotate a large gate. The gate has a rotating wheel on it.&lt;br /&gt;
&lt;br /&gt;
You want that the object (castle) to keep working when it is moved and/or rotated, but also when it is edited&lt;br /&gt;
and the hinges are moved and/or rotated. This means that the state of the gate prims&lt;br /&gt;
must be &#039;&#039;stored&#039;&#039; relative to the hinges, which is by far the easiest thing to do to begin with,&lt;br /&gt;
after all, the gate rotates around the hinges and has no relation with the rest of the castle.&lt;br /&gt;
&lt;br /&gt;
Hence, we have the Region Coordinate System, the Object Coordinate System (the castle) and the Hinges Coordinate System.&lt;br /&gt;
The latter is our first example of a Prim Coordinates System, but I&#039;ll use the postfix &#039;_hc&#039; for &amp;quot;Hinges Coordinates&amp;quot;&lt;br /&gt;
instead of &#039;_pc&#039;. Finally we have the Spill Coordinate System (or Gate Coordinates) where the spill is a prim&lt;br /&gt;
around which we want to rotate the wheel, and I&#039;ll use &#039;_sc&#039; as postfix for that.&lt;br /&gt;
&lt;br /&gt;
The variables used then would be an orientation for the wheel in *_sc coordinates, the orientation of the spill,&lt;br /&gt;
and other gate prims, in *_hc coordinates and the orientation of the hinges in *_oc coordinates. Finally we could&lt;br /&gt;
have variables for the orientation of the castle (root prim) in *_rc coordinates of course.&lt;br /&gt;
&lt;br /&gt;
 vector   castle_pos_rc; // The position of the castle in Region Coordinates.&lt;br /&gt;
 rotation castle_rot_rc; // The rotation of the castle in Region Coordinates.&lt;br /&gt;
 &lt;br /&gt;
 vector   hinges_pos_oc; // The position of the hinges in Object Coordinates.&lt;br /&gt;
 rotation hinges_rot_oc; // The rotation of the hinges in Object Coordinates.&lt;br /&gt;
 &lt;br /&gt;
 vector   spill_pos_hc;  // The position of the spill in Hinges Coordinates.&lt;br /&gt;
 rotation spill_rot_hc;  // The rotation of the spill in Hinges Coordinates.&lt;br /&gt;
 &lt;br /&gt;
 vector   wheel_pos_sc;  // The position of the wheel in Spill Coordinates.&lt;br /&gt;
 rotation wheel_rot_sc;  // The rotation of the wheel in Spill Coordinates.&lt;br /&gt;
&lt;br /&gt;
Now because we used existing prims orientations as coordinate system for the next prim, the position&lt;br /&gt;
and rotation of those prims &#039;&#039;are&#039;&#039; the position and rotation of that coordinate system.&lt;br /&gt;
Just like before we saw that llGetPos/llGetRot returns the global orientation of the root prim&lt;br /&gt;
when used in a script in the root prim, while llGetRootPos/llGetRootRot gave us the relative&lt;br /&gt;
orientation of the Object Coordinate System in Region Coordinates, but is in fact the same as&lt;br /&gt;
what llGetPos/llGetRot in the root prim returns: the position/rotation of the root prim &#039;&#039;&#039;is&#039;&#039;&#039;&lt;br /&gt;
the orientation of the Object Coordinate System relative to the Region.&lt;br /&gt;
&lt;br /&gt;
Likewise, in this case, castle_*_rc is the relative orientation of the Object Coordinate System&lt;br /&gt;
in Region Coordinates as well as the orientation of the root prim in Region Coordinates; they&lt;br /&gt;
are the same thing.&lt;br /&gt;
&lt;br /&gt;
The same then applies to the *_oc variables, which we defined as the orientation of&lt;br /&gt;
the hinges in Object Coordinates, but at the same time are the relative orientation&lt;br /&gt;
of the Hinges Coordinate System in Object Coordinates. The *_hc variables are the&lt;br /&gt;
orientation of spill in Hinges Coordinates, but also the relative orientation of&lt;br /&gt;
the Spill Coordinates in Hinges Coordinates.&lt;br /&gt;
&lt;br /&gt;
Lets write it out using the same notation convention as used above, then&lt;br /&gt;
we have:&lt;br /&gt;
&lt;br /&gt;
 vector   oc_pos_rc = castle_pos_rc; // The Object Coordinate System orientation in Region Coordinates.&lt;br /&gt;
 rotation oc_rot_rc = castle_rot_rc;&lt;br /&gt;
 &lt;br /&gt;
 vector   hc_pos_oc = hinges_pos_oc; // The Hinges Coordinate System orientation in Object Coordinates.&lt;br /&gt;
 rotation hc_rot_oc = hinges_rot_oc;&lt;br /&gt;
 &lt;br /&gt;
 vector   sc_pos_hc = spill_pos_hc;  // The Spill Coordinate System orientation in Hinges Coordinates.&lt;br /&gt;
 rotation sc_rot_hc = spill_rot_hc;&lt;br /&gt;
&lt;br /&gt;
It will therefore probably not surprise you that&lt;br /&gt;
&lt;br /&gt;
 vector   hc_pos_rc = hc_pos_oc * oc_rot_rc + oc_pos_rc; // The Hinges Coordinate System orientation in Region Coordinates.&lt;br /&gt;
 rotation hc_rot_rc = hc_rot_oc * oc_rot_rc;&lt;br /&gt;
 &lt;br /&gt;
 vector   sc_pos_rc = sc_pos_hc * hc_rot_rc + hc_pos_rc; // The Spill Coordinate System orientation in Region Coordinates.&lt;br /&gt;
 rotation sc_rot_rc = sc_rot_hc * hc_rot_rc;&lt;br /&gt;
&lt;br /&gt;
And finally, using the latter, we can express the wheel orientation in region coordinates:&lt;br /&gt;
&lt;br /&gt;
 vector   wheel_pos_rc = wheel_pos_sc * sc_rot_rc + sc_pos_rc;&lt;br /&gt;
 rotation wheel_rot_rc = wheel_rot_sc * sc_rot_rc;&lt;br /&gt;
&lt;br /&gt;
Although this was nothing else but applying the coordinate system conversion formula ((1)) three times,&lt;br /&gt;
it might give some insight to get rid of the intermediate variables and express the wheel&lt;br /&gt;
orientation in region coordinates without them, giving:&lt;br /&gt;
&lt;br /&gt;
 wheel_pos_rc = ((wheel_pos_sc * sc_rot_hc + sc_pos_hc) * hc_rot_oc + hc_pos_oc) * oc_rot_rc + oc_pos_rc&lt;br /&gt;
 wheel_rot_rc = wheel_rot_sc * sc_rot_hc * hc_rot_oc * oc_rot_rc&lt;br /&gt;
&lt;br /&gt;
=== Applying rotations and translations ===&lt;br /&gt;
&lt;br /&gt;
Applying rotations and translations (moving) is very much the same as coordinate system transformations described above.&lt;br /&gt;
To show this consider the following: imagine you have a prim &#039;pa&#039; with its own coordinate system A.&lt;br /&gt;
Then it trivially has position ZERO_VECTOR and rotation ZERO_ROTATION relative to A, per definition.&lt;br /&gt;
&lt;br /&gt;
 vector   pa_pos_A = ZERO_VECTOR;&lt;br /&gt;
 rotation pa_rot_A = ZERO_ROTATION;&lt;br /&gt;
&lt;br /&gt;
Now consider a prim &#039;pb&#039; that has some relative position pb_pos_A and rotation pb_rot_A given in A coordinates.&lt;br /&gt;
For example,&lt;br /&gt;
&lt;br /&gt;
 vector   pb_pos_A = &amp;lt;0.5, 0.6, 0.7&amp;gt;;&lt;br /&gt;
 rotation pb_rot_A = &amp;lt;0.38, 0.26, 0.34, 0.82&amp;gt;;&lt;br /&gt;
&lt;br /&gt;
Note that 0.38&amp;amp;sup2; + 0.26&amp;amp;sup2; + 0.34&amp;amp;sup2; + 0.82&amp;amp;sup2; = 1, as it must be since rotations are normalized.&lt;br /&gt;
&lt;br /&gt;
As seen before, the orientation of pb relative to pa is the same as the orientation of pb relative to A,&lt;br /&gt;
and the same as the orientation of B relative to A. pa and A are interchangeable as long as pa has&lt;br /&gt;
ZERO_VECTOR and ZERO_ROTATION relative to A. Thus, with B being the coordinate system where pb currently&lt;br /&gt;
is, we also have:&lt;br /&gt;
&lt;br /&gt;
 vector   B_pos_A = pb_pos_A; // The orientation of coordinate system B, in coordinates of A.&lt;br /&gt;
 rotation B_rot_A = pb_rot_A;&lt;br /&gt;
&lt;br /&gt;
Now suppose we want move the prim pa (without moving the coordinate system A),&lt;br /&gt;
by applying the translation &#039;B_pos_A&#039;, after all a translation is stored in a vector&lt;br /&gt;
and B_pos_A is a vector. Likewise, we want to rotate pa (again without influencing A)&lt;br /&gt;
by applying the rotation B_rot_A. Then the most logical order to this in is by&lt;br /&gt;
&#039;&#039;first&#039;&#039; applying the rotation and &#039;&#039;then&#039;&#039; applying the translation, because then&lt;br /&gt;
the meaning of the translation is preserved and will match the meaning of B_pos_A&lt;br /&gt;
in that pa will end up where pb is now. If you&#039;d first apply the translation so that&lt;br /&gt;
pa ends up where pb is, and then apply the rotation (around A!) then pa would swoop&lt;br /&gt;
around the origin of A and move away from its desired position.&lt;br /&gt;
&lt;br /&gt;
Doing this correctly should leave us with pa_pos_A == pb_pos_A and pa_rot_A == pb_rot_A,&lt;br /&gt;
so that pa ended up precisely where pb is now. We can&#039;t just assign those values&lt;br /&gt;
however, because we&#039;re looking for a formula that works in general; a way to apply&lt;br /&gt;
B_rot_A and then B_pos_A to any prim with -say- orientation pc_pos_A, pc_rot_A.&lt;br /&gt;
&lt;br /&gt;
Thus, first we apply the rotation:&lt;br /&gt;
&lt;br /&gt;
 pc_rot_A *= B_rot_A;&lt;br /&gt;
 pc_pos_A *= B_rot_A;&lt;br /&gt;
&lt;br /&gt;
And then apply the translation:&lt;br /&gt;
&lt;br /&gt;
 pc_pos_A += B_pos_A;&lt;br /&gt;
&lt;br /&gt;
Now lets check if indeed this would cause pa to end up where pb is.&lt;br /&gt;
The effect on pa_*_A would be:&lt;br /&gt;
&lt;br /&gt;
 pa_rot_A = pa_rot_A * B_rot_A = ZERO_ROTATION * B_rot_A = B_rot_A = pb_rot_A;&lt;br /&gt;
 pa_pos_A = pa_pos_A * B_rot_A = ZERO_VECTOR * B_rot_A = ZERO_VECTOR;&lt;br /&gt;
 &lt;br /&gt;
 and then the translation&lt;br /&gt;
 &lt;br /&gt;
 pa_pos_A = pa_pos_A + B_pos_A = ZERO_VECTOR + B_pos_A = B_pos_A = pb_pos_A;&lt;br /&gt;
&lt;br /&gt;
So yes, pa_*_A ends up as pb_*_A!&lt;br /&gt;
&lt;br /&gt;
The real test however would be if we first applied some transformation to pa&lt;br /&gt;
to bring it to some arbitrary orientation (aka, pc), then apply the transformation&lt;br /&gt;
B_rot_A,B_pos_A and then reverse the first transformation but now relative to B,&lt;br /&gt;
and then find that we indeed end up at pb.&lt;br /&gt;
&lt;br /&gt;
Let us first define a &#039;transformation&#039;, which exists of a vector for the&lt;br /&gt;
translation and a rotation for the rotation. We will have two transformations&lt;br /&gt;
during this test: t1: pa -&amp;gt; pc, and t2: pa -&amp;gt; pb.&lt;br /&gt;
&lt;br /&gt;
As we just saw (or we hope this is going to be the case), t2 can be defined as:&lt;br /&gt;
&lt;br /&gt;
 vector   t2_translation = B_pos_A;&lt;br /&gt;
 rotation t2_rotation = B_rot_A;&lt;br /&gt;
&lt;br /&gt;
where as t1 is arbitrary, just some values t1_translation and t1_rotation.&lt;br /&gt;
&lt;br /&gt;
Applying t1 to pa, we get (this is thus the same as above, but now with the &#039;t1&#039; notation):&lt;br /&gt;
&lt;br /&gt;
 pa_rot_A *= t1_rotation;&lt;br /&gt;
 pa_pos_A *= t1_rotation;&lt;br /&gt;
 pa_pos_A += t1_translation;&lt;br /&gt;
&lt;br /&gt;
Next we apply translation t2 to that:&lt;br /&gt;
&lt;br /&gt;
 pa_rot_A *= t2_rotation;&lt;br /&gt;
 pa_pos_A *= t2_rotation;&lt;br /&gt;
 pa_pos_A += t2_translation;&lt;br /&gt;
&lt;br /&gt;
Finally we want to reverse t1, but in the coordinate system of B.&lt;br /&gt;
Therefore, we first convert our coordinates to that of B (formula (1)):&lt;br /&gt;
&lt;br /&gt;
 pa_pos_B = pa_pos_A * A_rot_B + A_pos_B;&lt;br /&gt;
 pa_rot_B = pa_rot_A * A_rot_B;&lt;br /&gt;
&lt;br /&gt;
where (formula (2))&lt;br /&gt;
&lt;br /&gt;
 A_pos_B = - B_pos_A / B_rot_A;&lt;br /&gt;
 A_rot_B = ZERO_ROTATION / B_rot_A;&lt;br /&gt;
&lt;br /&gt;
and then reverse t1. Note now we have to do the translation first!&lt;br /&gt;
&lt;br /&gt;
 pa_pos_B -= t1_translation;&lt;br /&gt;
 pa_pos_B /= t1_rotation;&lt;br /&gt;
 pa_rot_B /= t1_rotation;&lt;br /&gt;
&lt;br /&gt;
And if everything worked out then pa now should be at ZERO_VECTOR, ZERO_ROTATION relative to B!&lt;br /&gt;
&lt;br /&gt;
As pa_pos_A,pa_rot_A started as ZERO_VECTOR,ZERO_ROTATION, the first step&lt;br /&gt;
of applying t1 resulted in pa_rot_A = t1_rotation and pa_pos_A = t1_translation.&lt;br /&gt;
&lt;br /&gt;
After applying t2 we get pa_rot_A = t1_rotation * t2_rotation, and pa_pos_A = t1_translation * t2_rotation + t2_translation.&lt;br /&gt;
&lt;br /&gt;
Converting that to B gives&lt;br /&gt;
&lt;br /&gt;
 pa_pos_B = (t1_translation * t2_rotation + t2_translation) * A_rot_B + A_pos_B&lt;br /&gt;
 pa_rot_B = (t1_rotation * t2_rotation) * A_rot_B&lt;br /&gt;
&lt;br /&gt;
where, remembering that t2_translation = B_pos_A and t2_rotation = B_rot_A,&lt;br /&gt;
&lt;br /&gt;
 A_pos_B = - B_pos_A / B_rot_A = - t2_translation / t2_rotation&lt;br /&gt;
 A_rot_B = ZERO_ROTATION / B_rot_A = ZERO_ROTATION / t2_rotation&lt;br /&gt;
&lt;br /&gt;
so that we get&lt;br /&gt;
&lt;br /&gt;
 pa_pos_B = (t1_translation * t2_rotation + t2_translation) / t2_rotation - t2_translation / t2_rotation = t1_translation&lt;br /&gt;
 pa_rot_B = (t1_rotation * t2_rotation) / t2_rotation = t1_rotation&lt;br /&gt;
&lt;br /&gt;
and finally reversing t1 gives:&lt;br /&gt;
&lt;br /&gt;
 pa_pos_B = (t1_translation - t1_translation) / t1_rotation = ZERO_VECTOR&lt;br /&gt;
 pa_rot_B = t1_rotation / t1_rotation = ZERO_ROTATION&lt;br /&gt;
&lt;br /&gt;
So that we can conclude that if you have two prims pa and pb, each representing their own coordinate system A and B respectively,&lt;br /&gt;
and you express the orientation of B relative to A as the pair (B_pos_A, B_rot_A) &amp;amp;mdash; then the following holds.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;The transformation pair (t_translation, t_rotation) equals (B_pos_A, B_rot_A) as long as you first apply the rotation and then the translation while working in the coordinate system of A&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
The latter is also very practical, because you normally won&#039;t know&lt;br /&gt;
anything about the target coordinate system B until you actually did the transformation.&lt;br /&gt;
&lt;br /&gt;
Now remember that we found that in order to convert variables from being relative to a coordinate system B to a coordinate system A,&lt;br /&gt;
we did (formula (1)):&lt;br /&gt;
&lt;br /&gt;
 pos_A = pos_B * B_rot_A + B_pos_A&lt;br /&gt;
 rot_A = rot_B * B_rot_A&lt;br /&gt;
&lt;br /&gt;
which is thus exactly the same as first applying the rotation t1_rotation and then the translation t1_translation&lt;br /&gt;
on the pair (pos_B, rot_B) where that pair is relative to A! That isn&#039;t too weird because if you consider a prim&lt;br /&gt;
in the origin of A with no rotation, aka (ZERO_VECTOR, ZERO_ROTATION) relative to A and then apply the transformation&lt;br /&gt;
then you expect to end up in the origin of B with no rotation relative to B. Aka pos_B = ZERO_VECTOR and rot_B = ZERO_ROTATION.&lt;br /&gt;
So now work backwards: assume you already have the prim in B like that, then what are its coordinates in A?&lt;br /&gt;
That would be the above conversion thus, with pos_B = ZERO_VECTOR and rot_B = ZERO_ROTATION.&lt;br /&gt;
&lt;br /&gt;
Hence, doing the conversion with ZERO as input gives the same results as doing the t transformation with ZERO as input!&lt;br /&gt;
And the final formula for a transformation just looks exactly the same:&lt;br /&gt;
&lt;br /&gt;
 &#039;&#039;&#039;target_pos_A = source_pos_A * t_rotation + t_translation        (4)&#039;&#039;&#039;&lt;br /&gt;
 &#039;&#039;&#039;target_rot_A = source_rot_A * t_rotation&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
=== Scaling coordinate systems ===&lt;br /&gt;
&lt;br /&gt;
Apart from rotation and translation, there is one more linear operator that can be used to convert&lt;br /&gt;
between coordinate systems: scaling.&lt;br /&gt;
&lt;br /&gt;
Let A_pos_B be the position of the origin of A in the coordinates of B. Let A_rot_B be the orientation of A within B,&lt;br /&gt;
and let the vector A_B_scale be the scaling factors for each axes. Scaling has no influence on the origin of&lt;br /&gt;
a coordinate system, but it matters for the rotation when the scaling factors per axis are different.&lt;br /&gt;
&lt;br /&gt;
I think that a good choice is scale first and rotate afterwards. Because that leaves the values&lt;br /&gt;
of the coordinates of A_rot_B alone: it remains the rotation as defined in B, which makes sense&lt;br /&gt;
since it is written in the coordinates of B. However, it&#039;s just a matter of choice really, which&lt;br /&gt;
in this case will deform B_rot_A instead of A_rot_B. I can imagine that the choice might depend&lt;br /&gt;
on the application.&lt;br /&gt;
&lt;br /&gt;
Chosing that we first scale, a point at pos_A is mapped onto the point pos_B as follows:&lt;br /&gt;
&lt;br /&gt;
 pos_B = (S * pos_A) * A_rot_B + A_pos_B&lt;br /&gt;
&lt;br /&gt;
where S is a 3x3 matrix with as diagonal the vector A_B_scale (and the rest zeroes).&lt;br /&gt;
Note that when each element of A_B_scale is the same then you can just use a scalar for S, equal to the scale of each axis.&lt;br /&gt;
&lt;br /&gt;
Whether or not S is a matrix or a scalar, lets just replace it with &#039;A_B_scale&#039; here. Just keep in&lt;br /&gt;
mind that if it isn&#039;t a scalar then this won&#039;t work in LSL directly: then you&#039;ll have to split&lt;br /&gt;
it up in three different code lines because LSL doesn&#039;t support scaling or matrices.&lt;br /&gt;
&lt;br /&gt;
  pos_B = pos_A;&lt;br /&gt;
  pos_B.x *= A_B_scale.x;  // Scale&lt;br /&gt;
  pos_B.y *= A_B_scale.y;&lt;br /&gt;
  pos_B.z *= A_B_scale.z;&lt;br /&gt;
  pos_B *= A_rot_B;        // Rotate&lt;br /&gt;
  pos_B += A_pos_B;        // Translate&lt;br /&gt;
&lt;br /&gt;
Note that the inverse of S, 1/S, is a 3x3 matrix with as diagonal the inverse of each element of A_B_scale.&lt;br /&gt;
We will either write &#039;B_A_scale&#039;, or divide by &#039;A_B_scale&#039; in our notation.&lt;br /&gt;
&lt;br /&gt;
Therefore our notation becomes:&lt;br /&gt;
&lt;br /&gt;
 pos_B = (&#039;A_B_scale&#039; * pos_A) * A_rot_B + A_pos_B&lt;br /&gt;
&lt;br /&gt;
Since A and B are arbitrary, we would expect the same formula to hold when swapping A and B:&lt;br /&gt;
&lt;br /&gt;
 pos_A = (&#039;B_A_scale&#039; * pos_B) * B_rot_A + B_pos_A&lt;br /&gt;
&lt;br /&gt;
Solving pos_B from that by subtracting B_pos_A from both sides, then dividing both sides by B_rot_A&lt;br /&gt;
and finally left multiplying both sides with the inverse of B_A_scale, gives:&lt;br /&gt;
&lt;br /&gt;
 pos_B = &#039;A_B_scale&#039; * ((pos_A - B_pos_A) / B_rot_A) = &#039;A_B_scale&#039; * (pos_A / B_rot_A) - &#039;A_B_scale&#039; * (B_pos_A / B_rot_A)&lt;br /&gt;
&lt;br /&gt;
from which we can conclude (by setting pos_A to ZERO_VECTOR) that&lt;br /&gt;
&lt;br /&gt;
 A_pos_B = -&#039;A_B_scale&#039; * (B_pos_A / B_rot_A)&lt;br /&gt;
&lt;br /&gt;
Solving B_pos_A from that by left multiplying both sides with -B_A_scale and then right multiplying both sides with B_rot_A, gives:&lt;br /&gt;
&lt;br /&gt;
 B_pos_A = - (&#039;B_A_scale&#039; * A_pos_B) * B_rot_A&lt;br /&gt;
&lt;br /&gt;
By setting A_pos_B to ZERO_VECTOR, and this B_pos_A too, we can also conclude that&lt;br /&gt;
&lt;br /&gt;
 (&#039;A_B_scale&#039; * pos_A) * A_rot_B = &#039;A_B_scale&#039; * (pos_A / B_rot_A)&lt;br /&gt;
&lt;br /&gt;
If &#039;A_B_scale&#039; is a scalar, so that the order of multiplication doesn&#039;t matter,&lt;br /&gt;
then the scale just cancels on both sides and we find the conversion that we&lt;br /&gt;
found before, that B_rot_A is the inverse of A_rot_B. However, if A_B_scale&lt;br /&gt;
is a diagonal matrix then the order matters and the brackets are significant.&lt;br /&gt;
&lt;br /&gt;
There is no way to let pos_A drop out: we cannot write B_rot_A as function&lt;br /&gt;
of A_B_scale and A_rot_B.&lt;br /&gt;
&lt;br /&gt;
The conclusion is that a scale is asymmetrical: if you choose that a scale A_B_scale&lt;br /&gt;
means that you first apply the scale on a vector in A and then rotate, then&lt;br /&gt;
that automatically implies that when going from B to A you first have to rotate&lt;br /&gt;
and &#039;&#039;then&#039;&#039; apply the scale.&lt;br /&gt;
&lt;br /&gt;
To make the choice clear in the name, I suggest to put an &#039;r&#039; in front of the&lt;br /&gt;
coordinate system that need rotation to be applied first. &lt;br /&gt;
&lt;br /&gt;
In summary, if A_rB_scale is defined as&lt;br /&gt;
&lt;br /&gt;
 &#039;&#039;&#039;pos_B = (&#039;A_rB_scale&#039; * pos_A) * A_rot_B + A_pos_B      (5)&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
then that implies that rB_A_scale has to be applied after rotation.&lt;br /&gt;
Note this means braces, NOT changing the left- or right- side of&lt;br /&gt;
multiplications! Matrices (scales) are always on the left side&lt;br /&gt;
of a vector, while rotations are always on the right side. Thus we get: &lt;br /&gt;
&lt;br /&gt;
 &#039;&#039;&#039;pos_A = &#039;rB_A_scale&#039; * (pos_B * B_rot_A) + B_pos_A      (6)&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
If now we solve pos_B from the latter, we get:&lt;br /&gt;
&lt;br /&gt;
 pos_B = (&#039;A_rB_scale&#039; * (pos_A - B_pos_A)) / B_rot_A = (&#039;A_rB_scale&#039; * pos_A) / B_rot_A - (&#039;A_rB_scale&#039; * B_pos_A) / B_rot_A&lt;br /&gt;
&lt;br /&gt;
Hence&lt;br /&gt;
&lt;br /&gt;
 &#039;&#039;&#039;B_pos_A = - &#039;rB_A_scale&#039; * (A_pos_B / A_rot_B)          (7)&#039;&#039;&#039;&lt;br /&gt;
 &#039;&#039;&#039;B_rot_A = ZERO_ROTATION / A_rot_B&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
and&lt;br /&gt;
&lt;br /&gt;
 &#039;&#039;&#039;A_pos_B = - (&#039;A_rB_scale&#039; * B_posA) / B_rot_A           (8)&#039;&#039;&#039;&lt;br /&gt;
 &#039;&#039;&#039;A_rot_B = ZERO_ROTATION / B_rot_A&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Note how these two sets condense into the same thing when the scale is a scalar,&lt;br /&gt;
but also when A_rot_B and B_rot_A are ZERO_ROTATION. In fact, when the rotation&lt;br /&gt;
involved is of the special case of one or more rotations of 90 degrees around&lt;br /&gt;
any of the axes, so that the rotation merely swaps axes, one could define&lt;br /&gt;
the inverse of A_B_scale by applying that rotation to that vector (swapping&lt;br /&gt;
the scaling factors), next to inverting each factor individually.&lt;br /&gt;
That is a different way of how we defined B_A_scale, but it would collapse&lt;br /&gt;
the two sets into one for that special set of rotations. I&#039;m using that trick&lt;br /&gt;
in the example script below.&lt;br /&gt;
&lt;br /&gt;
=== Direction vectors ===&lt;br /&gt;
&lt;br /&gt;
A &#039;direction&#039; is a normalized vector (its length is 1), or unit vector, where only the direction&lt;br /&gt;
it points to is important.&lt;br /&gt;
&lt;br /&gt;
Of course, in the light of rotations between coordinate systems, also the directions&lt;br /&gt;
are relative to some coordinate system.&lt;br /&gt;
&lt;br /&gt;
As stated before, using some &#039;starting&#039; unit vector a rotation can be expressed&lt;br /&gt;
as a direction by applying the rotation to a starting vector. Reversing this&lt;br /&gt;
process runs into floating point round off errors however, or might even have lost&lt;br /&gt;
all information of the rotation when we rotate around the starting vector itself.&lt;br /&gt;
&lt;br /&gt;
There is a better way to convert directions (back) to a rotation however: by using &#039;&#039;two&#039;&#039;&lt;br /&gt;
directions that are perpendicular, each having a unit vector along one of the axes&lt;br /&gt;
as starting vector. That way there is always at least one vector enough rotated away&lt;br /&gt;
from the actual rotation axis in order not to suffer from (too much) information loss.&lt;br /&gt;
&lt;br /&gt;
For example, let us use the unit vector along the positive X axis and the unit vector&lt;br /&gt;
along the positive Z axis. In LSL those are often called fwd and up respectively.&lt;br /&gt;
Furthermore, lets work in a coordinate system A. Then we have the &#039;starting&#039; vectors:&lt;br /&gt;
&lt;br /&gt;
 &#039;&#039;&#039;vector A_fwd_A  = &amp;lt;1, 0, 0&amp;gt;;            (9)&#039;&#039;&#039;&lt;br /&gt;
 &#039;&#039;&#039;vector A_left_A = &amp;lt;0, 1, 0&amp;gt;;&#039;&#039;&#039;&lt;br /&gt;
 &#039;&#039;&#039;vector A_up_A   = &amp;lt;0, 0, 1&amp;gt;;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
We said we only knew the fwd and up directions, but the third can always be&lt;br /&gt;
calculated from the other two with a cross product:&lt;br /&gt;
&lt;br /&gt;
 &#039;&#039;&#039;A_fwd_B  = A_left_B % A_up_B;           (10)&#039;&#039;&#039;&lt;br /&gt;
 &#039;&#039;&#039;A_left_B = A_up_B % A_fwd_B;&#039;&#039;&#039;&lt;br /&gt;
 &#039;&#039;&#039;A_up_B   = A_fwd_B % A_left_B;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Hence, the cross product exists of the other two in the order left to right where after &#039;up&#039; you start at &#039;fwd&#039; again; they rotate: ... left up fwd left up fwd ...&lt;br /&gt;
Put a &#039;=&#039; at any space in that sequence and a &#039;%&#039; at the next space and you have the right formula. Also note that x % y = - y % x, in case you were wondering.&lt;br /&gt;
&lt;br /&gt;
Now assume we have the target directions A_*_B, then we can find the rotation between&lt;br /&gt;
A and B with:&lt;br /&gt;
&lt;br /&gt;
 &#039;&#039;&#039;A_rot_B = [[llAxes2Rot]](A_fwd_B, A_left_B, A_up_B);       (11)&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Where A_rot_B is the rotation that turns A_*_A into A_*_B:&lt;br /&gt;
&lt;br /&gt;
 A_fwd_B  = A_fwd_A  * A_rot_B&lt;br /&gt;
 A_left_B = A_left_A * A_rot_B&lt;br /&gt;
 A_up_B   = A_up_A   * A_rot_B&lt;br /&gt;
&lt;br /&gt;
=== Finding coordinate systems ===&lt;br /&gt;
&lt;br /&gt;
Assume you already have a coordinate system B (for example, region or object coordinates, the orientations of which you can find directly with [[#LSL functions]]).&lt;br /&gt;
&lt;br /&gt;
Finding coordinate system A means that you find A_rot_B (or B_rot_A which is just the inverse), and A_pos_B or B_pos_A.&lt;br /&gt;
&lt;br /&gt;
Finding the rotation is usually the easiest since it doesn&#039;t depend on where the origin is and can most likely&lt;br /&gt;
be derived somehow. For example, in many cases you will have two orthogonal direction vectors in B that you know&lt;br /&gt;
to be parallel with the x, y or z axes of A. Lets say that you have AsX_dir_B and a AsY_dir_B that make an angle&lt;br /&gt;
of 90 degrees and have a length of 1, where AsX_dir_B is known to be parallel with the X axis of A and AsY_dir_B&lt;br /&gt;
is known to be parallel with the Y axis of A. Note that in this case we can also use the notation A_fwd_B for AsX_dir_B since&lt;br /&gt;
&#039;fwd&#039; is in the X direction (AsX_dir_B means &amp;quot;A&#039;s X-axis direction in coordinates of B&amp;quot;, and A_fwd_B means &amp;quot;A&#039;s&lt;br /&gt;
forwards direction in coordinates of B&amp;quot;, so they are the same thing). Then we find:&lt;br /&gt;
&lt;br /&gt;
 A_rot_B = [[llAxes2Rot]](AsX_dir_B, AsY_dir_B, AsX_dir_B % AsY_dir_B);&lt;br /&gt;
&lt;br /&gt;
as discussed in the previous paragraph.&lt;br /&gt;
&lt;br /&gt;
Next, if you have a vector from_B_to_A pointing from the origin of B to the origin of A, then you have&lt;br /&gt;
the translation between A and B too:&lt;br /&gt;
&lt;br /&gt;
If from_B_to_A is in coordinates of A, then&lt;br /&gt;
&lt;br /&gt;
 B_pos_A = -from_B_to_A&lt;br /&gt;
&lt;br /&gt;
while if from_B_to_A is in coordinates of B, then&lt;br /&gt;
&lt;br /&gt;
 A_pos_B = from_B_to_A&lt;br /&gt;
&lt;br /&gt;
Slight counter intuitive you have to read &#039;A_pos_B&#039; as &#039;The vector pointing from the origin of B to the origin of A&#039;,&lt;br /&gt;
but plausible since it is in the coordinates of B and thus you should expect the vector to start in the origin&lt;br /&gt;
of B.&lt;br /&gt;
&lt;br /&gt;
If you have a series of vectors that are stacked, all the way from B to A, then of course you just add them all up&lt;br /&gt;
to get A_pos_B. Likewise, if you have a series of vectors in the coordinates of A that are stacked to add up&lt;br /&gt;
to go from A to B, then add them all up to get B_pos_A.&lt;br /&gt;
&lt;br /&gt;
The interesting case therefore is where you have a vector C_pos_A that points from A to C and is in the coordinates&lt;br /&gt;
of A, and a vector C_pos_B that points from B to C and is in the coordinates of B.&lt;br /&gt;
&lt;br /&gt;
To solve this puzzle, lets first write the vectors slightly different so we&#039;re not confused about&lt;br /&gt;
what they mean, even after converting between the coordinate systems A and B.&lt;br /&gt;
&lt;br /&gt;
Let AC_vec_A be C_pos_A: the vector (arrow) from the origin of A to C (in coordinates of A) and&lt;br /&gt;
let BC_vec_B be C_pos_B: the vector from the origin of B to C (in the coordinates of B).&lt;br /&gt;
Note how the notation of _vec_ is similar to that of _dir_, except that a direction vector has&lt;br /&gt;
a length of 1, and this vector has both a direction and a length: it describes how to get from&lt;br /&gt;
one point to another. Like directions, when converting them between A and B you ONLY&lt;br /&gt;
apply the rotation A_rot_B! Also note that a vector with a minus sign just means &amp;quot;in the opposite direction&amp;quot;,&lt;br /&gt;
hence CA_vec_A = -AC_vec_A.&lt;br /&gt;
&lt;br /&gt;
Thus, we find that&lt;br /&gt;
&lt;br /&gt;
 AC_vec_B = AC_vec_A * A_rot_B&lt;br /&gt;
&lt;br /&gt;
and find&lt;br /&gt;
&lt;br /&gt;
 A_pos_B = BA_vec_B = BC_vec_B + CA_vec_B = BC_vec_B - AC_vec_B = BC_vec_B - AC_vec_A * A_rot_B&lt;br /&gt;
&lt;br /&gt;
then dropping the extra notation again&lt;br /&gt;
&lt;br /&gt;
 &#039;&#039;&#039;A_pos_B = C_pos_B - C_pos_A * A_rot_B         (12)&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Which is rather logical when you read it in English as &amp;quot;To go from B to A in coordinates of B (A_pos_B),&lt;br /&gt;
you first go from B to C in coordinates of B (C_pos_B) and then in the opposite direction (the minus sign)&lt;br /&gt;
of going from A to C (namely from C to A) converted to the coordinates of B.&lt;br /&gt;
&lt;br /&gt;
And oh wonder - if we write this result a little different we find:&lt;br /&gt;
&lt;br /&gt;
 C_pos_A = (C_pos_B - A_pos_B) / A_rot_B&lt;br /&gt;
&lt;br /&gt;
which is the normal conversion (formula (3)) for the position of C from A to B coordinates!&lt;br /&gt;
&lt;br /&gt;
=== LSL functions ===&lt;br /&gt;
&lt;br /&gt;
What all of the above taught you is mainly a coding style: use prefixes and postfixes for your rotations (and translations)!&lt;br /&gt;
It&#039;s all in the &#039;&#039;&#039;&#039;&#039;names&#039;&#039;&#039;&#039;&#039; of your variables. A &#039;rotation&#039; type can be the rotation part of a transformation&lt;br /&gt;
(not tied to a particular coordinate system, but rather rotating around whatever coordinate system you apply it to),&lt;br /&gt;
it can be the representation of a unit vector, it can be the rotation part of the orientation of a prim relative to a&lt;br /&gt;
given coordinate system, or it can represent the rotation part of a coordinate system conversion.&lt;br /&gt;
If you don&#039;t use a consistent way to reflect all that in your variable names then you &#039;&#039;will&#039;&#039; get confused.&lt;br /&gt;
&lt;br /&gt;
The LSL functions mostly deal with two types: orientations (position + rotation) of prims relative to some coordinate system,&lt;br /&gt;
and simply transformations (rotation and/or translation).&lt;br /&gt;
&lt;br /&gt;
The table below shows the coordinate systems involved.&lt;br /&gt;
&lt;br /&gt;
{| rules=&amp;quot;all&amp;quot; style=&amp;quot;margin:2em 1em 2em 1em; border:none 2px #000000; background-color:#F9F9F9; font-size:120%; empty-cells:hide;&amp;quot;&lt;br /&gt;
 |-&lt;br /&gt;
 | colspan=2 |&lt;br /&gt;
 | style=&amp;quot;padding: 5px 10px 5px 10px; background-color: #ffdddd; text-align: center&amp;quot; colspan=2 | Coordinates of the prim containing the script (&#039;&#039;&#039;sc_&#039;&#039;&#039;)&lt;br /&gt;
 |- {{Hl2}}&lt;br /&gt;
 ! style=&amp;quot;padding: 5px 10px 5px 10px; color: blue; background-color: #eeeeb0&amp;quot; | Coordinate System&lt;br /&gt;
 ! style=&amp;quot;padding: 5px 10px 5px 10px; color: green; background-color: lightgray&amp;quot; | Abbreviation &lt;br /&gt;
 ! style=&amp;quot;padding: 5px 10px 5px 10px&amp;quot; | script in child prim&lt;br /&gt;
 ! style=&amp;quot;padding: 5px 10px 5px 10px&amp;quot; | script in root prim&lt;br /&gt;
 |-&lt;br /&gt;
 | style=&amp;quot;padding: 5px 10px 5px 10px; color: blue; background-color: #ffffa0&amp;quot; | World/Map Coordinates&lt;br /&gt;
 | style=&amp;quot;padding: 5px 10px 5px 10px&amp;quot;                                         | &#039;&#039;&#039;wc&#039;&#039;&#039;&lt;br /&gt;
 | style=&amp;quot;padding: 5px 10px 5px 10px&amp;quot; colspan=2                               | &amp;lt;span style=&amp;quot;font-family: mono; font-size: 90%&amp;quot;&amp;gt;sc_pos_&#039;&#039;&#039;wc&#039;&#039;&#039; = sc_pos_rc + [[llGetRegionCorner]]()&amp;lt;br&amp;gt;sc_rot_&#039;&#039;&#039;wc&#039;&#039;&#039; = sc_rot_rc&amp;lt;/span&amp;gt;&lt;br /&gt;
 |-&lt;br /&gt;
 | style=&amp;quot;padding: 5px 10px 5px 10px; color: blue; background-color: #ffffa0&amp;quot; | Region Coordinates&lt;br /&gt;
 | style=&amp;quot;padding: 5px 10px 5px 10px&amp;quot;                                         | &#039;&#039;&#039;rc&#039;&#039;&#039;&lt;br /&gt;
 | style=&amp;quot;padding: 5px 10px 5px 10px&amp;quot; colspan=2                               | &amp;lt;span style=&amp;quot;font-family: mono; font-size: 90%&amp;quot;&amp;gt;sc_pos_&#039;&#039;&#039;rc&#039;&#039;&#039; = [[llGetPos]]()&amp;lt;br&amp;gt;sc_rot_&#039;&#039;&#039;rc&#039;&#039;&#039; = [[llGetRot]]()&amp;lt;/span&amp;gt;&lt;br /&gt;
 |-&lt;br /&gt;
 | style=&amp;quot;padding: 5px 10px 5px 10px; color: blue; background-color: #ffffa0&amp;quot; | Object/Root Coordinates&lt;br /&gt;
 | style=&amp;quot;padding: 5px 10px 5px 10px&amp;quot;                                         | &#039;&#039;&#039;oc&#039;&#039;&#039;&lt;br /&gt;
 | style=&amp;quot;padding: 5px 10px 5px 10px&amp;quot;                                         | &amp;lt;span style=&amp;quot;font-family: mono; font-size: 90%&amp;quot;&amp;gt;sc_pos_&#039;&#039;&#039;oc&#039;&#039;&#039; = [[llGetLocalPos]]()&amp;lt;br&amp;gt;sc_rot_&#039;&#039;&#039;oc&#039;&#039;&#039; = [[llGetLocalRot]]()&amp;lt;/span&amp;gt;&lt;br /&gt;
 | style=&amp;quot;padding: 5px 10px 5px 10px&amp;quot;                                         | &amp;lt;span style=&amp;quot;font-family: mono; font-size: 90%&amp;quot;&amp;gt;sc_pos_&#039;&#039;&#039;oc&#039;&#039;&#039; = [[ZERO_VECTOR]]&amp;lt;br&amp;gt;sc_rot_&#039;&#039;&#039;oc&#039;&#039;&#039; = [[ZERO_ROTATION]]&amp;lt;/span&amp;gt;&lt;br /&gt;
 |-&lt;br /&gt;
 | style=&amp;quot;padding: 5px 10px 5px 10px; color: blue; background-color: #ffffa0&amp;quot; | Self Coordinates&lt;br /&gt;
 | style=&amp;quot;padding: 5px 10px 5px 10px&amp;quot;                                         | &#039;&#039;&#039;sc&#039;&#039;&#039;&lt;br /&gt;
 | style=&amp;quot;padding: 5px 10px 5px 10px&amp;quot; colspan=2                               | &amp;lt;span style=&amp;quot;font-family: mono; font-size: 90%&amp;quot;&amp;gt;sc_pos_&#039;&#039;&#039;sc&#039;&#039;&#039; = [[ZERO_VECTOR]]&amp;lt;br&amp;gt;sc_rot_&#039;&#039;&#039;sc&#039;&#039;&#039; = [[ZERO_ROTATION]]&amp;lt;/span&amp;gt;&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
Where &#039;in the root prim&#039; can be detect by testing that [[llGetLinkNumber]]() returns a value &amp;lt;= 1.&lt;br /&gt;
&lt;br /&gt;
Alternatively, you can set link = [[llGetLinkNumber]]() and use the following table which&lt;br /&gt;
shows how to obtain the coordinates of a prim with link number &#039;link&#039; from a script anywhere in the same object.&lt;br /&gt;
Note that this doesn&#039;t work when the object exist of a single prim: then [[llGetLinkNumber]]() returns 0,&lt;br /&gt;
while &#039;link&#039; must be larger than 0 here. If you need to get Object Coordinates (_oc) then do not use the&lt;br /&gt;
negative value [[LINK_THIS]]. You can use [[LINK_THIS]] for the other coordinate systems, provided&lt;br /&gt;
the object exists of at least two prims.&lt;br /&gt;
&lt;br /&gt;
{| rules=&amp;quot;all&amp;quot; style=&amp;quot;margin:2em 1em 2em 1em; border:none 2px #000000; background-color:#F9F9F9; font-size:120%; empty-cells:hide;&amp;quot;&lt;br /&gt;
 |-&lt;br /&gt;
 | colspan=2 |&lt;br /&gt;
 | style=&amp;quot;padding: 5px 10px 5px 10px; background-color: #ffdddd; text-align: center&amp;quot; colspan=2 | Coordinates of a linked prim (&#039;&#039;&#039;link_&#039;&#039;&#039;)&lt;br /&gt;
 |- {{Hl2}}&lt;br /&gt;
 ! style=&amp;quot;padding: 5px 10px 5px 10px; color: blue; background-color: #eeeeb0&amp;quot; | Coordinate System&lt;br /&gt;
 ! style=&amp;quot;padding: 5px 10px 5px 10px; color: green; background-color: lightgray&amp;quot; | Abbreviation &lt;br /&gt;
 ! style=&amp;quot;padding: 5px 10px 5px 10px&amp;quot; | link &amp;gt; 1&lt;br /&gt;
 ! style=&amp;quot;padding: 5px 10px 5px 10px&amp;quot; | link = 1&lt;br /&gt;
 |-&lt;br /&gt;
 | style=&amp;quot;padding: 5px 10px 5px 10px; color: blue; background-color: #ffffa0&amp;quot; | World/Map Coordinates&lt;br /&gt;
 | style=&amp;quot;padding: 5px 10px 5px 10px&amp;quot;                                         | &#039;&#039;&#039;wc&#039;&#039;&#039;&lt;br /&gt;
 | style=&amp;quot;padding: 5px 10px 5px 10px&amp;quot; colspan=2                               | &amp;lt;span style=&amp;quot;font-family: mono; font-size: 90%&amp;quot;&amp;gt;link_pos_&#039;&#039;&#039;wc&#039;&#039;&#039; = link_pos_rc + [[llGetRegionCorner]]()&amp;lt;br&amp;gt;link_rot_&#039;&#039;&#039;wc&#039;&#039;&#039; = link_rot_rc&amp;lt;/span&amp;gt;&lt;br /&gt;
 |-&lt;br /&gt;
 | style=&amp;quot;padding: 5px 10px 5px 10px; color: blue; background-color: #ffffa0&amp;quot; | Region Coordinates&lt;br /&gt;
 | style=&amp;quot;padding: 5px 10px 5px 10px&amp;quot;                                         | &#039;&#039;&#039;rc&#039;&#039;&#039;&lt;br /&gt;
 | style=&amp;quot;padding: 5px 10px 5px 10px&amp;quot; colspan=2                               | &amp;lt;span style=&amp;quot;font-family: mono; font-size: 90%&amp;quot;&amp;gt;link_pos_&#039;&#039;&#039;rc&#039;&#039;&#039; = [[llList2Vector]]([[llGetLinkPrimitiveParams]](&#039;&#039;&#039;link&#039;&#039;&#039;, [&amp;lt;span&amp;gt;&amp;lt;/span&amp;gt;[[PRIM_POSITION]]]), 0)&amp;lt;br&amp;gt;link_rot_&#039;&#039;&#039;rc&#039;&#039;&#039; = [[llList2Rot]]([[llGetLinkPrimitiveParams]](&#039;&#039;&#039;link&#039;&#039;&#039;, [&amp;lt;span&amp;gt;&amp;lt;/span&amp;gt;[[PRIM_ROTATION]]]), 0)&amp;lt;/span&amp;gt;&lt;br /&gt;
 |-&lt;br /&gt;
 | style=&amp;quot;padding: 5px 10px 5px 10px; color: blue; background-color: #ffffa0&amp;quot; | Object/Root Coordinates&lt;br /&gt;
 | style=&amp;quot;padding: 5px 10px 5px 10px&amp;quot;                                         | &#039;&#039;&#039;oc&#039;&#039;&#039;&lt;br /&gt;
 | style=&amp;quot;padding: 5px 10px 5px 10px&amp;quot;                                         | &amp;lt;span style=&amp;quot;font-family: mono; font-size: 90%&amp;quot;&amp;gt;link_pos_&#039;&#039;&#039;oc&#039;&#039;&#039; = [[llList2Vector]]([[llGetLinkPrimitiveParams]](&#039;&#039;&#039;link&#039;&#039;&#039;, [&amp;lt;span&amp;gt;&amp;lt;/span&amp;gt;[[PRIM_POS_LOCAL]]]), 0)&amp;lt;br&amp;gt;link_rot_&#039;&#039;&#039;oc&#039;&#039;&#039; = [[llList2Rot]]([[llGetLinkPrimitiveParams]](&#039;&#039;&#039;link&#039;&#039;&#039;, [&amp;lt;span&amp;gt;&amp;lt;/span&amp;gt;[[PRIM_ROT_LOCAL]]]), 0)&amp;lt;/span&amp;gt;&lt;br /&gt;
 | style=&amp;quot;padding: 5px 10px 5px 10px&amp;quot;                                         | &amp;lt;span style=&amp;quot;font-family: mono; font-size: 90%&amp;quot;&amp;gt;link_pos_&#039;&#039;&#039;oc&#039;&#039;&#039; = [[ZERO_VECTOR]]&amp;lt;br&amp;gt;link_rot_&#039;&#039;&#039;oc&#039;&#039;&#039; = [[ZERO_ROTATION]]&amp;lt;/span&amp;gt;&lt;br /&gt;
 |-&lt;br /&gt;
 | style=&amp;quot;padding: 5px 10px 5px 10px; color: blue; background-color: #ffffa0&amp;quot; | Self Coordinates&lt;br /&gt;
 | style=&amp;quot;padding: 5px 10px 5px 10px&amp;quot;                                         | &#039;&#039;&#039;sc&#039;&#039;&#039;&lt;br /&gt;
 | style=&amp;quot;padding: 5px 10px 5px 10px&amp;quot; colspan=2                               | &amp;lt;span style=&amp;quot;font-family: mono; font-size: 90%&amp;quot;&amp;gt;link_pos_&#039;&#039;&#039;sc&#039;&#039;&#039; = (link_pos_oc - sc_pos_oc) / sc_rot_oc&amp;lt;br&amp;gt;link_rot_&#039;&#039;&#039;sc&#039;&#039;&#039; = link_rot_oc / sc_rot_oc&amp;lt;/span&amp;gt;&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
While the above table works for link = [[LINK_ROOT]], it is probably more convenient to use the following table:&lt;br /&gt;
&lt;br /&gt;
{| rules=&amp;quot;all&amp;quot; style=&amp;quot;margin:2em 1em 2em 1em; border:none 2px #000000; background-color:#F9F9F9; font-size:120%; empty-cells:hide;&amp;quot;&lt;br /&gt;
 |-&lt;br /&gt;
 | colspan=2 |&lt;br /&gt;
 | style=&amp;quot;padding: 5px 10px 5px 10px; background-color: #ffdddd; text-align: center&amp;quot; colspan=2 | Coordinates of the root prim (&#039;&#039;&#039;oc_&#039;&#039;&#039;)&lt;br /&gt;
 |- {{Hl2}}&lt;br /&gt;
 ! style=&amp;quot;padding: 5px 10px 5px 10px; color: blue; background-color: #eeeeb0&amp;quot; | Coordinate System&lt;br /&gt;
 ! style=&amp;quot;padding: 5px 10px 5px 10px; color: green; background-color: lightgray&amp;quot; | Abbreviation &lt;br /&gt;
 ! style=&amp;quot;padding: 5px 10px 5px 10px&amp;quot; | script in any prim&lt;br /&gt;
 |-&lt;br /&gt;
 | style=&amp;quot;padding: 5px 10px 5px 10px; color: blue; background-color: #ffffa0&amp;quot; | World/Map Coordinates&lt;br /&gt;
 | style=&amp;quot;padding: 5px 10px 5px 10px&amp;quot;                                         | &#039;&#039;&#039;wc&#039;&#039;&#039;&lt;br /&gt;
 | style=&amp;quot;padding: 5px 10px 5px 10px&amp;quot;                                         | &amp;lt;span style=&amp;quot;font-family: mono; font-size: 90%&amp;quot;&amp;gt;oc_pos_&#039;&#039;&#039;wc&#039;&#039;&#039; = oc_pos_rc + [[llGetRegionCorner]]()&amp;lt;br&amp;gt;oc_rot_&#039;&#039;&#039;wc&#039;&#039;&#039; = oc_rot_rc&amp;lt;/span&amp;gt;&lt;br /&gt;
 |-&lt;br /&gt;
 | style=&amp;quot;padding: 5px 10px 5px 10px; color: blue; background-color: #ffffa0&amp;quot; | Region Coordinates&lt;br /&gt;
 | style=&amp;quot;padding: 5px 10px 5px 10px&amp;quot;                                         | &#039;&#039;&#039;rc&#039;&#039;&#039;&lt;br /&gt;
 | style=&amp;quot;padding: 5px 10px 5px 10px&amp;quot;                                         | &amp;lt;span style=&amp;quot;font-family: mono; font-size: 90%&amp;quot;&amp;gt;oc_pos_&#039;&#039;&#039;rc&#039;&#039;&#039; = [[llGetRootPosition]]()&amp;lt;br&amp;gt;oc_rot_&#039;&#039;&#039;rc&#039;&#039;&#039; = [[llGetRootRotation]]()&amp;lt;/span&amp;gt;&lt;br /&gt;
 |-&lt;br /&gt;
 | style=&amp;quot;padding: 5px 10px 5px 10px; color: blue; background-color: #ffffa0&amp;quot; | Object/Root Coordinates&lt;br /&gt;
 | style=&amp;quot;padding: 5px 10px 5px 10px&amp;quot;                                         | &#039;&#039;&#039;oc&#039;&#039;&#039;&lt;br /&gt;
 | style=&amp;quot;padding: 5px 10px 5px 10px&amp;quot;                                         | &amp;lt;span style=&amp;quot;font-family: mono; font-size: 90%&amp;quot;&amp;gt;oc_pos_&#039;&#039;&#039;oc&#039;&#039;&#039; = [[ZERO_VECTOR]]&amp;lt;br&amp;gt;oc_rot_&#039;&#039;&#039;oc&#039;&#039;&#039; = [[ZERO_ROTATION]]&amp;lt;/span&amp;gt;&lt;br /&gt;
 |-&lt;br /&gt;
 | style=&amp;quot;padding: 5px 10px 5px 10px; color: blue; background-color: #ffffa0&amp;quot; | Self Coordinates&lt;br /&gt;
 | style=&amp;quot;padding: 5px 10px 5px 10px&amp;quot;                                         | &#039;&#039;&#039;sc&#039;&#039;&#039;&lt;br /&gt;
 | style=&amp;quot;padding: 5px 10px 5px 10px&amp;quot;                                         | &amp;lt;span style=&amp;quot;font-family: mono; font-size: 90%&amp;quot;&amp;gt;oc_pos_&#039;&#039;&#039;sc&#039;&#039;&#039; = - sc_pos_oc / sc_rot_oc&amp;lt;br&amp;gt;oc_rot_&#039;&#039;&#039;sc&#039;&#039;&#039; = [[ZERO_ROTATION]] / sc_rot_oc&amp;lt;/span&amp;gt;&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
As shows from the above table, LSL does not directly support &#039;&#039;&#039;_sc&#039;&#039;&#039; coordinates,&lt;br /&gt;
and I used conversions to fill in the tables. All in all, we listed four coordinate systems (wc, rc, oc and sc; not including the &#039;link_&#039; stuff,&lt;br /&gt;
which isn&#039;t really a separate coordinate system)&lt;br /&gt;
and thus could write out four times four is sixteen ways to convert one into the other. Four of those would be trivial, and of the remaining&lt;br /&gt;
twelve we can express six as the inverse of the other six.&lt;br /&gt;
&lt;br /&gt;
However, lets ignore the World Coordinates for now, which are just the same as the Region Coordinates with an offset for the position.&lt;br /&gt;
Then we have three coordinate systems (rc, oc and sc), leading to nine conversion, three of which are trivial, and of the remaining&lt;br /&gt;
six three can be expressed as the inverse of the other three. Those three are: oc_*_rc, sc_*_rc and sc_*_oc, which are all listed above.&lt;br /&gt;
The trivial ones, rc_*_rc, oc_*_oc and sc_*_sc, are all ZERO_* (the latter two also are listed in the tables above).&lt;br /&gt;
Finally, the inverse values, rc_*_oc, rc_*_sc and oc_*_sc can be expressed with the inversion formula given in [[#Converting between coordinate systems]].&lt;br /&gt;
So this is really all there is.&lt;br /&gt;
&lt;br /&gt;
=== The fourth dimension ===&lt;br /&gt;
&lt;br /&gt;
Picture a coordinate system as three perpendicular lines, like an object in-world perhaps existing of&lt;br /&gt;
three really long prims in the colors red, green and blue. You can toss them into the region&lt;br /&gt;
where they randomly bounce around like dice &amp;amp;ndash; a whole bunch of them!&lt;br /&gt;
And then you freeze time - make a snapshot.&lt;br /&gt;
&lt;br /&gt;
With the knowledge so far you can now express the position and rotation of an object or prim relative&lt;br /&gt;
to any of those coordinate systems &amp;amp;ndash; and convert between them at will.&lt;br /&gt;
Apply rotations and translations relative to any chosen system.&lt;br /&gt;
All of the coordinate systems are virtually the same! But in practice this isn&#039;t the case, why is that?&lt;br /&gt;
&lt;br /&gt;
The reason is that in practice coordinate systems change in time, in a way that you cannot predict.&lt;br /&gt;
It&#039;s like they are still tumbling and bouncing around and you have no idea where they are.&lt;br /&gt;
&lt;br /&gt;
This noise comes mainly from one thing: objects are being moved. Taken into repositories and rezzed back,&lt;br /&gt;
rotated and possibly even scaled! In fact, not just objects, but also prims inside objects can be changed&lt;br /&gt;
at will at any moment and a good script must take that into account.&lt;br /&gt;
&lt;br /&gt;
The art of programming therefore becomes &#039;&#039;design&#039;&#039;. You must choose which coordinate systems you&lt;br /&gt;
want to use; what your global variables store, relative to which coordinate system.&lt;br /&gt;
&lt;br /&gt;
Unfortunately, a script can &#039;&#039;not&#039;&#039; detect when this might have happened and only perform extra computations&lt;br /&gt;
or re-computation, of otherwise constant variables, when a prim or object has actually been changed.&lt;br /&gt;
There is an LSL event [[moving_start]] but that only works half on SL and not at all on opensim.&lt;br /&gt;
For rotation detection there is nothing.&lt;br /&gt;
&lt;br /&gt;
As such, it is necessary to call the LSL functions listed in the tables above every time you&lt;br /&gt;
want to do anything that depends on them; which hopefully won&#039;t be too often.&lt;br /&gt;
&lt;br /&gt;
The following example script can be put in the root prim of an object of any number of cubes&lt;br /&gt;
and allows one to sit on each cube, using [[llLinkSitTarget]], even when you move or rotate&lt;br /&gt;
child prims.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lsl2&amp;quot;&amp;gt;&lt;br /&gt;
// A script written to show how to use coordinate systems in LSL.&lt;br /&gt;
//&lt;br /&gt;
// Copyright(c) Timmy Songbird @DreamNation&lt;br /&gt;
//              Timmy Foxclaw  @SL,&lt;br /&gt;
//              2014&lt;br /&gt;
//&lt;br /&gt;
// This program is free software; you can redistribute it and/or modify&lt;br /&gt;
// it under the terms of the GNU General Public License as published by&lt;br /&gt;
// the Free Software Foundation; either version 2 of the License, or&lt;br /&gt;
// (at your option) any later version.&lt;br /&gt;
//&lt;br /&gt;
// This program is distributed in the hope that it will be useful,&lt;br /&gt;
// but WITHOUT ANY WARRANTY; without even the implied warranty of&lt;br /&gt;
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the&lt;br /&gt;
// GNU General Public License for more details.&lt;br /&gt;
//&lt;br /&gt;
// You should have received a copy of the GNU General Public License&lt;br /&gt;
// along with this program; if not, write to the Free Software&lt;br /&gt;
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307, USA.&#039;)&lt;br /&gt;
&lt;br /&gt;
//----------------------------------------------------------------------------&lt;br /&gt;
//#line &amp;quot;/opt/secondlife/scripts/scripts/tests/llLinkSitTarget_Test.m4s:5&amp;quot;&lt;br /&gt;
// GitLocation: tests/llLinkSitTarget_Test.m4s&lt;br /&gt;
// GitID: 32c3ab5a6f17d96eafe4e110bb91a700e2fd589b&lt;br /&gt;
&lt;br /&gt;
// This script uses the follow coordinate systems:&lt;br /&gt;
//&lt;br /&gt;
// rc     : Region Coordinates.&lt;br /&gt;
// oc     : Object, or root prim, Coordinates.&lt;br /&gt;
// link   : Coordinates of prim with link number &#039;link&#039;.&lt;br /&gt;
// STc    : Coordinates of the touched face (see llDetectedTouchST)&lt;br /&gt;
//          (x and y in the ranger [0, 1] with (0, 0) in the bottom-left corner).&lt;br /&gt;
// center : Coordinates of the touched face with the origin in the center,&lt;br /&gt;
//          the orientation is the same as STc (z is the normal of the surface),&lt;br /&gt;
//          but scaled to be in meters.&lt;br /&gt;
// ac     : Avatar center Coordinates. This is really the same as stc, but&lt;br /&gt;
//          moved up an offset. Rotations passed to llLinkSitTarget are&lt;br /&gt;
//          relative to this coordinate system.&lt;br /&gt;
&lt;br /&gt;
//----------------------------------------------------------------------------&lt;br /&gt;
//#line &amp;quot;/opt/secondlife/scripts/scripts/tests/llLinkSitTarget_Test.m4s:24&amp;quot;&lt;br /&gt;
// The sit position of the sit target.&lt;br /&gt;
// This value is *different* in SL and opensim, and even changed since opensim version 0.7.6.&lt;br /&gt;
// The currently measured values for the z component are:&lt;br /&gt;
// SL: 0.05, opensim 0.7.6: 0.0, opensim 0.8.x: -agentSize.z / 37.9075&lt;br /&gt;
&lt;br /&gt;
// Use this in SL:&lt;br /&gt;
//vector sittarget_pos_ac = &amp;lt;0.0, 0.0, 0.05&amp;gt;;&lt;br /&gt;
//integer opensimver = 0; // SL&lt;br /&gt;
&lt;br /&gt;
// Use this on opensim:&lt;br /&gt;
vector sittarget_pos_ac = &amp;lt;0.0, 0.0, 0.0&amp;gt;;&lt;br /&gt;
//integer opensimver = 7; // Opensim 0.7.6&lt;br /&gt;
integer opensimver = 8; // Opensim &amp;gt;= 0.8&lt;br /&gt;
&lt;br /&gt;
//----------------------------------------------------------------------------&lt;br /&gt;
//#line &amp;quot;/opt/secondlife/scripts/scripts/tests/llLinkSitTarget_Test.m4s:40&amp;quot;&lt;br /&gt;
// face_link() returns a list of vectors in link coordinates.&lt;br /&gt;
//&lt;br /&gt;
// Returns: [bottomLeft_link, topRight_link].&lt;br /&gt;
//&lt;br /&gt;
// bottomLeft_link is the bottom left corner of the given face,&lt;br /&gt;
// that is - the corner where (S, T) = (0, 0).&lt;br /&gt;
// topRight_link is the top right corner of the given face,&lt;br /&gt;
// that is - the corner where (S, T) = (1, 1).&lt;br /&gt;
list face_link(integer link, integer face)&lt;br /&gt;
{&lt;br /&gt;
  list params = llGetLinkPrimitiveParams(link, [PRIM_TYPE, PRIM_SIZE]);&lt;br /&gt;
  vector bottomLeft_link;&lt;br /&gt;
  vector topRight_link;&lt;br /&gt;
  integer prim_type = llList2Integer(params, 0);&lt;br /&gt;
  if (prim_type == PRIM_TYPE_BOX)&lt;br /&gt;
  {&lt;br /&gt;
    topRight_link = llList2Vector(params, 7) * 0.5;&lt;br /&gt;
    if (face == 0)&lt;br /&gt;
    {&lt;br /&gt;
      bottomLeft_link = -topRight_link;&lt;br /&gt;
      bottomLeft_link.z = topRight_link.z;&lt;br /&gt;
    }&lt;br /&gt;
    else if (face == 1)&lt;br /&gt;
    {&lt;br /&gt;
      bottomLeft_link = -topRight_link;&lt;br /&gt;
      topRight_link.y = bottomLeft_link.y;&lt;br /&gt;
    }&lt;br /&gt;
    else if (face == 2)&lt;br /&gt;
    {&lt;br /&gt;
      bottomLeft_link = -topRight_link;&lt;br /&gt;
      bottomLeft_link.x = topRight_link.x;&lt;br /&gt;
    }&lt;br /&gt;
    else if (face == 3)&lt;br /&gt;
    {&lt;br /&gt;
      topRight_link.x = -topRight_link.x;&lt;br /&gt;
      bottomLeft_link = -topRight_link;&lt;br /&gt;
      bottomLeft_link.y = topRight_link.y;&lt;br /&gt;
    }&lt;br /&gt;
    else if (face == 4)&lt;br /&gt;
    {&lt;br /&gt;
      topRight_link.y = -topRight_link.y;&lt;br /&gt;
      bottomLeft_link = -topRight_link;&lt;br /&gt;
      topRight_link.x = bottomLeft_link.x;&lt;br /&gt;
    }&lt;br /&gt;
    else if (face == 5)&lt;br /&gt;
    {&lt;br /&gt;
      topRight_link.y = -topRight_link.y;&lt;br /&gt;
      topRight_link.z = -topRight_link.z;&lt;br /&gt;
      bottomLeft_link = -topRight_link;&lt;br /&gt;
      bottomLeft_link.z = topRight_link.z;&lt;br /&gt;
    }&lt;br /&gt;
    else&lt;br /&gt;
    {&lt;br /&gt;
      llWhisper(0, &amp;quot;This script only supports sitting on boxes without cuts or holes.&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
  else&lt;br /&gt;
  {&lt;br /&gt;
    llWhisper(0, &amp;quot;This script does not work for non-box prims.&amp;quot;);&lt;br /&gt;
  }&lt;br /&gt;
  return [bottomLeft_link, topRight_link];&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
//----------------------------------------------------------------------------&lt;br /&gt;
//#line &amp;quot;/opt/secondlife/scripts/scripts/tests/llLinkSitTarget_Test.m4s:104&amp;quot;&lt;br /&gt;
default&lt;br /&gt;
{&lt;br /&gt;
  touch_start(integer num)&lt;br /&gt;
  {&lt;br /&gt;
    integer n;&lt;br /&gt;
    // Run over everyone that might have touch a prim (it could be more than one!)&lt;br /&gt;
    for (n = 0; n &amp;lt; num; ++n)&lt;br /&gt;
    {&lt;br /&gt;
      // Get the link number of the touch prim.&lt;br /&gt;
      integer link = llDetectedLinkNumber(n);&lt;br /&gt;
&lt;br /&gt;
      // Some conversion variables we need, copied directly from the table above.&lt;br /&gt;
      vector   link_pos_rc = llList2Vector(llGetLinkPrimitiveParams(link, [PRIM_POSITION]), 0);&lt;br /&gt;
      rotation link_rot_rc = llList2Rot(llGetLinkPrimitiveParams(link, [PRIM_ROTATION]), 0);&lt;br /&gt;
&lt;br /&gt;
      // Get the face of the prim that was touched.&lt;br /&gt;
      integer face = llDetectedTouchFace(n);&lt;br /&gt;
      if (face == TOUCH_INVALID_FACE)&lt;br /&gt;
      {&lt;br /&gt;
        llInstantMessage(llDetectedKey(n), &amp;quot;Sorry, your viewer does not support touched faces.&amp;quot;);&lt;br /&gt;
      }&lt;br /&gt;
      else&lt;br /&gt;
      {&lt;br /&gt;
        // llDetectedTouchPos returns the position where an object was touched in Region Coordinates.&lt;br /&gt;
        vector touch_pos_rc = llDetectedTouchPos(n);&lt;br /&gt;
        // Convert that into link coordinates.&lt;br /&gt;
        vector touch_pos_link = (touch_pos_rc - link_pos_rc) / link_rot_rc;&lt;br /&gt;
&lt;br /&gt;
        // llDetectedTouchBinormal returns a normalized, directional vector in Region Coordinates.&lt;br /&gt;
        // So, it&#039;s not a position; it is a direction (dir), really representing a rotation.&lt;br /&gt;
        vector binormal_dir_rc = llDetectedTouchBinormal(n);&lt;br /&gt;
&lt;br /&gt;
        // In general a direction vector can not be converted to a rotation (when the&lt;br /&gt;
        // starting reference vector is (almost) the same as the direction vector, which&lt;br /&gt;
        // might be the case here since we have no idea where the vector is pointing to).&lt;br /&gt;
        // Therefore we just leave it as a vector, but we treat it the same as a rotation:&lt;br /&gt;
        // leave the origin alone and just correct the rotation when converting to the&lt;br /&gt;
        // local coordinate system of the link prim.&lt;br /&gt;
        vector binormal_dir_link = binormal_dir_rc / link_rot_rc; // binormal_dir_rc * rc_rot_link&lt;br /&gt;
&lt;br /&gt;
        // llDetectedTouchNormal returns a normalized, directional vector in Region Coordinates.&lt;br /&gt;
        // It is perpendicular to the surface (pointing outwards) and makes an angle of 90 degrees&lt;br /&gt;
        // with binormal_dir. Here we immediately convert it to _link coordinates.&lt;br /&gt;
        vector normal_dir_link = llDetectedTouchNormal(n) / link_rot_rc;&lt;br /&gt;
&lt;br /&gt;
        // Calculate the tangent vector.&lt;br /&gt;
        vector tangent_dir_link = binormal_dir_link % normal_dir_link;&lt;br /&gt;
&lt;br /&gt;
        // Get the [bottomLeft_link, topRight_link] positions of the surface &#039;face&#039;, in link coordinates.&lt;br /&gt;
        list surface_link = face_link(link, face);&lt;br /&gt;
        vector bottomLeft_pos_link = llList2Vector(surface_link, 0);&lt;br /&gt;
        vector topRight_pos_link = llList2Vector(surface_link, 1);&lt;br /&gt;
&lt;br /&gt;
        // Calculate the center of the surface.&lt;br /&gt;
        vector center_pos_link = (bottomLeft_pos_link + topRight_pos_link) * 0.5;&lt;br /&gt;
&lt;br /&gt;
        // The unit x vector in link coordinates is obviously &amp;lt;1, 0, 0&amp;gt;, center_rot_link is&lt;br /&gt;
        // therefore the rotation that is needed to rotate that to tangent_dir_link, which&lt;br /&gt;
        // represents &amp;lt;1, 0, 0&amp;gt; in center coordinates (the positive S direction).&lt;br /&gt;
        // The positive T direction, or &amp;lt;0, 1, 0&amp;gt; in center coordinates, is the binormal vector.&lt;br /&gt;
        // llAxes2Rot(fwd, left, up) returns the rotation needed to rotate &amp;lt;1, 0, 0&amp;gt; to fwd,&lt;br /&gt;
        // and &amp;lt;0, 1, 0&amp;gt; to left (and thus &amp;lt;0, 0, 1&amp;gt; to up).&lt;br /&gt;
        rotation center_rot_link = llAxes2Rot(tangent_dir_link, binormal_dir_link, normal_dir_link);&lt;br /&gt;
&lt;br /&gt;
        // llDetectedTouchST returns a vector in the plane of the touched surface,&lt;br /&gt;
        // with x and y ranging from 0,0 in the &amp;quot;bottom left&amp;quot; corner till 1,1 for&lt;br /&gt;
        // opposite corner. The value is thus in ST Coordinates.&lt;br /&gt;
        vector touch_pos_STc = llDetectedTouchST(n);&lt;br /&gt;
&lt;br /&gt;
        // Caluclate the size of the surface and rotate it in the plane of the center coordinates.&lt;br /&gt;
        vector center_link_scale = (topRight_pos_link - bottomLeft_pos_link) / center_rot_link;&lt;br /&gt;
&lt;br /&gt;
        // Convert touch_pos to center coordinates.&lt;br /&gt;
        vector touch_pos_center = &amp;lt;(touch_pos_STc.x - 0.5) * center_link_scale.x, (touch_pos_STc.y - 0.5) * center_link_scale.y, 0.0&amp;gt;;&lt;br /&gt;
&lt;br /&gt;
        // Calculate a unit vector from the touch position to the edge.&lt;br /&gt;
        vector edge_dir_center;&lt;br /&gt;
        // Find the nearest edge.&lt;br /&gt;
        vector edge_pos_center = touch_pos_center;&lt;br /&gt;
        if (center_link_scale.x * 0.5 - llFabs(edge_pos_center.x) &amp;gt; center_link_scale.y * 0.5 - llFabs(edge_pos_center.y))&lt;br /&gt;
        {&lt;br /&gt;
          integer positive = llRound(touch_pos_STc.y);&lt;br /&gt;
          edge_pos_center.y = (positive - 0.5) * center_link_scale.y;&lt;br /&gt;
          edge_dir_center = &amp;lt;0, positive * 2 - 1, 0&amp;gt;;&lt;br /&gt;
        }&lt;br /&gt;
        else&lt;br /&gt;
        {&lt;br /&gt;
          integer positive = llRound(touch_pos_STc.x);&lt;br /&gt;
          edge_pos_center.x = (positive - 0.5) * center_link_scale.x;&lt;br /&gt;
          edge_dir_center = &amp;lt;positive * 2 - 1, 0, 0&amp;gt;;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        // Convert edge_dir_center to link coordinates (because llLinkSitTarget takes link coordinates).&lt;br /&gt;
        vector edge_dir_link = edge_dir_center * center_rot_link;&lt;br /&gt;
&lt;br /&gt;
        // Calculate the rotation of the seated avatar from this direction, using the fact that we still have normal_dir_link.&lt;br /&gt;
        // This puts the fwd direction of the avatar in the direction edge_dir (from touch point to nearest edge)&lt;br /&gt;
        // and the up direction of the avatar perpendicular to the touched surface.&lt;br /&gt;
        rotation ac_rot_link = llAxes2Rot(edge_dir_link, normal_dir_link % edge_dir_link, normal_dir_link);&lt;br /&gt;
&lt;br /&gt;
        // Where do we want to sit?&lt;br /&gt;
        // Currently lets just sit where the user clicked, without limits or corrections.&lt;br /&gt;
        vector sit_pos_center = touch_pos_center;&lt;br /&gt;
&lt;br /&gt;
        // Convert the sit position to link coordinates (because llLinkSitTarget takes link coordinates).&lt;br /&gt;
        vector sit_pos_link = sit_pos_center * center_rot_link + center_pos_link;&lt;br /&gt;
&lt;br /&gt;
        // This vector is really a function of avatar shape and what looks&lt;br /&gt;
        // aesthetically pleasing. However, it is only minimal a function&lt;br /&gt;
        // avatar height (the only thing we can roughly know from a script)&lt;br /&gt;
        // and much more a function of shape values that we can&#039;t know.&lt;br /&gt;
        // So for now, just leave this as a constant.&lt;br /&gt;
        //&lt;br /&gt;
        // In ascii art, a sitting avatar looks more or less like this:&lt;br /&gt;
        //                ^&lt;br /&gt;
        //                |z&lt;br /&gt;
        //            ac_ |&lt;br /&gt;
        //               \S           &#039;S&#039; is the sittarget_pos_ac, in SL it is 0.05m above(_ac) &#039;O&#039;.&lt;br /&gt;
        //         &amp;lt;--x---O   ()      &#039;O&#039; is the Origin of ac (Avatar center (attach point) Coordinates).&lt;br /&gt;
        //                |   /|      &#039;*&#039; is the sittarget (as passed to llSitTarget) and is 0.4m below(_link) S.&lt;br /&gt;
        //    sittarget--&amp;gt;*__/_/&lt;br /&gt;
        //               _/   ^__ sit_pos_ac, 0.62 below(_ac) &#039;O&#039;, and 0.34 backwards(_ac).&lt;br /&gt;
        //                |&lt;br /&gt;
        vector sit_pos_ac = &amp;lt;-0.34, 0.0, -0.62&amp;gt;;&lt;br /&gt;
&lt;br /&gt;
        // Correct grid dependent sittarget_pos_ac.&lt;br /&gt;
        if (opensimver == 7)&lt;br /&gt;
        {&lt;br /&gt;
          sittarget_pos_ac.z = 0.0;&lt;br /&gt;
        }&lt;br /&gt;
        else if (opensimver == 8)&lt;br /&gt;
        {&lt;br /&gt;
          vector agentSize = llGetAgentSize(llDetectedKey(n));&lt;br /&gt;
          sittarget_pos_ac.z = agentSize.z / -37.9075; // Constant determined on &amp;quot;OpenSim 0.8.0 Dev&amp;quot;, April 2014.&lt;br /&gt;
          llSay(0, &amp;quot;sittarget_pos_ac = &amp;quot; + (string)sittarget_pos_ac);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        // Find the translation of the ac coordinate system.&lt;br /&gt;
        vector ac_pos_link = sit_pos_link - sit_pos_ac * ac_rot_link;&lt;br /&gt;
&lt;br /&gt;
        // Convert the sittarget from ac coordinates to link coordinates.&lt;br /&gt;
        vector sittarget_pos_link = sittarget_pos_ac * ac_rot_link + ac_pos_link;&lt;br /&gt;
&lt;br /&gt;
        // Grid dependent vertical offset.&lt;br /&gt;
        //&lt;br /&gt;
        // This is a historical offset introduced by Linden Lab from the beginning.&lt;br /&gt;
        // It is actually a mistake because when the avatar is rotated this causes&lt;br /&gt;
        // the avatar to move sideways! Apparently also Philips Linden found rotations&lt;br /&gt;
        // hard to understand.&lt;br /&gt;
        if (opensimver == 7)&lt;br /&gt;
        {&lt;br /&gt;
          // opensim version 0.7.6&lt;br /&gt;
          // Obviously, this should have been the same as on SL.&lt;br /&gt;
          // Later it got &amp;quot;corrected&amp;quot;, but in a wrong way (sittarget_pos_ac still differs with SL).&lt;br /&gt;
          sittarget_pos_link.z -= 0.418;&lt;br /&gt;
        }&lt;br /&gt;
        else&lt;br /&gt;
        {&lt;br /&gt;
          // SL and opensim &amp;gt;= 0.8.&lt;br /&gt;
          sittarget_pos_link.z -= 0.4;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        // Set the sit target.&lt;br /&gt;
        llLinkSitTarget(link, sittarget_pos_link, ac_rot_link);&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;/div&gt;</summary>
		<author><name>Timmy Foxclaw</name></author>
	</entry>
	<entry>
		<id>https://wiki.secondlife.com/w/index.php?title=Talk:LlSitTarget&amp;diff=1189605</id>
		<title>Talk:LlSitTarget</title>
		<link rel="alternate" type="text/html" href="https://wiki.secondlife.com/w/index.php?title=Talk:LlSitTarget&amp;diff=1189605"/>
		<updated>2014-04-20T13:30:37Z</updated>

		<summary type="html">&lt;p&gt;Timmy Foxclaw: /* GetSitTarget */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Unsitting on wrong side or camera rotation ==&lt;br /&gt;
&lt;br /&gt;
Hi, i am getting frustrated with this. I create a board and set the sit target with&lt;br /&gt;
&amp;lt;code&amp;gt;llSitTarget(&amp;lt;0.4, 0.0, 0.0&amp;gt;, ZERO_ROTATION);&amp;lt;/code&amp;gt;&lt;br /&gt;
and an animation which for &amp;quot;standing&amp;quot;. So while the person technical sits, she stands in front of the board. &lt;br /&gt;
But I have a problem with that: If the board stand freely, the person unsits right through it towards the other side. I can put the board with the back  facing a large wall. In the case the unsitting is correctly in front of it. But on sit down the camera rotates, so that it is behind the avatar again; on the other side of the wall.&lt;br /&gt;
&lt;br /&gt;
If anyone has an idea how to fix, please tell me (even if it is just an idea where to look for more information). --[[User:Maike Short|Maike Short]] 12:41, 24 February 2008 (PST)&lt;br /&gt;
&lt;br /&gt;
:You could position the camera with the {{LSLGC|Camera}} functions.  -- [[User:Strife Onizuka|Strife Onizuka]] 04:46, 25 February 2008 (PST)&lt;br /&gt;
&lt;br /&gt;
==GetSitTarget==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;lsl&amp;gt;&lt;br /&gt;
list GetSitTarget(integer prim, key av)&lt;br /&gt;
{//WARNING: llGetObjectDetails can introduce an error that goes as far as the 5th decimal place.&lt;br /&gt;
    vector tp = llGetAgentSize(av);&lt;br /&gt;
    if(tp)&lt;br /&gt;
    {&lt;br /&gt;
        if(prim == LINK_THIS)//llGetLinkKey doesn&#039;t like LINK_THIS&lt;br /&gt;
            prim = llGetLinkNumber();&lt;br /&gt;
    &lt;br /&gt;
        list details = OBJECT_POS + (list)OBJECT_ROT;&lt;br /&gt;
        rotation f = llList2Rot(details = (llGetObjectDetails(llGetLinkKey(prim), details) + llGetObjectDetails(av, details)), 1);&lt;br /&gt;
    &lt;br /&gt;
        return [(llRot2Up(f = (llList2Rot(details, 3) / f)) * tp.z * 0.02638) +&lt;br /&gt;
                ((llList2Vector(details, 2) - llList2Vector(details, 0)) / f) - &amp;lt;0.0, 0.0, 0.4&amp;gt;, f];&lt;br /&gt;
    }&lt;br /&gt;
    return [];&lt;br /&gt;
}//Written by Strife Onizuka&lt;br /&gt;
&amp;lt;/lsl&amp;gt;&lt;br /&gt;
Hi Strife! This version of your GetSitTarget, and the other version on the actual LlSitTarget page, both always return &amp;lt;0.000000, 0.000000, 0.707107, 0.707107&amp;gt; for the rotation. --[[User:MartinRJ Fayray|MartinRJ Fayray]] 07:52, 21 January 2013 (PST)&lt;br /&gt;
&lt;br /&gt;
:I haven&#039;t touched this in 5 years but I don&#039;t see a reason why it should be doing what you say. Are you sure you are using it properly? The prim parameter specifies what prim the location will be local to. The function was written to aid in determining sit targets when making furniture. You have the avatar sit on one object and then you get it&#039;s position local to the furniture so you can program in the sit target.&lt;br /&gt;
&lt;br /&gt;
:Just to clarify, you are saying that when you sit on an object with the following script in it, you don&#039;t get approximately the specified value? -- &#039;&#039;&#039;[[User:Strife_Onizuka|Strife]]&#039;&#039;&#039; &amp;lt;sup&amp;gt;&amp;lt;small&amp;gt;([[User talk:Strife_Onizuka|talk]]|[[Special:Contributions/Strife_Onizuka|contribs]])&amp;lt;/small&amp;gt;&amp;lt;/sup&amp;gt; 20:37, 22 January 2013 (PST)&lt;br /&gt;
&lt;br /&gt;
:It seems to work now. No idea what I was doing wrong. Thank you strife!--[[User:MartinRJ Fayray|MartinRJ Fayray]] 07:36, 3 February 2013 (PST)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;lsl&amp;gt;&lt;br /&gt;
vector vOffset = &amp;lt;0,0,1&amp;gt;;&lt;br /&gt;
rotation rOffset = &amp;lt;0,0,0,1&amp;gt;;&lt;br /&gt;
&lt;br /&gt;
list GetSitTarget(integer prim, key av)&lt;br /&gt;
{//WARNING: llGetObjectDetails can introduce an error that goes as far as the 5th decimal place!&lt;br /&gt;
 //This is highly unlikely to be ever noticed unless compounded over time.&lt;br /&gt;
 //Do not use while moving (like in a moving vehicle)!!!&lt;br /&gt;
    vector tp = llGetAgentSize(av);&lt;br /&gt;
    if(tp)&lt;br /&gt;
    {&lt;br /&gt;
        if(prim == LINK_THIS)//llGetLinkKey doesn&#039;t like LINK_THIS&lt;br /&gt;
            prim = llGetLinkNumber();&lt;br /&gt;
 &lt;br /&gt;
        list details = [OBJECT_POS, OBJECT_ROT];&lt;br /&gt;
        rotation f = llList2Rot(details = (llGetObjectDetails(llGetLinkKey(prim), details) + llGetObjectDetails(av, details)), 1);&lt;br /&gt;
        rotation r = llList2Rot(details, 3) / f;&lt;br /&gt;
 &lt;br /&gt;
        return [((llList2Vector(details, 2) - llList2Vector(details, 0)) / f) + (llRot2Up(r) * tp.z * 0.02638) - &amp;lt;0.0, 0.0, 0.4&amp;gt;, r];&lt;br /&gt;
    }&lt;br /&gt;
    return [];&lt;br /&gt;
}//Written by Strife Onizuka&lt;br /&gt;
&lt;br /&gt;
default{&lt;br /&gt;
    state_entry(){&lt;br /&gt;
        llSitTarget(vOffset, rOffset);&lt;br /&gt;
    }&lt;br /&gt;
    changed(integer change){&lt;br /&gt;
        key id = llAvatarOnSitTarget();&lt;br /&gt;
        if(id)&lt;br /&gt;
            llOwnerSay(&amp;quot;[&amp;quot;+llList2CSV([vOffset, rOffset]) +&amp;quot;] ~ [&amp;quot; + llList2CSV(GetSitTarget(LINK_THIS, id))+&amp;quot;]&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/lsl&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Note&#039;&#039;&#039;: the above two scripts in this paragraph are incorrect. Most notably, the position of an avatar (it&#039;s Avatar Center) is NOT dependent on the AgentSize of the seated avatar. I added another script that returns the sit target, below. [[User:Timmy Foxclaw|Timmy Foxclaw]] 10:31, 7 April 2014 (PDT)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;lsl&amp;gt;&lt;br /&gt;
// A script to develop and test sbGetLinkSitTarget&lt;br /&gt;
//&lt;br /&gt;
// Copyright(c) Timmy Songbird @DreamNation&lt;br /&gt;
//              Timmy Foxclaw  @SL,&lt;br /&gt;
//              2014&lt;br /&gt;
//&lt;br /&gt;
// This program is free software; you can redistribute it and/or modify&lt;br /&gt;
// it under the terms of the GNU General Public License as published by&lt;br /&gt;
// the Free Software Foundation; either version 2 of the License, or&lt;br /&gt;
// (at your option) any later version.&lt;br /&gt;
//&lt;br /&gt;
// This program is distributed in the hope that it will be useful,&lt;br /&gt;
// but WITHOUT ANY WARRANTY; without even the implied warranty of&lt;br /&gt;
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the&lt;br /&gt;
// GNU General Public License for more details.&lt;br /&gt;
//&lt;br /&gt;
// You should have received a copy of the GNU General Public License&lt;br /&gt;
// along with this program; if not, write to the Free Software&lt;br /&gt;
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307, USA.&#039;)&lt;br /&gt;
&lt;br /&gt;
//----------------------------------------------------------------------------&lt;br /&gt;
//#line &amp;quot;/opt/secondlife/scripts/scripts/tests/sbGetLinkSitTarget_Test.m4s:4&amp;quot;&lt;br /&gt;
// This script sets a &amp;quot;random&amp;quot;-ish sit target on every prim in an object.&lt;br /&gt;
// Recommended for your test is an object existing of two default cubes&lt;br /&gt;
// with arbitrary rotations and position. Put this script only in the&lt;br /&gt;
// root prim.&lt;br /&gt;
//&lt;br /&gt;
// The script sets the sit targets on compile or touch. Please touch&lt;br /&gt;
// the object after editting one of the prims.&lt;br /&gt;
//&lt;br /&gt;
// When an avatar (un)sits on one of the prims, the script prints for every&lt;br /&gt;
// sit target that has a seated avatar the return value of sbGetLinkSitTarget.&lt;br /&gt;
// This value should be (almost) equal to the values passed to llSitTarget.&lt;br /&gt;
&lt;br /&gt;
// Example output:&lt;br /&gt;
&lt;br /&gt;
// Object: [&amp;lt;0.200000, 0.300000, 0.500000&amp;gt;, &amp;lt;0.100000, 0.150000, 0.120000, 0.976268&amp;gt;] set with llSitTarget on 2 prims.&lt;br /&gt;
// Object: [&amp;lt;0.199999, 0.300001, 0.499999&amp;gt;, &amp;lt;0.100000, 0.150000, 0.120000, 0.976268&amp;gt;] returned by sbGetLinkSitTarget(1).&lt;br /&gt;
// Object: [&amp;lt;0.199998, 0.300002, 0.499998&amp;gt;, &amp;lt;0.100000, 0.150000, 0.120000, 0.976268&amp;gt;] returned by sbGetLinkSitTarget(2).&lt;br /&gt;
&lt;br /&gt;
// GitLocation: tests/sbGetLinkSitTarget_Test.m4s&lt;br /&gt;
&lt;br /&gt;
//----------------------------------------------------------------------------&lt;br /&gt;
//#line &amp;quot;/opt/secondlife/scripts/scripts/tests/sbGetLinkSitTarget_Test.m4s:26&amp;quot;&lt;br /&gt;
vector sitTarget_pos_link = &amp;lt;0.2, 0.3, 0.5&amp;gt;;&lt;br /&gt;
rotation sitTarget_rot_link = &amp;lt;0.1, 0.15, 0.12, 0.9762684&amp;gt;;&lt;br /&gt;
&lt;br /&gt;
//----------------------------------------------------------------------------&lt;br /&gt;
//#line &amp;quot;/opt/secondlife/scripts/scripts/tests/sbGetLinkSitTarget_Test.m4s:31&amp;quot;&lt;br /&gt;
// Returns the correct values to use for llSitTarget to make&lt;br /&gt;
// the currently seated avatar sit in the same way when re-seated.&lt;br /&gt;
// If no avatar is currently sitting then [ZERO_VECTOR, ZERO_ROTATION] is returned.&lt;br /&gt;
//&lt;br /&gt;
// [1] http://wiki.secondlife.com/wiki/User:Timmy_Foxclaw/About_Coordinate_Systems_and_Rotations#LSL_functions&lt;br /&gt;
// [2] http://wiki.secondlife.com/wiki/User:Timmy_Foxclaw/About_Coordinate_Systems_and_Rotations#Converting_between_coordinate_systems&lt;br /&gt;
list sbGetLinkSitTarget(integer link)&lt;br /&gt;
{&lt;br /&gt;
  // Calling llAvatarOnLinkSitTarget(0) always returns NULL_KEY because the link&lt;br /&gt;
  // number of an unlinked prim changes from 0 to 1 as soon as an avatar sits on&lt;br /&gt;
  // it. So if 0 was passed then they probably meant 1.&lt;br /&gt;
  if (link == 0)&lt;br /&gt;
  {&lt;br /&gt;
    link = 1;&lt;br /&gt;
  }&lt;br /&gt;
  key av = llAvatarOnLinkSitTarget(link);&lt;br /&gt;
  if (av != NULL_KEY)&lt;br /&gt;
  {&lt;br /&gt;
    // Get link_pos_oc and link_rot_oc. See table 2 in [1].&lt;br /&gt;
    vector link_pos_oc = ZERO_VECTOR;&lt;br /&gt;
    rotation link_rot_oc = ZERO_ROTATION;&lt;br /&gt;
    if (link &amp;gt; 1)&lt;br /&gt;
    {&lt;br /&gt;
      list params = llGetLinkPrimitiveParams(link, [PRIM_POS_LOCAL, PRIM_ROT_LOCAL]);&lt;br /&gt;
      link_pos_oc = llList2Vector(params, 0);&lt;br /&gt;
      link_rot_oc = llList2Rot(params, 1);&lt;br /&gt;
    }&lt;br /&gt;
    // Find the link number of the seated avatar.&lt;br /&gt;
    integer avNum = llGetNumberOfPrims();&lt;br /&gt;
    do&lt;br /&gt;
    {&lt;br /&gt;
        if (av == llGetLinkKey(avNum))&lt;br /&gt;
        {&lt;br /&gt;
            // Get ac_pos_oc and ac_rot_oc (ac stands for Avatar Center), exactly the same as above&lt;br /&gt;
            // except that we don&#039;t need to test if avNum &amp;gt; 1, because it always will be.&lt;br /&gt;
            list params = llGetLinkPrimitiveParams(avNum, [PRIM_POS_LOCAL, PRIM_ROT_LOCAL]);&lt;br /&gt;
            vector ac_pos_oc = llList2Vector(params, 0);&lt;br /&gt;
            rotation ac_rot_oc = llList2Rot(params, 1);&lt;br /&gt;
&lt;br /&gt;
            // Convert that to link coordinates. See formula (3) in [2].&lt;br /&gt;
            vector ac_pos_link = (ac_pos_oc - link_pos_oc) / link_rot_oc;&lt;br /&gt;
            rotation ac_rot_link = ac_rot_oc / link_rot_oc;&lt;br /&gt;
&lt;br /&gt;
            // Now we have this little vector in the Avatar Center coordinates.&lt;br /&gt;
            vector sit_pos_ac = &amp;lt;0.0, 0.0, 0.05&amp;gt;;&lt;br /&gt;
&lt;br /&gt;
            // Convert that to link coordinates. See formula (1) in [2].&lt;br /&gt;
            vector sit_pos_link = sit_pos_ac * ac_rot_link + ac_pos_link;&lt;br /&gt;
&lt;br /&gt;
            // Return the values, accounting for the sit target bug of 0.4m.&lt;br /&gt;
            return [sit_pos_link - &amp;lt;0.0, 0.0, 0.4&amp;gt;, ac_rot_link];&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    while (--avNum);&lt;br /&gt;
  }&lt;br /&gt;
  return [ZERO_VECTOR, ZERO_ROTATION];&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
setSitTargets()&lt;br /&gt;
{&lt;br /&gt;
  // Set the same sit target on every prim.&lt;br /&gt;
  integer n = llGetNumberOfPrims();&lt;br /&gt;
  llSay(0, &amp;quot;[&amp;quot; +  llList2CSV([sitTarget_pos_link, sitTarget_rot_link]) + &amp;quot;] set with llSitTarget on &amp;quot; + (string)n + &amp;quot; prims.&amp;quot;);&lt;br /&gt;
  do&lt;br /&gt;
  {&lt;br /&gt;
    llLinkSitTarget(n, sitTarget_pos_link, sitTarget_rot_link);&lt;br /&gt;
  }&lt;br /&gt;
  while(--n);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
//----------------------------------------------------------------------------&lt;br /&gt;
//#line &amp;quot;/opt/secondlife/scripts/scripts/tests/sbGetLinkSitTarget_Test.m4s:105&amp;quot;&lt;br /&gt;
default&lt;br /&gt;
{&lt;br /&gt;
  state_entry()&lt;br /&gt;
  {&lt;br /&gt;
    setSitTargets();&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  touch_start(integer n)&lt;br /&gt;
  {&lt;br /&gt;
    setSitTargets();&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  changed(integer change)&lt;br /&gt;
  {&lt;br /&gt;
    if ((change &amp;amp; CHANGED_LINK))&lt;br /&gt;
    {&lt;br /&gt;
      integer n = llGetNumberOfPrims();&lt;br /&gt;
      do&lt;br /&gt;
      {&lt;br /&gt;
        key av = llAvatarOnLinkSitTarget(n);&lt;br /&gt;
        if (av != NULL_KEY)&lt;br /&gt;
        {&lt;br /&gt;
          llSay(0, &amp;quot;[&amp;quot; + llList2CSV(sbGetLinkSitTarget(n)) + &amp;quot;] returned by sbGetLinkSitTarget(&amp;quot; + (string)n + &amp;quot;).&amp;quot;);&lt;br /&gt;
        }&lt;br /&gt;
      }&lt;br /&gt;
      while(--n);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/lsl&amp;gt;&lt;br /&gt;
:Yes the above two scripts are older versions. The 0.05 offset has been tried before. {{User|Talarus Luan}} [https://wiki.secondlife.com/w/index.php?title=LlSitTarget&amp;amp;diff=1179695&amp;amp;oldid=1179694 could not get it to work]. {{User|Talarus Luan}} went on to work out a quadratic equation that provided a more accurate result. See [[#UpdateSitTarget_changes.3F|#UpdateSitTarget changes?]] below. -- &#039;&#039;&#039;[[User:Strife_Onizuka|Strife]]&#039;&#039;&#039; &amp;lt;sup&amp;gt;&amp;lt;small&amp;gt;([[User talk:Strife_Onizuka|talk]]|[[Special:Contributions/Strife_Onizuka|contribs]])&amp;lt;/small&amp;gt;&amp;lt;/sup&amp;gt; 12:38, 7 April 2014 (PDT)&lt;br /&gt;
&lt;br /&gt;
::Hi Strife. There must be some miscommunication - we seem to be talking about different things. After extensive research (see [[ User:Timmy_Foxclaw/About_Coordinate_Systems_and_Rotations|this link]], especially the script at the end), I have found that the value is exactly 0.05 and not depend on the height of the avatar in SecondLife. The function sbGetLinkSitTarget as defined in the script above returns the exact values (within the normal floating point round off error of 0.000002 or so), no matter what position and rotation you passed to llSitTarget. Perhaps we can meet in some sandbox in SL? I&#039;d like to understand where your quadratic expression exactly comes in. Maybe you can show me the test object and the tests that you did to determine it. [[User:Timmy Foxclaw|Timmy Foxclaw]] 15:41, 7 April 2014 (PDT)&lt;br /&gt;
&lt;br /&gt;
:::I&#039;d love to meet you inworld but my current schedule precludes that for about the next month (it has sucked, I missed my own 10 year birthday). Beyond inserting the changes proposed by others I haven&#039;t done any of the work on this myself, I code mostly for the fun of it and do testing in LSLEditor. I have been watching your ACSaR article evolve, I&#039;ve been thinking it might be worth bringing into the main namespace. I don&#039;t know how LL did such a wonderful job of screwing sittargets up. -- &#039;&#039;&#039;[[User:Strife_Onizuka|Strife]]&#039;&#039;&#039; &amp;lt;sup&amp;gt;&amp;lt;small&amp;gt;([[User talk:Strife_Onizuka|talk]]|[[Special:Contributions/Strife_Onizuka|contribs]])&amp;lt;/small&amp;gt;&amp;lt;/sup&amp;gt; 19:18, 7 April 2014 (PDT)&lt;br /&gt;
&lt;br /&gt;
::::Hey Timmy.  I&#039;m guessing that the quadratic equation to wihch Strife is referring is the one at the end of the [[#UpdateSitTarget_changes.3F|#UpdateSitTarget changes?]] section below, where {{User|Talarus Luan}} arrives at the quadratic equation&lt;br /&gt;
&lt;br /&gt;
 offset = 0.008906 * z^3 - 0.049831 * z^2 + 0.088967 * z&lt;br /&gt;
&lt;br /&gt;
::::where z is avatar height.  If I plug z = 1.16 and z = 2.45 into this equation, I get the values 0.050050466 and 0.049831322 respectively.  The difference between these two values is just 0.000219144, so it&#039;s all very close to 0.05.  However, I&#039;d love to know the exact calculation in order to get this right in the next release of OpenSimulator.  On a very unscientific eyeballing, they both seem more accurate than the z * 0.02638 calculation in the script (which has a value range of 0.0306008 to 0.064631) but between these two it&#039;s much harder to tell.  How do you perform your measurements? -- [[User:Fenn Meredith|Fenn Meredith]] 16:26, 18 April 2014 (PDT)&lt;br /&gt;
&lt;br /&gt;
:::::Hi Fenn, I gave you a test object in SL. It prints out the values. A little drawing would make things a lot more clear but well, that&#039;s a bit hard :p. The idea is that if you pass some vector to llSitTarget then you have to add 0.4 to it&#039;s Z value to arrive at the same point as the vector in the Avatar center Coordinate system (AC) that points along the Z-axis of that coordinate system (lets call that point S). Hence if you apply no rotation then S is 0.4m above the sittarget, and the AC is 0.05m below that, hence 0.35m above the set sittarget. If you apply a rotation of 180 degrees, they will add up and AC ends up at 0.45m above the set sittarget. While, if you use a rotation of 90 degrees then AC ends up 0.4m above the set sittarget, but 0.05m to the left (or right) of it. The latter is thus the easiest way to distinguish them with a single sit. Here is a script that does that:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;lsl&amp;gt;vector sit_pos_link = &amp;lt;0.0, 0.0, 1.0&amp;gt;;&lt;br /&gt;
rotation ac_rot_link;&lt;br /&gt;
&lt;br /&gt;
default&lt;br /&gt;
{&lt;br /&gt;
  state_entry()&lt;br /&gt;
  {&lt;br /&gt;
    vector rot = &amp;lt;90.0, 0.0, 0&amp;gt;;&lt;br /&gt;
    ac_rot_link = llEuler2Rot(rot * DEG_TO_RAD);&lt;br /&gt;
    llSitTarget(sit_pos_link, ac_rot_link);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  changed(integer change)&lt;br /&gt;
  {&lt;br /&gt;
    if ((change &amp;amp; CHANGED_LINK))&lt;br /&gt;
    {&lt;br /&gt;
      key av = llAvatarOnSitTarget();&lt;br /&gt;
      if (av != NULL_KEY)&lt;br /&gt;
      {&lt;br /&gt;
        llRequestPermissions(av, PERMISSION_TRIGGER_ANIMATION);&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  run_time_permissions(integer perm)&lt;br /&gt;
  {&lt;br /&gt;
    if ((perm &amp;amp; PERMISSION_TRIGGER_ANIMATION))&lt;br /&gt;
    {&lt;br /&gt;
      key user = llAvatarOnSitTarget();&lt;br /&gt;
      if (user)&lt;br /&gt;
      {&lt;br /&gt;
        integer linkNum = llGetNumberOfPrims();&lt;br /&gt;
        do&lt;br /&gt;
        {&lt;br /&gt;
          if (user == llGetLinkKey(linkNum))&lt;br /&gt;
          {&lt;br /&gt;
            list params = llGetLinkPrimitiveParams(linkNum, [PRIM_POS_LOCAL, PRIM_SIZE]);&lt;br /&gt;
            vector ac_pos_link = llList2Vector(params, 0);&lt;br /&gt;
            vector offsets = ac_pos_link - sit_pos_link;&lt;br /&gt;
            vector agentSize = llList2Vector(params, 1);&lt;br /&gt;
            float z = agentSize.z;&lt;br /&gt;
            llSay(0, &amp;quot;The agentSize.z is &amp;quot; + (string)z + &amp;quot; --&amp;gt;\n0.008906 * z^3 - 0.049831 * z^2 + 0.088967 * z = &amp;quot; + (string)(((0.008906 * z - 0.049831) * z + 0.088967) * z));&lt;br /&gt;
            llSay(0, &amp;quot;The actual offsets are:\n&amp;quot; + (string)offsets.z + &amp;quot; and &amp;quot; + (string)offsets.y + &amp;quot; (+/- 0.000002)&amp;quot;);&lt;br /&gt;
            jump end;&lt;br /&gt;
          }&lt;br /&gt;
        }&lt;br /&gt;
        while (--linkNum);&lt;br /&gt;
      }&lt;br /&gt;
      @end;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/lsl&amp;gt;&lt;br /&gt;
&lt;br /&gt;
:::::You can use this script also in opensim to see what it gives there. In 0.8-dev you might also want to print offsets.y / z (which will give -0.02638). [[User:Timmy Foxclaw|Timmy Foxclaw]] 06:25, 20 April 2014 (PDT)&lt;br /&gt;
&lt;br /&gt;
==Using llSetLinkPrimitiveParams for skydiving: why limited to 5m in a linked set?==&lt;br /&gt;
llSetLinkPrimitiveParams can be used as a handy tool to adjust an avatar&#039;s position and rotation.&lt;br /&gt;
This works perfectly when the object consists of 1 prim, with a range for setting the avatar position away to 500m easily!&lt;br /&gt;
When there are more prims linked, this offset seems to be limited to 5m (measured with llVecDist). This is an awfull sideeffect!&lt;br /&gt;
&lt;br /&gt;
Put this next script inside a prim and sit on the prim, it will bring you to 1000.0 higher then the prim.&lt;br /&gt;
Next link this prim to another prim and try again. You will notice you are limited to 5m. My Question: why is this limited?&lt;br /&gt;
&amp;lt;lsl&amp;gt;&lt;br /&gt;
// by Randur Source&lt;br /&gt;
&lt;br /&gt;
integer heightcnt = 0;&lt;br /&gt;
list heights = [0.0, 1.0, 5.0, 6.0, 10.0, 100.0, 300.0, 500.0, 800.0, 1000.0];&lt;br /&gt;
&lt;br /&gt;
default&lt;br /&gt;
{&lt;br /&gt;
    state_entry()&lt;br /&gt;
    {&lt;br /&gt;
        llSitTarget(ZERO_VECTOR,ZERO_ROTATION); // Clear the current sittarget for a clear test&lt;br /&gt;
        llSetRot(ZERO_ROTATION); // set the prim to no rotation, for simple z axis movement&lt;br /&gt;
    }&lt;br /&gt;
    &lt;br /&gt;
    changed(integer change)&lt;br /&gt;
    {&lt;br /&gt;
        if (change &amp;amp; CHANGED_LINK) // detect linked prims and avatars&lt;br /&gt;
        {&lt;br /&gt;
            integer primnum = llGetNumberOfPrims(); // the avatar is the last linked prim&lt;br /&gt;
            if (primnum &amp;lt;= 1) // stop if there is only 1 prim&lt;br /&gt;
                return;&lt;br /&gt;
        &lt;br /&gt;
            key avatar = llGetLinkKey(primnum);&lt;br /&gt;
            if (llGetAgentSize(avatar) == ZERO_VECTOR) // stop if this is not an avatar&lt;br /&gt;
                return;&lt;br /&gt;
                &lt;br /&gt;
            // loop through the list of test heights:&lt;br /&gt;
            for (heightcnt = 0; heightcnt &amp;lt; llGetListLength(heights); heightcnt++)&lt;br /&gt;
            {&lt;br /&gt;
                float height = llList2Float(heights,heightcnt);&lt;br /&gt;
                llSetLinkPrimitiveParams(primnum,[PRIM_POSITION,&amp;lt;0.0,0.0,height&amp;gt;]); // set this to the wanted height using a vector z axis&lt;br /&gt;
                &lt;br /&gt;
                vector avatarpos = llList2Vector(llGetObjectDetails(avatar,[OBJECT_POS]),0); // detect the avatar position within the sim&lt;br /&gt;
                float distance = llVecDist(llGetPos(),avatarpos);&lt;br /&gt;
                llOwnerSay(&amp;quot;Attempt to move &amp;quot; + llKey2Name(llGetLinkKey(primnum)) +&lt;br /&gt;
                           &amp;quot; to &amp;quot; + (string)height + &amp;quot;m high resulting to &amp;quot; + (string)distance + &amp;quot;m&amp;quot;);&lt;br /&gt;
                &lt;br /&gt;
                llSleep(1.0);&lt;br /&gt;
            }&lt;br /&gt;
            llUnSit(avatar);&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/lsl&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Posted by Sylvio Runo : Answer &#039;&#039;&#039; :&lt;br /&gt;
The correct limit is 54 meters.&lt;br /&gt;
You can&#039;t move a linked object more than 54 meters away from the axis of the root prim.&lt;br /&gt;
On SecondLife (other grids like OsGrid, may works diferent) when an agent sit on prim, the agent is attached to it, so the agent is a linked prim of the link set.&lt;br /&gt;
&lt;br /&gt;
More information about link rules, you will find here : http://wiki.secondlife.com/wiki/Linkability_Rules [http://wiki.secondlife.com/wiki/Linkability_Rules]&lt;br /&gt;
&lt;br /&gt;
==UpdateSitTarget changes?==&lt;br /&gt;
I recently worked on a project where I used a version of this function, and it appears that it is a little off. A couple of things I noted: the Z-offset of the sit target is 0.35, not 0.4, and the avatar size doesn&#039;t seem to affect this position at all. When I used this function verbatim, I noticed discrepancies between the actual sit target and the set position call. When I changed the script as noted, I got a perfect match. Has the handling of the sit target been changed since this was written? [[User:Talarus Luan|Talarus Luan]] 22:57, 1 July 2009 (UTC)&lt;br /&gt;
:Seconded. I wish I&#039;d looked at this discussion before spending an hour on trying to figure out how the code actually behaved. -- [[User:Tonya Souther|Tonya Souther]] 15:11, 19 August 2009 (UTC)&lt;br /&gt;
&lt;br /&gt;
::This is news to me but I haven&#039;t been in world in ages :( -- &#039;&#039;&#039;[[User:Strife_Onizuka|Strife]]&#039;&#039;&#039; &amp;lt;sup&amp;gt;&amp;lt;small&amp;gt;([[User talk:Strife_Onizuka|talk]]|[[Special:Contributions/Strife_Onizuka|contribs]])&amp;lt;/small&amp;gt;&amp;lt;/sup&amp;gt; 22:56, 20 August 2009 (UTC)&lt;br /&gt;
&lt;br /&gt;
:::From some quick testing in 1.40, this seems to be how the &amp;quot;true&amp;quot; offset is computed:&lt;br /&gt;
:::1. Start with offset as provided by LSL.&lt;br /&gt;
:::2. Add &amp;lt; 0.0 , 0.0 , 0.4 &amp;gt;&lt;br /&gt;
:::3. Subtract llRot2Up( rot ) * 0.05&lt;br /&gt;
:::[[User:Gregory Maurer|--Gregory Maurer]] 20:00, 28 August 2010 (UTC)&lt;br /&gt;
&lt;br /&gt;
::::Confirmed. The following appears to work fine:&lt;br /&gt;
&amp;lt;lsl&amp;gt;llSetLinkPrimitiveParams(linkNum, [PRIM_POS_LOCAL, pos + &amp;lt;0.0, 0.0, 0.4&amp;gt; - (llRot2Up(rot) * 0.05), PRIM_ROT_LOCAL, rot]);&amp;lt;/lsl&amp;gt;&lt;br /&gt;
::::This of course using the new &amp;lt;code&amp;gt;PRIM_POS_LOCAL&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;PRIM_ROT_LOCAL&amp;lt;/code&amp;gt; values for simplicity. If one or two others can confirm that the above code works correctly, then I can splice it into the example.&amp;lt;br/&amp;gt;-- &#039;&#039;&#039;[[User:Haravikk_Mistral|Haravikk]]&#039;&#039;&#039; &amp;lt;sup&amp;gt;&amp;lt;small&amp;gt;([[User_talk:Haravikk_Mistral|talk]]|[[Special:Contributions/Haravikk_Mistral|contribs]])&amp;lt;/small&amp;gt;&amp;lt;/sup&amp;gt; 14:16, 26 December 2011 (PST)&lt;br /&gt;
&lt;br /&gt;
:::::Be sure to test it with avatars of different shapes, and shoe configurations. I recall that being an issue. {{User|Escort DeFarge}} would know about this best. -- &#039;&#039;&#039;[[User:Strife_Onizuka|Strife]]&#039;&#039;&#039; &amp;lt;sup&amp;gt;&amp;lt;small&amp;gt;([[User talk:Strife_Onizuka|talk]]|[[Special:Contributions/Strife_Onizuka|contribs]])&amp;lt;/small&amp;gt;&amp;lt;/sup&amp;gt; 22:05, 26 December 2011 (PST)&lt;br /&gt;
&lt;br /&gt;
::::::I tried with my two main avatar appearances, one average human height and one closer to 8 feet tall, and it didn&#039;t seem to make a difference. The test I used was a simple object with sit-target set, and a menu allowing it to be repositioned, causing the sit-target to move and if an avatar is seated on it, they will be repositioned using &amp;lt;code&amp;gt;llSetLinkPrimitiveParams()&amp;lt;/code&amp;gt; as done above. In my case the position of the avatar was consistent both when sitting on the object (using the sit-target) and being repositioned. Avatar height appears to have no effect, as the sit-target seems to define the avatar&#039;s hip-location, which is seemingly the avatar&#039;s &amp;quot;centre&amp;quot; when seated. I&#039;ll try to run some more tests when I get a chance, as it&#039;s possible this behaviour may not hold true if the object doesn&#039;t have a sit-target on it. The height of the avatar does however have a marked visual impact, depending exactly what you&#039;re trying to line up where, but that&#039;s a general issue with sitting on objects.&amp;lt;br/&amp;gt;-- &#039;&#039;&#039;[[User:Haravikk_Mistral|Haravikk]]&#039;&#039;&#039; &amp;lt;sup&amp;gt;&amp;lt;small&amp;gt;([[User_talk:Haravikk_Mistral|talk]]|[[Special:Contributions/Haravikk_Mistral|contribs]])&amp;lt;/small&amp;gt;&amp;lt;/sup&amp;gt; 05:38, 28 December 2011 (PST)&lt;br /&gt;
:::::::Sorry for my long delay in responding. Due to various RL issues and SL/LL burnout, I took a year off from SL to pursue other activities. That said, it seems to work fine to me, Haravikk; however, I have not done exhaustive testing with tons of different avs, shoes, etc. I would consider going ahead and changing it, because the version as it is right now is not correct for the majority of avatars, regardless. If Escort DeFarge or someone else wants to amend it later to include edge cases, that&#039;s great, but a better base accuracy is more important at this point. In fact, I think I will go ahead and edit it in, since it has been so long anyway.[[User:Talarus Luan|Talarus Luan]] 12:12, 5 July 2013 (PDT)&lt;br /&gt;
:::::::Holding up on the edit, further testing is revealing that if the script is in a prim other than the root, it is off by varying amounts depending on the rotation.[[User:Talarus Luan|Talarus Luan]] 12:39, 5 July 2013 (PDT)&lt;br /&gt;
:::::::OK, I think I found the error. Still need to keep the local position/rotation values for the child prim the script is in, like so:&lt;br /&gt;
&amp;lt;lsl&amp;gt;llSetLinkPrimitiveParams(linkNum, PRIM_POS_LOCAL, (pos + &amp;lt;0.0, 0.0, 0.4&amp;gt; - (llRot2Up(rot) * 0.05)) * localrot + localpos, PRIM_ROT_LOCAL, rot * localrot]);&amp;lt;/lsl&amp;gt;&lt;br /&gt;
:::::::I&#039;ll hold off on the edit until I can get another verify that this code is good.[[User:Talarus Luan|Talarus Luan]] 12:51, 5 July 2013 (PDT)&lt;br /&gt;
:::::::OK. I think I have analyzed this to death today and have come to the conclusion that Strife&#039;s original code is largely correct, but the error I am seeing comes from the &amp;quot;magic constants&amp;quot; 0.4 and 0.02638. Haravikk&#039;s code is simply a reduced form of Strife&#039;s code. The 0.4 magic constant is still there, but Haravikk is using just a close, but fixed, magic constant of 0.05 instead of Strife&#039;s (size.z * 0.02638), which comes out very close to 0.5 for most normal human avs. Thus, I am concluding that the inaccuracy is in the &amp;quot;magic constants&amp;quot; themselves, and I am going to hold off on the edit until I can get some more information on the source of these constants and see if there are better, more accurate values. It is annoying that, in all these years, we still haven&#039;t gotten LL to just tell us what the damn difference is between avatar sit targets and local position offsets in a linkset. It can&#039;t be that hard for someone who is familiar with the code to look at it and document it. -.- [[User:Talarus Luan|Talarus Luan]] 13:24, 5 July 2013 (PDT)&lt;br /&gt;
&lt;br /&gt;
::::::::Welcome back! I&#039;d like to take credit for that but that&#039;s the part that Escort contributed. As to where 0.02638 comes from, I vaguely recall it came from Escort&#039;s testing. I was driven more by &amp;quot;wouldn&#039;t it be cool to write a function that...&amp;quot; than anything else. I do agree the values have always been not quite right. -- &#039;&#039;&#039;[[User:Strife_Onizuka|Strife]]&#039;&#039;&#039; &amp;lt;sup&amp;gt;&amp;lt;small&amp;gt;([[User talk:Strife_Onizuka|talk]]|[[Special:Contributions/Strife_Onizuka|contribs]])&amp;lt;/small&amp;gt;&amp;lt;/sup&amp;gt; 23:10, 5 July 2013 (PDT)&lt;br /&gt;
:::::::::Thanks! OK, I did a bunch of empirical testing, sampling a bunch of avatars from 1.16m to 2.45m in height, as reported by llGetAgentSize. I picked the lowest and highest and one about standard height, and fitted a parabolic curve through them. I have reduced the inaccuracies to a great degree, but it still isn&#039;t 100% perfect for all sizes in that range, just the ones that I used to solve the curve equation. The rest show a *tiny* bit of movement, but they are very close. Obviously, the difference isn&#039;t parabolic, probably just some kind of discrete step function, but it works.[[User:Talarus Luan|Talarus Luan]] 11:16, 14 July 2013 (PDT)&lt;br /&gt;
&amp;lt;lsl&amp;gt;vector vCoefficients = &amp;lt;0.008906,-0.049831,0.088967&amp;gt;;&lt;br /&gt;
float fAdjust = vCoefficients.x * size.z * size.z + vCoefficients.y * size.z + vCoefficients.z;&lt;br /&gt;
llSetLinkPrimitiveParamsFast(linkNum,&lt;br /&gt;
    [PRIM_POS_LOCAL, (pos + &amp;lt;0.0, 0.0, 0.4&amp;gt; - (llRot2Up(rot) * size.z * fAdjust)) * localrot + localpos,&lt;br /&gt;
     PRIM_ROT_LOCAL, rot * localrot]);&amp;lt;/lsl&amp;gt;&lt;br /&gt;
&lt;br /&gt;
::::::::::I see you mind reading abilities haven&#039;t diminished (I contemplated suggesting the tests you have done, decided to go to bed instead). Any reason not to use parentheses? It looks like something that could get optimized to an a series of FMAs (by the VM). -- &#039;&#039;&#039;[[User:Strife_Onizuka|Strife]]&#039;&#039;&#039; &amp;lt;sup&amp;gt;&amp;lt;small&amp;gt;([[User talk:Strife_Onizuka|talk]]|[[Special:Contributions/Strife_Onizuka|contribs]])&amp;lt;/small&amp;gt;&amp;lt;/sup&amp;gt; 21:33, 14 July 2013 (PDT)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;lsl&amp;gt;vector vCoefficients = &amp;lt;0.008906,-0.049831,0.088967&amp;gt;;&lt;br /&gt;
float fAdjust = ((((vCoefficients.x * size.z) + vCoefficients.y) * size.z) + vCoefficients.z) * size.z;&lt;br /&gt;
llSetLinkPrimitiveParamsFast(linkNum,&lt;br /&gt;
    [PRIM_POS_LOCAL, (pos + &amp;lt;0.0, 0.0, 0.4&amp;gt; - (llRot2Up(rot) * fAdjust)) * localrot + localpos,&lt;br /&gt;
     PRIM_ROT_LOCAL, rot * localrot]);&amp;lt;/lsl&amp;gt;&lt;br /&gt;
:::::::::::Yeah, I thought about optimizing it a bit after I posted it, but decided to leave it unoptimized here so the path from the current function to this change was clear, for demonstrability purposes. Besides, I had to leave some room for it to be Strifed&amp;amp;trade;. :P [[User:Talarus Luan|Talarus Luan]] 15:17, 17 July 2013 (PDT)&lt;br /&gt;
&lt;br /&gt;
::::::::::::I appreciate the gesture :p and I&#039;m not as bad as I use to be. I&#039;m not going to optimize out fAdjust, it&#039;s more readable this way. This is more for myself later as my memory is crap, the reasoning behind using llRot2Up is that it solves the pesky problem of the quaternion not having a magnitude of one. While the following isn&#039;t optimal, it is cool. -- &#039;&#039;&#039;[[User:Strife_Onizuka|Strife]]&#039;&#039;&#039; &amp;lt;sup&amp;gt;&amp;lt;small&amp;gt;([[User talk:Strife_Onizuka|talk]]|[[Special:Contributions/Strife_Onizuka|contribs]])&amp;lt;/small&amp;gt;&amp;lt;/sup&amp;gt; 00:00, 18 July 2013 (PDT)&lt;br /&gt;
&amp;lt;lsl&amp;gt;&lt;br /&gt;
size.x = (size.z * (size.y = (size.z * size.z)));&lt;br /&gt;
float fAdjust = vCoefficients * size;&lt;br /&gt;
&amp;lt;/lsl&amp;gt;&lt;br /&gt;
:::::::::::::Yeah, that is a nice way to represent it, for those used to the LSL representation for vector dot product. I&#039;m a little less enthused about the size vector assignment chain, but that&#039;s just my general dislike for C value assignments and such. In my mind, I separate assignments from expressions, so seeing them mixed together causes a bit of a train wreck in my brain&#039;s lexical analyzer. :P[[User:Talarus Luan|Talarus Luan]] 10:00, 21 July 2013 (PDT)&lt;br /&gt;
&lt;br /&gt;
::::::::::::::I don&#039;t think anyone uses the LSL vector dot product. It took me three days to remember it existed and then I look up the syntax just to make sure I wasn&#039;t crazy (yes yes, I agree it&#039;s insane to think that looking up the syntax of an obscure feature is proof against insanity but I&#039;m sticking to it, my cat agrees). I think a train wreck was my goal. -- &#039;&#039;&#039;[[User:Strife_Onizuka|Strife]]&#039;&#039;&#039; &amp;lt;sup&amp;gt;&amp;lt;small&amp;gt;([[User talk:Strife_Onizuka|talk]]|[[Special:Contributions/Strife_Onizuka|contribs]])&amp;lt;/small&amp;gt;&amp;lt;/sup&amp;gt; 11:13, 21 July 2013 (PDT)&lt;br /&gt;
&lt;br /&gt;
== Avatars Floating After Sit ==&lt;br /&gt;
&lt;br /&gt;
The position of avatars will sometimes change, generally noticeable as a rise on the Z axis of perhaps half a meter - common triggers for this is typing or another AV sitting on the same object - though these are not exhaustive.  Does anyone have a clue why this happens, and how to prevent it from happening? [[User:TaraLi Jie|TaraLi Jie]] 21:14, 11 March 2012 (PDT)&lt;br /&gt;
&lt;br /&gt;
:Hmm, there are a few possible causes, but the main cause are the animations involved, so it&#039;s worth remembering that any animation overrider can potentially cause weirdness while on a sit-target, which is why most good ones can turn themselves off while seated. It&#039;s a bit difficult to describe specific problems with animations, but I think that sometimes it can be caused by animations that have a weird first frame, since it&#039;s used to calculate all the offsets etc. for the rest of the animation; normally this will be a neutral pose since you don&#039;t actually see it in the animation, but if it&#039;s something odd then it can mess with positioning. -- &amp;lt;br/&amp;gt;-- &#039;&#039;&#039;[[User:Haravikk_Mistral|Haravikk]]&#039;&#039;&#039; &amp;lt;sup&amp;gt;&amp;lt;small&amp;gt;([[User_talk:Haravikk_Mistral|talk]]|[[Special:Contributions/Haravikk_Mistral|contribs]])&amp;lt;/small&amp;gt;&amp;lt;/sup&amp;gt; 05:34, 12 March 2012 (PDT)&lt;br /&gt;
&lt;br /&gt;
::When I&#039;ve had problems with this, the root cause has usually been that I&#039;ve (or something has) inadvertently stopped an animation that&#039;s holding the avatar in place before starting another one.   Because animations are all made differently, neither the animator with whom I work most of the time nor I have ever managed to figure out exactly what to avoid, but certainly when it happens to me, I always start debugging by looking very carefully at where I&#039;m turning animations off and considering whether, in fact, I need to turn them off at all.   Quite often, I find that simply turning off the default sit animation when my first animation starts, and then keeping the first animation going throughout, starting and stopping other ones over it, as necessary, solves the problem.&lt;br /&gt;
&lt;br /&gt;
::One &amp;quot;gotcha&amp;quot; is that stopping an animation and then immediately restarting it doesn&#039;t work.  It confuses the viewer something horrible, and often leads to people floating in mid-air.  [[User:Innula Zenovka|Innula Zenovka]] 09:04, 12 March 2012 (PDT)&lt;br /&gt;
&lt;br /&gt;
== Sit Target 0.4m &#039;bug&#039; ==&lt;br /&gt;
The notes say &lt;br /&gt;
&amp;quot;rot affects the position of the sit-target in a buggy way way.&lt;br /&gt;
To correct for the rot bug, simply subtract &amp;lt;0,0,0.4&amp;gt; from the position when rot is zero. See example below.&amp;quot;&lt;br /&gt;
&lt;br /&gt;
But the example script adjusts z by 0.4m when rotation is NOT zero.&lt;br /&gt;
&amp;lt;lsl&amp;gt;&lt;br /&gt;
if (rot!=ZERO_ROTATION) pos -=&amp;lt;0,0,0.4&amp;gt;;  //here is the work around&lt;br /&gt;
&amp;lt;/lsl&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Which should it be?&lt;br /&gt;
&lt;br /&gt;
I&#039;ve just been doing some tests without any 0.4m adjustment, and I am unable to observe any difference in my z position whether rotation is zero or not. Has something changed? If so, wouldn&#039;t the change screw up some furniture?&lt;br /&gt;
[[User:Omei Qunhua|Omei Qunhua]] 14:09, 16 March 2014 (PDT)&lt;br /&gt;
&lt;br /&gt;
:You are right, there shouldn&#039;t be a test there. My understanding is that you always need to subtract 0.4 from z. Changing it would screw up furniture. -- &#039;&#039;&#039;[[User:Strife_Onizuka|Strife]]&#039;&#039;&#039; &amp;lt;sup&amp;gt;&amp;lt;small&amp;gt;([[User talk:Strife_Onizuka|talk]]|[[Special:Contributions/Strife_Onizuka|contribs]])&amp;lt;/small&amp;gt;&amp;lt;/sup&amp;gt; 21:02, 16 March 2014 (PDT)&lt;/div&gt;</summary>
		<author><name>Timmy Foxclaw</name></author>
	</entry>
	<entry>
		<id>https://wiki.secondlife.com/w/index.php?title=Talk:LlSitTarget&amp;diff=1189604</id>
		<title>Talk:LlSitTarget</title>
		<link rel="alternate" type="text/html" href="https://wiki.secondlife.com/w/index.php?title=Talk:LlSitTarget&amp;diff=1189604"/>
		<updated>2014-04-20T13:25:39Z</updated>

		<summary type="html">&lt;p&gt;Timmy Foxclaw: Add script to print the offsets.&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Unsitting on wrong side or camera rotation ==&lt;br /&gt;
&lt;br /&gt;
Hi, i am getting frustrated with this. I create a board and set the sit target with&lt;br /&gt;
&amp;lt;code&amp;gt;llSitTarget(&amp;lt;0.4, 0.0, 0.0&amp;gt;, ZERO_ROTATION);&amp;lt;/code&amp;gt;&lt;br /&gt;
and an animation which for &amp;quot;standing&amp;quot;. So while the person technical sits, she stands in front of the board. &lt;br /&gt;
But I have a problem with that: If the board stand freely, the person unsits right through it towards the other side. I can put the board with the back  facing a large wall. In the case the unsitting is correctly in front of it. But on sit down the camera rotates, so that it is behind the avatar again; on the other side of the wall.&lt;br /&gt;
&lt;br /&gt;
If anyone has an idea how to fix, please tell me (even if it is just an idea where to look for more information). --[[User:Maike Short|Maike Short]] 12:41, 24 February 2008 (PST)&lt;br /&gt;
&lt;br /&gt;
:You could position the camera with the {{LSLGC|Camera}} functions.  -- [[User:Strife Onizuka|Strife Onizuka]] 04:46, 25 February 2008 (PST)&lt;br /&gt;
&lt;br /&gt;
==GetSitTarget==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;lsl&amp;gt;&lt;br /&gt;
list GetSitTarget(integer prim, key av)&lt;br /&gt;
{//WARNING: llGetObjectDetails can introduce an error that goes as far as the 5th decimal place.&lt;br /&gt;
    vector tp = llGetAgentSize(av);&lt;br /&gt;
    if(tp)&lt;br /&gt;
    {&lt;br /&gt;
        if(prim == LINK_THIS)//llGetLinkKey doesn&#039;t like LINK_THIS&lt;br /&gt;
            prim = llGetLinkNumber();&lt;br /&gt;
    &lt;br /&gt;
        list details = OBJECT_POS + (list)OBJECT_ROT;&lt;br /&gt;
        rotation f = llList2Rot(details = (llGetObjectDetails(llGetLinkKey(prim), details) + llGetObjectDetails(av, details)), 1);&lt;br /&gt;
    &lt;br /&gt;
        return [(llRot2Up(f = (llList2Rot(details, 3) / f)) * tp.z * 0.02638) +&lt;br /&gt;
                ((llList2Vector(details, 2) - llList2Vector(details, 0)) / f) - &amp;lt;0.0, 0.0, 0.4&amp;gt;, f];&lt;br /&gt;
    }&lt;br /&gt;
    return [];&lt;br /&gt;
}//Written by Strife Onizuka&lt;br /&gt;
&amp;lt;/lsl&amp;gt;&lt;br /&gt;
Hi Strife! This version of your GetSitTarget, and the other version on the actual LlSitTarget page, both always return &amp;lt;0.000000, 0.000000, 0.707107, 0.707107&amp;gt; for the rotation. --[[User:MartinRJ Fayray|MartinRJ Fayray]] 07:52, 21 January 2013 (PST)&lt;br /&gt;
&lt;br /&gt;
:I haven&#039;t touched this in 5 years but I don&#039;t see a reason why it should be doing what you say. Are you sure you are using it properly? The prim parameter specifies what prim the location will be local to. The function was written to aid in determining sit targets when making furniture. You have the avatar sit on one object and then you get it&#039;s position local to the furniture so you can program in the sit target.&lt;br /&gt;
&lt;br /&gt;
:Just to clarify, you are saying that when you sit on an object with the following script in it, you don&#039;t get approximately the specified value? -- &#039;&#039;&#039;[[User:Strife_Onizuka|Strife]]&#039;&#039;&#039; &amp;lt;sup&amp;gt;&amp;lt;small&amp;gt;([[User talk:Strife_Onizuka|talk]]|[[Special:Contributions/Strife_Onizuka|contribs]])&amp;lt;/small&amp;gt;&amp;lt;/sup&amp;gt; 20:37, 22 January 2013 (PST)&lt;br /&gt;
&lt;br /&gt;
:It seems to work now. No idea what I was doing wrong. Thank you strife!--[[User:MartinRJ Fayray|MartinRJ Fayray]] 07:36, 3 February 2013 (PST)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;lsl&amp;gt;&lt;br /&gt;
vector vOffset = &amp;lt;0,0,1&amp;gt;;&lt;br /&gt;
rotation rOffset = &amp;lt;0,0,0,1&amp;gt;;&lt;br /&gt;
&lt;br /&gt;
list GetSitTarget(integer prim, key av)&lt;br /&gt;
{//WARNING: llGetObjectDetails can introduce an error that goes as far as the 5th decimal place!&lt;br /&gt;
 //This is highly unlikely to be ever noticed unless compounded over time.&lt;br /&gt;
 //Do not use while moving (like in a moving vehicle)!!!&lt;br /&gt;
    vector tp = llGetAgentSize(av);&lt;br /&gt;
    if(tp)&lt;br /&gt;
    {&lt;br /&gt;
        if(prim == LINK_THIS)//llGetLinkKey doesn&#039;t like LINK_THIS&lt;br /&gt;
            prim = llGetLinkNumber();&lt;br /&gt;
 &lt;br /&gt;
        list details = [OBJECT_POS, OBJECT_ROT];&lt;br /&gt;
        rotation f = llList2Rot(details = (llGetObjectDetails(llGetLinkKey(prim), details) + llGetObjectDetails(av, details)), 1);&lt;br /&gt;
        rotation r = llList2Rot(details, 3) / f;&lt;br /&gt;
 &lt;br /&gt;
        return [((llList2Vector(details, 2) - llList2Vector(details, 0)) / f) + (llRot2Up(r) * tp.z * 0.02638) - &amp;lt;0.0, 0.0, 0.4&amp;gt;, r];&lt;br /&gt;
    }&lt;br /&gt;
    return [];&lt;br /&gt;
}//Written by Strife Onizuka&lt;br /&gt;
&lt;br /&gt;
default{&lt;br /&gt;
    state_entry(){&lt;br /&gt;
        llSitTarget(vOffset, rOffset);&lt;br /&gt;
    }&lt;br /&gt;
    changed(integer change){&lt;br /&gt;
        key id = llAvatarOnSitTarget();&lt;br /&gt;
        if(id)&lt;br /&gt;
            llOwnerSay(&amp;quot;[&amp;quot;+llList2CSV([vOffset, rOffset]) +&amp;quot;] ~ [&amp;quot; + llList2CSV(GetSitTarget(LINK_THIS, id))+&amp;quot;]&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/lsl&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Note&#039;&#039;&#039;: the above two scripts in this paragraph are incorrect. Most notably, the position of an avatar (it&#039;s Avatar Center) is NOT dependent on the AgentSize of the seated avatar. I added another script that returns the sit target, below. [[User:Timmy Foxclaw|Timmy Foxclaw]] 10:31, 7 April 2014 (PDT)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;lsl&amp;gt;&lt;br /&gt;
// A script to develop and test sbGetLinkSitTarget&lt;br /&gt;
//&lt;br /&gt;
// Copyright(c) Timmy Songbird @DreamNation&lt;br /&gt;
//              Timmy Foxclaw  @SL,&lt;br /&gt;
//              2014&lt;br /&gt;
//&lt;br /&gt;
// This program is free software; you can redistribute it and/or modify&lt;br /&gt;
// it under the terms of the GNU General Public License as published by&lt;br /&gt;
// the Free Software Foundation; either version 2 of the License, or&lt;br /&gt;
// (at your option) any later version.&lt;br /&gt;
//&lt;br /&gt;
// This program is distributed in the hope that it will be useful,&lt;br /&gt;
// but WITHOUT ANY WARRANTY; without even the implied warranty of&lt;br /&gt;
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the&lt;br /&gt;
// GNU General Public License for more details.&lt;br /&gt;
//&lt;br /&gt;
// You should have received a copy of the GNU General Public License&lt;br /&gt;
// along with this program; if not, write to the Free Software&lt;br /&gt;
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307, USA.&#039;)&lt;br /&gt;
&lt;br /&gt;
//----------------------------------------------------------------------------&lt;br /&gt;
//#line &amp;quot;/opt/secondlife/scripts/scripts/tests/sbGetLinkSitTarget_Test.m4s:4&amp;quot;&lt;br /&gt;
// This script sets a &amp;quot;random&amp;quot;-ish sit target on every prim in an object.&lt;br /&gt;
// Recommended for your test is an object existing of two default cubes&lt;br /&gt;
// with arbitrary rotations and position. Put this script only in the&lt;br /&gt;
// root prim.&lt;br /&gt;
//&lt;br /&gt;
// The script sets the sit targets on compile or touch. Please touch&lt;br /&gt;
// the object after editting one of the prims.&lt;br /&gt;
//&lt;br /&gt;
// When an avatar (un)sits on one of the prims, the script prints for every&lt;br /&gt;
// sit target that has a seated avatar the return value of sbGetLinkSitTarget.&lt;br /&gt;
// This value should be (almost) equal to the values passed to llSitTarget.&lt;br /&gt;
&lt;br /&gt;
// Example output:&lt;br /&gt;
&lt;br /&gt;
// Object: [&amp;lt;0.200000, 0.300000, 0.500000&amp;gt;, &amp;lt;0.100000, 0.150000, 0.120000, 0.976268&amp;gt;] set with llSitTarget on 2 prims.&lt;br /&gt;
// Object: [&amp;lt;0.199999, 0.300001, 0.499999&amp;gt;, &amp;lt;0.100000, 0.150000, 0.120000, 0.976268&amp;gt;] returned by sbGetLinkSitTarget(1).&lt;br /&gt;
// Object: [&amp;lt;0.199998, 0.300002, 0.499998&amp;gt;, &amp;lt;0.100000, 0.150000, 0.120000, 0.976268&amp;gt;] returned by sbGetLinkSitTarget(2).&lt;br /&gt;
&lt;br /&gt;
// GitLocation: tests/sbGetLinkSitTarget_Test.m4s&lt;br /&gt;
&lt;br /&gt;
//----------------------------------------------------------------------------&lt;br /&gt;
//#line &amp;quot;/opt/secondlife/scripts/scripts/tests/sbGetLinkSitTarget_Test.m4s:26&amp;quot;&lt;br /&gt;
vector sitTarget_pos_link = &amp;lt;0.2, 0.3, 0.5&amp;gt;;&lt;br /&gt;
rotation sitTarget_rot_link = &amp;lt;0.1, 0.15, 0.12, 0.9762684&amp;gt;;&lt;br /&gt;
&lt;br /&gt;
//----------------------------------------------------------------------------&lt;br /&gt;
//#line &amp;quot;/opt/secondlife/scripts/scripts/tests/sbGetLinkSitTarget_Test.m4s:31&amp;quot;&lt;br /&gt;
// Returns the correct values to use for llSitTarget to make&lt;br /&gt;
// the currently seated avatar sit in the same way when re-seated.&lt;br /&gt;
// If no avatar is currently sitting then [ZERO_VECTOR, ZERO_ROTATION] is returned.&lt;br /&gt;
//&lt;br /&gt;
// [1] http://wiki.secondlife.com/wiki/User:Timmy_Foxclaw/About_Coordinate_Systems_and_Rotations#LSL_functions&lt;br /&gt;
// [2] http://wiki.secondlife.com/wiki/User:Timmy_Foxclaw/About_Coordinate_Systems_and_Rotations#Converting_between_coordinate_systems&lt;br /&gt;
list sbGetLinkSitTarget(integer link)&lt;br /&gt;
{&lt;br /&gt;
  // Calling llAvatarOnLinkSitTarget(0) always returns NULL_KEY because the link&lt;br /&gt;
  // number of an unlinked prim changes from 0 to 1 as soon as an avatar sits on&lt;br /&gt;
  // it. So if 0 was passed then they probably meant 1.&lt;br /&gt;
  if (link == 0)&lt;br /&gt;
  {&lt;br /&gt;
    link = 1;&lt;br /&gt;
  }&lt;br /&gt;
  key av = llAvatarOnLinkSitTarget(link);&lt;br /&gt;
  if (av != NULL_KEY)&lt;br /&gt;
  {&lt;br /&gt;
    // Get link_pos_oc and link_rot_oc. See table 2 in [1].&lt;br /&gt;
    vector link_pos_oc = ZERO_VECTOR;&lt;br /&gt;
    rotation link_rot_oc = ZERO_ROTATION;&lt;br /&gt;
    if (link &amp;gt; 1)&lt;br /&gt;
    {&lt;br /&gt;
      list params = llGetLinkPrimitiveParams(link, [PRIM_POS_LOCAL, PRIM_ROT_LOCAL]);&lt;br /&gt;
      link_pos_oc = llList2Vector(params, 0);&lt;br /&gt;
      link_rot_oc = llList2Rot(params, 1);&lt;br /&gt;
    }&lt;br /&gt;
    // Find the link number of the seated avatar.&lt;br /&gt;
    integer avNum = llGetNumberOfPrims();&lt;br /&gt;
    do&lt;br /&gt;
    {&lt;br /&gt;
        if (av == llGetLinkKey(avNum))&lt;br /&gt;
        {&lt;br /&gt;
            // Get ac_pos_oc and ac_rot_oc (ac stands for Avatar Center), exactly the same as above&lt;br /&gt;
            // except that we don&#039;t need to test if avNum &amp;gt; 1, because it always will be.&lt;br /&gt;
            list params = llGetLinkPrimitiveParams(avNum, [PRIM_POS_LOCAL, PRIM_ROT_LOCAL]);&lt;br /&gt;
            vector ac_pos_oc = llList2Vector(params, 0);&lt;br /&gt;
            rotation ac_rot_oc = llList2Rot(params, 1);&lt;br /&gt;
&lt;br /&gt;
            // Convert that to link coordinates. See formula (3) in [2].&lt;br /&gt;
            vector ac_pos_link = (ac_pos_oc - link_pos_oc) / link_rot_oc;&lt;br /&gt;
            rotation ac_rot_link = ac_rot_oc / link_rot_oc;&lt;br /&gt;
&lt;br /&gt;
            // Now we have this little vector in the Avatar Center coordinates.&lt;br /&gt;
            vector sit_pos_ac = &amp;lt;0.0, 0.0, 0.05&amp;gt;;&lt;br /&gt;
&lt;br /&gt;
            // Convert that to link coordinates. See formula (1) in [2].&lt;br /&gt;
            vector sit_pos_link = sit_pos_ac * ac_rot_link + ac_pos_link;&lt;br /&gt;
&lt;br /&gt;
            // Return the values, accounting for the sit target bug of 0.4m.&lt;br /&gt;
            return [sit_pos_link - &amp;lt;0.0, 0.0, 0.4&amp;gt;, ac_rot_link];&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    while (--avNum);&lt;br /&gt;
  }&lt;br /&gt;
  return [ZERO_VECTOR, ZERO_ROTATION];&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
setSitTargets()&lt;br /&gt;
{&lt;br /&gt;
  // Set the same sit target on every prim.&lt;br /&gt;
  integer n = llGetNumberOfPrims();&lt;br /&gt;
  llSay(0, &amp;quot;[&amp;quot; +  llList2CSV([sitTarget_pos_link, sitTarget_rot_link]) + &amp;quot;] set with llSitTarget on &amp;quot; + (string)n + &amp;quot; prims.&amp;quot;);&lt;br /&gt;
  do&lt;br /&gt;
  {&lt;br /&gt;
    llLinkSitTarget(n, sitTarget_pos_link, sitTarget_rot_link);&lt;br /&gt;
  }&lt;br /&gt;
  while(--n);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
//----------------------------------------------------------------------------&lt;br /&gt;
//#line &amp;quot;/opt/secondlife/scripts/scripts/tests/sbGetLinkSitTarget_Test.m4s:105&amp;quot;&lt;br /&gt;
default&lt;br /&gt;
{&lt;br /&gt;
  state_entry()&lt;br /&gt;
  {&lt;br /&gt;
    setSitTargets();&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  touch_start(integer n)&lt;br /&gt;
  {&lt;br /&gt;
    setSitTargets();&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  changed(integer change)&lt;br /&gt;
  {&lt;br /&gt;
    if ((change &amp;amp; CHANGED_LINK))&lt;br /&gt;
    {&lt;br /&gt;
      integer n = llGetNumberOfPrims();&lt;br /&gt;
      do&lt;br /&gt;
      {&lt;br /&gt;
        key av = llAvatarOnLinkSitTarget(n);&lt;br /&gt;
        if (av != NULL_KEY)&lt;br /&gt;
        {&lt;br /&gt;
          llSay(0, &amp;quot;[&amp;quot; + llList2CSV(sbGetLinkSitTarget(n)) + &amp;quot;] returned by sbGetLinkSitTarget(&amp;quot; + (string)n + &amp;quot;).&amp;quot;);&lt;br /&gt;
        }&lt;br /&gt;
      }&lt;br /&gt;
      while(--n);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/lsl&amp;gt;&lt;br /&gt;
:Yes the above two scripts are older versions. The 0.05 offset has been tried before. {{User|Talarus Luan}} [https://wiki.secondlife.com/w/index.php?title=LlSitTarget&amp;amp;diff=1179695&amp;amp;oldid=1179694 could not get it to work]. {{User|Talarus Luan}} went on to work out a quadratic equation that provided a more accurate result. See [[#UpdateSitTarget_changes.3F|#UpdateSitTarget changes?]] below. -- &#039;&#039;&#039;[[User:Strife_Onizuka|Strife]]&#039;&#039;&#039; &amp;lt;sup&amp;gt;&amp;lt;small&amp;gt;([[User talk:Strife_Onizuka|talk]]|[[Special:Contributions/Strife_Onizuka|contribs]])&amp;lt;/small&amp;gt;&amp;lt;/sup&amp;gt; 12:38, 7 April 2014 (PDT)&lt;br /&gt;
&lt;br /&gt;
::Hi Strife. There must be some miscommunication - we seem to be talking about different things. After extensive research (see [[ User:Timmy_Foxclaw/About_Coordinate_Systems_and_Rotations|this link]], especially the script at the end), I have found that the value is exactly 0.05 and not depend on the height of the avatar in SecondLife. The function sbGetLinkSitTarget as defined in the script above returns the exact values (within the normal floating point round off error of 0.000002 or so), no matter what position and rotation you passed to llSitTarget. Perhaps we can meet in some sandbox in SL? I&#039;d like to understand where your quadratic expression exactly comes in. Maybe you can show me the test object and the tests that you did to determine it. [[User:Timmy Foxclaw|Timmy Foxclaw]] 15:41, 7 April 2014 (PDT)&lt;br /&gt;
&lt;br /&gt;
:::I&#039;d love to meet you inworld but my current schedule precludes that for about the next month (it has sucked, I missed my own 10 year birthday). Beyond inserting the changes proposed by others I haven&#039;t done any of the work on this myself, I code mostly for the fun of it and do testing in LSLEditor. I have been watching your ACSaR article evolve, I&#039;ve been thinking it might be worth bringing into the main namespace. I don&#039;t know how LL did such a wonderful job of screwing sittargets up. -- &#039;&#039;&#039;[[User:Strife_Onizuka|Strife]]&#039;&#039;&#039; &amp;lt;sup&amp;gt;&amp;lt;small&amp;gt;([[User talk:Strife_Onizuka|talk]]|[[Special:Contributions/Strife_Onizuka|contribs]])&amp;lt;/small&amp;gt;&amp;lt;/sup&amp;gt; 19:18, 7 April 2014 (PDT)&lt;br /&gt;
&lt;br /&gt;
::::Hey Timmy.  I&#039;m guessing that the quadratic equation to wihch Strife is referring is the one at the end of the [[#UpdateSitTarget_changes.3F|#UpdateSitTarget changes?]] section below, where {{User|Talarus Luan}} arrives at the quadratic equation&lt;br /&gt;
&lt;br /&gt;
 offset = 0.008906 * z^3 - 0.049831 * z^2 + 0.088967 * z&lt;br /&gt;
&lt;br /&gt;
::::where z is avatar height.  If I plug z = 1.16 and z = 2.45 into this equation, I get the values 0.050050466 and 0.049831322 respectively.  The difference between these two values is just 0.000219144, so it&#039;s all very close to 0.05.  However, I&#039;d love to know the exact calculation in order to get this right in the next release of OpenSimulator.  On a very unscientific eyeballing, they both seem more accurate than the z * 0.02638 calculation in the script (which has a value range of 0.0306008 to 0.064631) but between these two it&#039;s much harder to tell.  How do you perform your measurements? -- [[User:Fenn Meredith|Fenn Meredith]] 16:26, 18 April 2014 (PDT)&lt;br /&gt;
&lt;br /&gt;
:::::Hi Fenn, I gave you a test object in SL. It prints out the values. A little drawing would things a lot more clear but well, that&#039;s a bit hard :p. The idea is that if you pass some vector to llSitTarget then you have to add 0.4 to it&#039;s Z value to arrive at the same point as the vector in the Avatar Center Coordinate System (AC) that points along the Z-axis of that coordinate system (lets call that point S). Hence if you apply no rotation then S is 0.4m above the sittarget, and the AC is 0.05m below that, hence 0.35m above the set sittarget. If you apply a rotation of 180 degrees, they will add up and AC ends up at 0.45m above the set sittarget. While, if you use a rotation of 90 degrees then AC ends up 0.4m above the set sittarget, but 0.05m to the left (or right) of it. The latter is thus the easiest way to distinguish them with a single sit. Here is a script that does that:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;lsl&amp;gt;vector sit_pos_link = &amp;lt;0.0, 0.0, 1.0&amp;gt;;&lt;br /&gt;
rotation ac_rot_link;&lt;br /&gt;
&lt;br /&gt;
default&lt;br /&gt;
{&lt;br /&gt;
  state_entry()&lt;br /&gt;
  {&lt;br /&gt;
    vector rot = &amp;lt;90.0, 0.0, 0&amp;gt;;&lt;br /&gt;
    ac_rot_link = llEuler2Rot(rot * DEG_TO_RAD);&lt;br /&gt;
    llSitTarget(sit_pos_link, ac_rot_link);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  changed(integer change)&lt;br /&gt;
  {&lt;br /&gt;
    if ((change &amp;amp; CHANGED_LINK))&lt;br /&gt;
    {&lt;br /&gt;
      key av = llAvatarOnSitTarget();&lt;br /&gt;
      if (av != NULL_KEY)&lt;br /&gt;
      {&lt;br /&gt;
        llRequestPermissions(av, PERMISSION_TRIGGER_ANIMATION);&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  run_time_permissions(integer perm)&lt;br /&gt;
  {&lt;br /&gt;
    if ((perm &amp;amp; PERMISSION_TRIGGER_ANIMATION))&lt;br /&gt;
    {&lt;br /&gt;
      key user = llAvatarOnSitTarget();&lt;br /&gt;
      if (user)&lt;br /&gt;
      {&lt;br /&gt;
        integer linkNum = llGetNumberOfPrims();&lt;br /&gt;
        do&lt;br /&gt;
        {&lt;br /&gt;
          if (user == llGetLinkKey(linkNum))&lt;br /&gt;
          {&lt;br /&gt;
            list params = llGetLinkPrimitiveParams(linkNum, [PRIM_POS_LOCAL, PRIM_SIZE]);&lt;br /&gt;
            vector ac_pos_link = llList2Vector(params, 0);&lt;br /&gt;
            vector offsets = ac_pos_link - sit_pos_link;&lt;br /&gt;
            vector agentSize = llList2Vector(params, 1);&lt;br /&gt;
            float z = agentSize.z;&lt;br /&gt;
            llSay(0, &amp;quot;The agentSize.z is &amp;quot; + (string)z + &amp;quot; --&amp;gt;\n0.008906 * z^3 - 0.049831 * z^2 + 0.088967 * z = &amp;quot; + (string)(((0.008906 * z - 0.049831) * z + 0.088967) * z));&lt;br /&gt;
            llSay(0, &amp;quot;The actual offsets are:\n&amp;quot; + (string)offsets.z + &amp;quot; and &amp;quot; + (string)offsets.y + &amp;quot; (+/- 0.000002)&amp;quot;);&lt;br /&gt;
            jump end;&lt;br /&gt;
          }&lt;br /&gt;
        }&lt;br /&gt;
        while (--linkNum);&lt;br /&gt;
      }&lt;br /&gt;
      @end;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/lsl&amp;gt;&lt;br /&gt;
&lt;br /&gt;
:::::You can use this script also in opensim to see what it gives there. In 0.8-dev you might also want to print offsets.y / z (which will give -0.02638). [[User:Timmy Foxclaw|Timmy Foxclaw]] 06:25, 20 April 2014 (PDT)&lt;br /&gt;
&lt;br /&gt;
==Using llSetLinkPrimitiveParams for skydiving: why limited to 5m in a linked set?==&lt;br /&gt;
llSetLinkPrimitiveParams can be used as a handy tool to adjust an avatar&#039;s position and rotation.&lt;br /&gt;
This works perfectly when the object consists of 1 prim, with a range for setting the avatar position away to 500m easily!&lt;br /&gt;
When there are more prims linked, this offset seems to be limited to 5m (measured with llVecDist). This is an awfull sideeffect!&lt;br /&gt;
&lt;br /&gt;
Put this next script inside a prim and sit on the prim, it will bring you to 1000.0 higher then the prim.&lt;br /&gt;
Next link this prim to another prim and try again. You will notice you are limited to 5m. My Question: why is this limited?&lt;br /&gt;
&amp;lt;lsl&amp;gt;&lt;br /&gt;
// by Randur Source&lt;br /&gt;
&lt;br /&gt;
integer heightcnt = 0;&lt;br /&gt;
list heights = [0.0, 1.0, 5.0, 6.0, 10.0, 100.0, 300.0, 500.0, 800.0, 1000.0];&lt;br /&gt;
&lt;br /&gt;
default&lt;br /&gt;
{&lt;br /&gt;
    state_entry()&lt;br /&gt;
    {&lt;br /&gt;
        llSitTarget(ZERO_VECTOR,ZERO_ROTATION); // Clear the current sittarget for a clear test&lt;br /&gt;
        llSetRot(ZERO_ROTATION); // set the prim to no rotation, for simple z axis movement&lt;br /&gt;
    }&lt;br /&gt;
    &lt;br /&gt;
    changed(integer change)&lt;br /&gt;
    {&lt;br /&gt;
        if (change &amp;amp; CHANGED_LINK) // detect linked prims and avatars&lt;br /&gt;
        {&lt;br /&gt;
            integer primnum = llGetNumberOfPrims(); // the avatar is the last linked prim&lt;br /&gt;
            if (primnum &amp;lt;= 1) // stop if there is only 1 prim&lt;br /&gt;
                return;&lt;br /&gt;
        &lt;br /&gt;
            key avatar = llGetLinkKey(primnum);&lt;br /&gt;
            if (llGetAgentSize(avatar) == ZERO_VECTOR) // stop if this is not an avatar&lt;br /&gt;
                return;&lt;br /&gt;
                &lt;br /&gt;
            // loop through the list of test heights:&lt;br /&gt;
            for (heightcnt = 0; heightcnt &amp;lt; llGetListLength(heights); heightcnt++)&lt;br /&gt;
            {&lt;br /&gt;
                float height = llList2Float(heights,heightcnt);&lt;br /&gt;
                llSetLinkPrimitiveParams(primnum,[PRIM_POSITION,&amp;lt;0.0,0.0,height&amp;gt;]); // set this to the wanted height using a vector z axis&lt;br /&gt;
                &lt;br /&gt;
                vector avatarpos = llList2Vector(llGetObjectDetails(avatar,[OBJECT_POS]),0); // detect the avatar position within the sim&lt;br /&gt;
                float distance = llVecDist(llGetPos(),avatarpos);&lt;br /&gt;
                llOwnerSay(&amp;quot;Attempt to move &amp;quot; + llKey2Name(llGetLinkKey(primnum)) +&lt;br /&gt;
                           &amp;quot; to &amp;quot; + (string)height + &amp;quot;m high resulting to &amp;quot; + (string)distance + &amp;quot;m&amp;quot;);&lt;br /&gt;
                &lt;br /&gt;
                llSleep(1.0);&lt;br /&gt;
            }&lt;br /&gt;
            llUnSit(avatar);&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/lsl&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Posted by Sylvio Runo : Answer &#039;&#039;&#039; :&lt;br /&gt;
The correct limit is 54 meters.&lt;br /&gt;
You can&#039;t move a linked object more than 54 meters away from the axis of the root prim.&lt;br /&gt;
On SecondLife (other grids like OsGrid, may works diferent) when an agent sit on prim, the agent is attached to it, so the agent is a linked prim of the link set.&lt;br /&gt;
&lt;br /&gt;
More information about link rules, you will find here : http://wiki.secondlife.com/wiki/Linkability_Rules [http://wiki.secondlife.com/wiki/Linkability_Rules]&lt;br /&gt;
&lt;br /&gt;
==UpdateSitTarget changes?==&lt;br /&gt;
I recently worked on a project where I used a version of this function, and it appears that it is a little off. A couple of things I noted: the Z-offset of the sit target is 0.35, not 0.4, and the avatar size doesn&#039;t seem to affect this position at all. When I used this function verbatim, I noticed discrepancies between the actual sit target and the set position call. When I changed the script as noted, I got a perfect match. Has the handling of the sit target been changed since this was written? [[User:Talarus Luan|Talarus Luan]] 22:57, 1 July 2009 (UTC)&lt;br /&gt;
:Seconded. I wish I&#039;d looked at this discussion before spending an hour on trying to figure out how the code actually behaved. -- [[User:Tonya Souther|Tonya Souther]] 15:11, 19 August 2009 (UTC)&lt;br /&gt;
&lt;br /&gt;
::This is news to me but I haven&#039;t been in world in ages :( -- &#039;&#039;&#039;[[User:Strife_Onizuka|Strife]]&#039;&#039;&#039; &amp;lt;sup&amp;gt;&amp;lt;small&amp;gt;([[User talk:Strife_Onizuka|talk]]|[[Special:Contributions/Strife_Onizuka|contribs]])&amp;lt;/small&amp;gt;&amp;lt;/sup&amp;gt; 22:56, 20 August 2009 (UTC)&lt;br /&gt;
&lt;br /&gt;
:::From some quick testing in 1.40, this seems to be how the &amp;quot;true&amp;quot; offset is computed:&lt;br /&gt;
:::1. Start with offset as provided by LSL.&lt;br /&gt;
:::2. Add &amp;lt; 0.0 , 0.0 , 0.4 &amp;gt;&lt;br /&gt;
:::3. Subtract llRot2Up( rot ) * 0.05&lt;br /&gt;
:::[[User:Gregory Maurer|--Gregory Maurer]] 20:00, 28 August 2010 (UTC)&lt;br /&gt;
&lt;br /&gt;
::::Confirmed. The following appears to work fine:&lt;br /&gt;
&amp;lt;lsl&amp;gt;llSetLinkPrimitiveParams(linkNum, [PRIM_POS_LOCAL, pos + &amp;lt;0.0, 0.0, 0.4&amp;gt; - (llRot2Up(rot) * 0.05), PRIM_ROT_LOCAL, rot]);&amp;lt;/lsl&amp;gt;&lt;br /&gt;
::::This of course using the new &amp;lt;code&amp;gt;PRIM_POS_LOCAL&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;PRIM_ROT_LOCAL&amp;lt;/code&amp;gt; values for simplicity. If one or two others can confirm that the above code works correctly, then I can splice it into the example.&amp;lt;br/&amp;gt;-- &#039;&#039;&#039;[[User:Haravikk_Mistral|Haravikk]]&#039;&#039;&#039; &amp;lt;sup&amp;gt;&amp;lt;small&amp;gt;([[User_talk:Haravikk_Mistral|talk]]|[[Special:Contributions/Haravikk_Mistral|contribs]])&amp;lt;/small&amp;gt;&amp;lt;/sup&amp;gt; 14:16, 26 December 2011 (PST)&lt;br /&gt;
&lt;br /&gt;
:::::Be sure to test it with avatars of different shapes, and shoe configurations. I recall that being an issue. {{User|Escort DeFarge}} would know about this best. -- &#039;&#039;&#039;[[User:Strife_Onizuka|Strife]]&#039;&#039;&#039; &amp;lt;sup&amp;gt;&amp;lt;small&amp;gt;([[User talk:Strife_Onizuka|talk]]|[[Special:Contributions/Strife_Onizuka|contribs]])&amp;lt;/small&amp;gt;&amp;lt;/sup&amp;gt; 22:05, 26 December 2011 (PST)&lt;br /&gt;
&lt;br /&gt;
::::::I tried with my two main avatar appearances, one average human height and one closer to 8 feet tall, and it didn&#039;t seem to make a difference. The test I used was a simple object with sit-target set, and a menu allowing it to be repositioned, causing the sit-target to move and if an avatar is seated on it, they will be repositioned using &amp;lt;code&amp;gt;llSetLinkPrimitiveParams()&amp;lt;/code&amp;gt; as done above. In my case the position of the avatar was consistent both when sitting on the object (using the sit-target) and being repositioned. Avatar height appears to have no effect, as the sit-target seems to define the avatar&#039;s hip-location, which is seemingly the avatar&#039;s &amp;quot;centre&amp;quot; when seated. I&#039;ll try to run some more tests when I get a chance, as it&#039;s possible this behaviour may not hold true if the object doesn&#039;t have a sit-target on it. The height of the avatar does however have a marked visual impact, depending exactly what you&#039;re trying to line up where, but that&#039;s a general issue with sitting on objects.&amp;lt;br/&amp;gt;-- &#039;&#039;&#039;[[User:Haravikk_Mistral|Haravikk]]&#039;&#039;&#039; &amp;lt;sup&amp;gt;&amp;lt;small&amp;gt;([[User_talk:Haravikk_Mistral|talk]]|[[Special:Contributions/Haravikk_Mistral|contribs]])&amp;lt;/small&amp;gt;&amp;lt;/sup&amp;gt; 05:38, 28 December 2011 (PST)&lt;br /&gt;
:::::::Sorry for my long delay in responding. Due to various RL issues and SL/LL burnout, I took a year off from SL to pursue other activities. That said, it seems to work fine to me, Haravikk; however, I have not done exhaustive testing with tons of different avs, shoes, etc. I would consider going ahead and changing it, because the version as it is right now is not correct for the majority of avatars, regardless. If Escort DeFarge or someone else wants to amend it later to include edge cases, that&#039;s great, but a better base accuracy is more important at this point. In fact, I think I will go ahead and edit it in, since it has been so long anyway.[[User:Talarus Luan|Talarus Luan]] 12:12, 5 July 2013 (PDT)&lt;br /&gt;
:::::::Holding up on the edit, further testing is revealing that if the script is in a prim other than the root, it is off by varying amounts depending on the rotation.[[User:Talarus Luan|Talarus Luan]] 12:39, 5 July 2013 (PDT)&lt;br /&gt;
:::::::OK, I think I found the error. Still need to keep the local position/rotation values for the child prim the script is in, like so:&lt;br /&gt;
&amp;lt;lsl&amp;gt;llSetLinkPrimitiveParams(linkNum, PRIM_POS_LOCAL, (pos + &amp;lt;0.0, 0.0, 0.4&amp;gt; - (llRot2Up(rot) * 0.05)) * localrot + localpos, PRIM_ROT_LOCAL, rot * localrot]);&amp;lt;/lsl&amp;gt;&lt;br /&gt;
:::::::I&#039;ll hold off on the edit until I can get another verify that this code is good.[[User:Talarus Luan|Talarus Luan]] 12:51, 5 July 2013 (PDT)&lt;br /&gt;
:::::::OK. I think I have analyzed this to death today and have come to the conclusion that Strife&#039;s original code is largely correct, but the error I am seeing comes from the &amp;quot;magic constants&amp;quot; 0.4 and 0.02638. Haravikk&#039;s code is simply a reduced form of Strife&#039;s code. The 0.4 magic constant is still there, but Haravikk is using just a close, but fixed, magic constant of 0.05 instead of Strife&#039;s (size.z * 0.02638), which comes out very close to 0.5 for most normal human avs. Thus, I am concluding that the inaccuracy is in the &amp;quot;magic constants&amp;quot; themselves, and I am going to hold off on the edit until I can get some more information on the source of these constants and see if there are better, more accurate values. It is annoying that, in all these years, we still haven&#039;t gotten LL to just tell us what the damn difference is between avatar sit targets and local position offsets in a linkset. It can&#039;t be that hard for someone who is familiar with the code to look at it and document it. -.- [[User:Talarus Luan|Talarus Luan]] 13:24, 5 July 2013 (PDT)&lt;br /&gt;
&lt;br /&gt;
::::::::Welcome back! I&#039;d like to take credit for that but that&#039;s the part that Escort contributed. As to where 0.02638 comes from, I vaguely recall it came from Escort&#039;s testing. I was driven more by &amp;quot;wouldn&#039;t it be cool to write a function that...&amp;quot; than anything else. I do agree the values have always been not quite right. -- &#039;&#039;&#039;[[User:Strife_Onizuka|Strife]]&#039;&#039;&#039; &amp;lt;sup&amp;gt;&amp;lt;small&amp;gt;([[User talk:Strife_Onizuka|talk]]|[[Special:Contributions/Strife_Onizuka|contribs]])&amp;lt;/small&amp;gt;&amp;lt;/sup&amp;gt; 23:10, 5 July 2013 (PDT)&lt;br /&gt;
:::::::::Thanks! OK, I did a bunch of empirical testing, sampling a bunch of avatars from 1.16m to 2.45m in height, as reported by llGetAgentSize. I picked the lowest and highest and one about standard height, and fitted a parabolic curve through them. I have reduced the inaccuracies to a great degree, but it still isn&#039;t 100% perfect for all sizes in that range, just the ones that I used to solve the curve equation. The rest show a *tiny* bit of movement, but they are very close. Obviously, the difference isn&#039;t parabolic, probably just some kind of discrete step function, but it works.[[User:Talarus Luan|Talarus Luan]] 11:16, 14 July 2013 (PDT)&lt;br /&gt;
&amp;lt;lsl&amp;gt;vector vCoefficients = &amp;lt;0.008906,-0.049831,0.088967&amp;gt;;&lt;br /&gt;
float fAdjust = vCoefficients.x * size.z * size.z + vCoefficients.y * size.z + vCoefficients.z;&lt;br /&gt;
llSetLinkPrimitiveParamsFast(linkNum,&lt;br /&gt;
    [PRIM_POS_LOCAL, (pos + &amp;lt;0.0, 0.0, 0.4&amp;gt; - (llRot2Up(rot) * size.z * fAdjust)) * localrot + localpos,&lt;br /&gt;
     PRIM_ROT_LOCAL, rot * localrot]);&amp;lt;/lsl&amp;gt;&lt;br /&gt;
&lt;br /&gt;
::::::::::I see you mind reading abilities haven&#039;t diminished (I contemplated suggesting the tests you have done, decided to go to bed instead). Any reason not to use parentheses? It looks like something that could get optimized to an a series of FMAs (by the VM). -- &#039;&#039;&#039;[[User:Strife_Onizuka|Strife]]&#039;&#039;&#039; &amp;lt;sup&amp;gt;&amp;lt;small&amp;gt;([[User talk:Strife_Onizuka|talk]]|[[Special:Contributions/Strife_Onizuka|contribs]])&amp;lt;/small&amp;gt;&amp;lt;/sup&amp;gt; 21:33, 14 July 2013 (PDT)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;lsl&amp;gt;vector vCoefficients = &amp;lt;0.008906,-0.049831,0.088967&amp;gt;;&lt;br /&gt;
float fAdjust = ((((vCoefficients.x * size.z) + vCoefficients.y) * size.z) + vCoefficients.z) * size.z;&lt;br /&gt;
llSetLinkPrimitiveParamsFast(linkNum,&lt;br /&gt;
    [PRIM_POS_LOCAL, (pos + &amp;lt;0.0, 0.0, 0.4&amp;gt; - (llRot2Up(rot) * fAdjust)) * localrot + localpos,&lt;br /&gt;
     PRIM_ROT_LOCAL, rot * localrot]);&amp;lt;/lsl&amp;gt;&lt;br /&gt;
:::::::::::Yeah, I thought about optimizing it a bit after I posted it, but decided to leave it unoptimized here so the path from the current function to this change was clear, for demonstrability purposes. Besides, I had to leave some room for it to be Strifed&amp;amp;trade;. :P [[User:Talarus Luan|Talarus Luan]] 15:17, 17 July 2013 (PDT)&lt;br /&gt;
&lt;br /&gt;
::::::::::::I appreciate the gesture :p and I&#039;m not as bad as I use to be. I&#039;m not going to optimize out fAdjust, it&#039;s more readable this way. This is more for myself later as my memory is crap, the reasoning behind using llRot2Up is that it solves the pesky problem of the quaternion not having a magnitude of one. While the following isn&#039;t optimal, it is cool. -- &#039;&#039;&#039;[[User:Strife_Onizuka|Strife]]&#039;&#039;&#039; &amp;lt;sup&amp;gt;&amp;lt;small&amp;gt;([[User talk:Strife_Onizuka|talk]]|[[Special:Contributions/Strife_Onizuka|contribs]])&amp;lt;/small&amp;gt;&amp;lt;/sup&amp;gt; 00:00, 18 July 2013 (PDT)&lt;br /&gt;
&amp;lt;lsl&amp;gt;&lt;br /&gt;
size.x = (size.z * (size.y = (size.z * size.z)));&lt;br /&gt;
float fAdjust = vCoefficients * size;&lt;br /&gt;
&amp;lt;/lsl&amp;gt;&lt;br /&gt;
:::::::::::::Yeah, that is a nice way to represent it, for those used to the LSL representation for vector dot product. I&#039;m a little less enthused about the size vector assignment chain, but that&#039;s just my general dislike for C value assignments and such. In my mind, I separate assignments from expressions, so seeing them mixed together causes a bit of a train wreck in my brain&#039;s lexical analyzer. :P[[User:Talarus Luan|Talarus Luan]] 10:00, 21 July 2013 (PDT)&lt;br /&gt;
&lt;br /&gt;
::::::::::::::I don&#039;t think anyone uses the LSL vector dot product. It took me three days to remember it existed and then I look up the syntax just to make sure I wasn&#039;t crazy (yes yes, I agree it&#039;s insane to think that looking up the syntax of an obscure feature is proof against insanity but I&#039;m sticking to it, my cat agrees). I think a train wreck was my goal. -- &#039;&#039;&#039;[[User:Strife_Onizuka|Strife]]&#039;&#039;&#039; &amp;lt;sup&amp;gt;&amp;lt;small&amp;gt;([[User talk:Strife_Onizuka|talk]]|[[Special:Contributions/Strife_Onizuka|contribs]])&amp;lt;/small&amp;gt;&amp;lt;/sup&amp;gt; 11:13, 21 July 2013 (PDT)&lt;br /&gt;
&lt;br /&gt;
== Avatars Floating After Sit ==&lt;br /&gt;
&lt;br /&gt;
The position of avatars will sometimes change, generally noticeable as a rise on the Z axis of perhaps half a meter - common triggers for this is typing or another AV sitting on the same object - though these are not exhaustive.  Does anyone have a clue why this happens, and how to prevent it from happening? [[User:TaraLi Jie|TaraLi Jie]] 21:14, 11 March 2012 (PDT)&lt;br /&gt;
&lt;br /&gt;
:Hmm, there are a few possible causes, but the main cause are the animations involved, so it&#039;s worth remembering that any animation overrider can potentially cause weirdness while on a sit-target, which is why most good ones can turn themselves off while seated. It&#039;s a bit difficult to describe specific problems with animations, but I think that sometimes it can be caused by animations that have a weird first frame, since it&#039;s used to calculate all the offsets etc. for the rest of the animation; normally this will be a neutral pose since you don&#039;t actually see it in the animation, but if it&#039;s something odd then it can mess with positioning. -- &amp;lt;br/&amp;gt;-- &#039;&#039;&#039;[[User:Haravikk_Mistral|Haravikk]]&#039;&#039;&#039; &amp;lt;sup&amp;gt;&amp;lt;small&amp;gt;([[User_talk:Haravikk_Mistral|talk]]|[[Special:Contributions/Haravikk_Mistral|contribs]])&amp;lt;/small&amp;gt;&amp;lt;/sup&amp;gt; 05:34, 12 March 2012 (PDT)&lt;br /&gt;
&lt;br /&gt;
::When I&#039;ve had problems with this, the root cause has usually been that I&#039;ve (or something has) inadvertently stopped an animation that&#039;s holding the avatar in place before starting another one.   Because animations are all made differently, neither the animator with whom I work most of the time nor I have ever managed to figure out exactly what to avoid, but certainly when it happens to me, I always start debugging by looking very carefully at where I&#039;m turning animations off and considering whether, in fact, I need to turn them off at all.   Quite often, I find that simply turning off the default sit animation when my first animation starts, and then keeping the first animation going throughout, starting and stopping other ones over it, as necessary, solves the problem.&lt;br /&gt;
&lt;br /&gt;
::One &amp;quot;gotcha&amp;quot; is that stopping an animation and then immediately restarting it doesn&#039;t work.  It confuses the viewer something horrible, and often leads to people floating in mid-air.  [[User:Innula Zenovka|Innula Zenovka]] 09:04, 12 March 2012 (PDT)&lt;br /&gt;
&lt;br /&gt;
== Sit Target 0.4m &#039;bug&#039; ==&lt;br /&gt;
The notes say &lt;br /&gt;
&amp;quot;rot affects the position of the sit-target in a buggy way way.&lt;br /&gt;
To correct for the rot bug, simply subtract &amp;lt;0,0,0.4&amp;gt; from the position when rot is zero. See example below.&amp;quot;&lt;br /&gt;
&lt;br /&gt;
But the example script adjusts z by 0.4m when rotation is NOT zero.&lt;br /&gt;
&amp;lt;lsl&amp;gt;&lt;br /&gt;
if (rot!=ZERO_ROTATION) pos -=&amp;lt;0,0,0.4&amp;gt;;  //here is the work around&lt;br /&gt;
&amp;lt;/lsl&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Which should it be?&lt;br /&gt;
&lt;br /&gt;
I&#039;ve just been doing some tests without any 0.4m adjustment, and I am unable to observe any difference in my z position whether rotation is zero or not. Has something changed? If so, wouldn&#039;t the change screw up some furniture?&lt;br /&gt;
[[User:Omei Qunhua|Omei Qunhua]] 14:09, 16 March 2014 (PDT)&lt;br /&gt;
&lt;br /&gt;
:You are right, there shouldn&#039;t be a test there. My understanding is that you always need to subtract 0.4 from z. Changing it would screw up furniture. -- &#039;&#039;&#039;[[User:Strife_Onizuka|Strife]]&#039;&#039;&#039; &amp;lt;sup&amp;gt;&amp;lt;small&amp;gt;([[User talk:Strife_Onizuka|talk]]|[[Special:Contributions/Strife_Onizuka|contribs]])&amp;lt;/small&amp;gt;&amp;lt;/sup&amp;gt; 21:02, 16 March 2014 (PDT)&lt;/div&gt;</summary>
		<author><name>Timmy Foxclaw</name></author>
	</entry>
	<entry>
		<id>https://wiki.secondlife.com/w/index.php?title=User:Timmy_Foxclaw/About_Coordinate_Systems_and_Rotations&amp;diff=1189468</id>
		<title>User:Timmy Foxclaw/About Coordinate Systems and Rotations</title>
		<link rel="alternate" type="text/html" href="https://wiki.secondlife.com/w/index.php?title=User:Timmy_Foxclaw/About_Coordinate_Systems_and_Rotations&amp;diff=1189468"/>
		<updated>2014-04-15T15:13:56Z</updated>

		<summary type="html">&lt;p&gt;Timmy Foxclaw: Number important formulas&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== About Coordinate Systems and Rotations ==&lt;br /&gt;
&lt;br /&gt;
=== The four coordinate systems ===&lt;br /&gt;
&lt;br /&gt;
There are four coordinate systems that are related to LSL programming:&lt;br /&gt;
# World coordinates&lt;br /&gt;
# Region coordinates&lt;br /&gt;
# Object coordinates (root prim coordinates)&lt;br /&gt;
# Child prim coordinates (coordinates relative to the prim that the script is in, or refered to by link number)&lt;br /&gt;
&lt;br /&gt;
The World coordinates refer to the map, and allow to include the sim&lt;br /&gt;
in the coordinates, or refer to void water.&lt;br /&gt;
&lt;br /&gt;
Region coordinates are relative to a given sim.&lt;br /&gt;
The origin is in the South/West corner at height 0.&lt;br /&gt;
The North/East corner then is 256, 256 and a Z coordinate&lt;br /&gt;
for the height up to 4096 meter (on opensim you can go even&lt;br /&gt;
higher).&lt;br /&gt;
&lt;br /&gt;
Object coordinates are relative to the root prim. Hence, if the object&lt;br /&gt;
is moved or rotated then the orientation of a child prim, when given&lt;br /&gt;
in object coordinates, doesn&#039;t change. In LSL &amp;quot;local position&amp;quot; and&lt;br /&gt;
&amp;quot;local rotation&amp;quot; refer to this coordinate system. &amp;quot;local&amp;quot; means&lt;br /&gt;
relative to the root prim.&lt;br /&gt;
&lt;br /&gt;
Prim Coordinates are relative to a given prim. If this prim is the root&lt;br /&gt;
prim then the Prim Coordinates are the same as the Object Coordinates.&lt;br /&gt;
For example, if a child prim is a cube with a size of 1,1,1 and one&lt;br /&gt;
red surface where the center of that surface is at 0.5,0,0 then it will&lt;br /&gt;
still be at 0.5,0,0 no matter how you move or rotate that child prim&lt;br /&gt;
(relative to the other linked prims).&lt;br /&gt;
&lt;br /&gt;
=== Positions ===&lt;br /&gt;
&lt;br /&gt;
A different position of the origin of a coordinate system is easy to understand:&lt;br /&gt;
You can think of positions as vectors that start in the origin of the&lt;br /&gt;
coordinate system that they are given in and end in the point that they&lt;br /&gt;
refer to. While the length of the vector is independent of the rotation of&lt;br /&gt;
the coordinate system, the three coordinates are not; but a mental picture&lt;br /&gt;
of an arrow doesn&#039;t have little numbers for three coordinates, so that&lt;br /&gt;
picture works independent of the rotation too.&lt;br /&gt;
&lt;br /&gt;
Since the rotation of the World Coordinate system and the Region Coordinate&lt;br /&gt;
system is the same (X, Y and Z axis are parallel of both), and since&lt;br /&gt;
World Coordinates aren&#039;t used in many LSL functions to begin with, we&lt;br /&gt;
will ignore World Coordinates for now and only refer to Region Coordinates,&lt;br /&gt;
or say &amp;quot;global&amp;quot; when we mean Region Coordinates.&lt;br /&gt;
&lt;br /&gt;
=== Rotations ===&lt;br /&gt;
&lt;br /&gt;
An LSL rotation internally stores a vector that is the axis around which&lt;br /&gt;
to rotate and the angle of the rotation around that axis.&lt;br /&gt;
Let &#039;&#039;&#039;V&#039;&#039;&#039; = &amp;amp;lt;u, v, w&amp;amp;gt; be the normalized vector (that is, with length 1) around&lt;br /&gt;
which we rotate and let &amp;amp;alpha; (alpha) be the angle around which we have to rotate.&lt;br /&gt;
Then the LSL rotation is a quaternion stored as r = &amp;amp;lt;x, y, z, s&amp;amp;gt; = &amp;amp;lt; &#039;&#039;&#039;V&#039;&#039;&#039; * sin(&amp;amp;alpha;/2), cos(&amp;amp;alpha;/2) &amp;amp;gt;.&lt;br /&gt;
Thus, r.x = x * sin(&amp;amp;alpha;/2), and r.s = cos(&amp;amp;alpha;/2) etc. Note that the quaternion&lt;br /&gt;
is also normalized.&lt;br /&gt;
Also note that there is a duality here because inverting &#039;&#039;&#039;V&#039;&#039;&#039; (making it point the&lt;br /&gt;
opposite way) and inverting the angle gives the same rotation; r and -r have&lt;br /&gt;
different values but are the same rotation.&lt;br /&gt;
Also note that if you don&#039;t rotate at all (&amp;amp;alpha; == 0) then it doesn&#039;t matter&lt;br /&gt;
what axis &#039;&#039;&#039;V&#039;&#039;&#039; you pick, which is apparent because &#039;&#039;&#039;V&#039;&#039;&#039; drops out since sin(0) = 0.&lt;br /&gt;
The quaternion &amp;amp;lt;0, 0, 0, 1&amp;amp;gt; is the ZERO_ROTATION quaternion.&lt;br /&gt;
&lt;br /&gt;
The point of this technical story is to show that for an LSL rotation to&lt;br /&gt;
make sense in terms of orientation, you need to be able to express a vector&lt;br /&gt;
in three coordinates (u, v, w above): the axis around which we rotate is&lt;br /&gt;
expressed relative to the X-, Y- and Z-axes of the coordinate system. Hence,&lt;br /&gt;
it is the orientation of the X-, Y- and Z-axes that defines the meaning&lt;br /&gt;
of a rotation in LSL.&lt;br /&gt;
&lt;br /&gt;
In terms of a mental picture the origin with the (orientation of the) three axis,&lt;br /&gt;
the red X-axis, the green Y-axis and the blue Z-axis is all the reference&lt;br /&gt;
we need, combined with a vector for position or a quaternion for rotation.&lt;br /&gt;
&lt;br /&gt;
When you edit an object, the viewer shows either &#039;World&#039; (meaning Region here) or &#039;Local&#039; axes, but&lt;br /&gt;
really the &#039;World&#039; (region) axes show the wrong origin, shifted to an averaged center&lt;br /&gt;
of the object, because if the origin was drawn at (0, 0, 0) you&#039;d most likely&lt;br /&gt;
not see it. The &#039;Local&#039; ruler shows the correct coordinate system for the&lt;br /&gt;
selected prim as its Prim Coordinate System. Selecting the root prim with&lt;br /&gt;
&#039;Local&#039; ruler on then shows the Object Coordinate System.&lt;br /&gt;
&lt;br /&gt;
=== The dimension of rotations ===&lt;br /&gt;
&lt;br /&gt;
As said before, given some coordinate system, any point in space can&lt;br /&gt;
be represented with a vector. Obviously space is three dimensional,&lt;br /&gt;
and thus vectors exists of three real values:&lt;br /&gt;
one needs three distinct floating point numbers, the x coordinate,&lt;br /&gt;
the y coordinate and the z coordinate to uniquely&lt;br /&gt;
identify a position in a given coordinate system.&lt;br /&gt;
&lt;br /&gt;
However, if one limits oneself to only normalized vectors, vectors&lt;br /&gt;
with a length of one, then those represent all points on the surface&lt;br /&gt;
of a sphere with radius 1.&lt;br /&gt;
A surface is obviously two dimensional, so it should be possible to&lt;br /&gt;
uniquely identify any point on the surface of such a sphere with&lt;br /&gt;
only two floating point numbers.&lt;br /&gt;
&lt;br /&gt;
One might think that selecting just two coordinates of the three of&lt;br /&gt;
the vector will suffice because the third is fixed by the length requirement,&lt;br /&gt;
but that only works for half spheres; for example, if x and y are known&lt;br /&gt;
then z can still be either plus the square root of x squared plus y squared,&lt;br /&gt;
&#039;&#039;or&#039;&#039; minus that value.&lt;br /&gt;
&lt;br /&gt;
Instead, a better choice would be the [http://mathworld.wolfram.com/SphericalCoordinates.html spherical coordinate system]&lt;br /&gt;
and express the unit vectors with the two angular coordinates &amp;amp;phi; (phi) and &amp;amp;theta; (theta),&lt;br /&gt;
where &amp;amp;phi; is the angle between the vector and the positive Z axis, and&lt;br /&gt;
&amp;amp;theta; the angle that the projection of the vector on to the X,Y plane makes&lt;br /&gt;
with the positive X axis. In other words, starting with a unit vector&lt;br /&gt;
along the positive Z-axis, one can obtain the required point on&lt;br /&gt;
the surface of the sphere by first rotating this vector around the&lt;br /&gt;
Y axis (towards the positive X axis) by an angle of &amp;amp;phi; and then rotating&lt;br /&gt;
the result around the Z-axis by an angle of &amp;amp;theta;. Note that in both cases&lt;br /&gt;
the rotations are counter-clockwise when one looks at it from the positive&lt;br /&gt;
side of the axis that one rotates around (towards the origin).&lt;br /&gt;
&lt;br /&gt;
What we just did was expressing a unit vector in terms of two rotations:&lt;br /&gt;
one around the Z axis and one around the Y axis; and indeed every rotation&lt;br /&gt;
can be expressed as two rotations around those two axis (or really, any&lt;br /&gt;
two arbitrary axes, as long as they are independent (not parallel)).&lt;br /&gt;
&lt;br /&gt;
It is therefore possible to represent unit vectors (aka, a &#039;&#039;direction&#039;&#039;)&lt;br /&gt;
with a rotation, as both are two dimensional. The mental picture here is&lt;br /&gt;
that any unit vector can be expressed as some fixed unit vector (for example&lt;br /&gt;
the one pointing along the positive Z axis, but any other would do as well)&lt;br /&gt;
and the rotation needed to turn that &#039;starting vector&#039; into the unit vector&lt;br /&gt;
that one wants to represent. The other way around almost works as well, with the&lt;br /&gt;
exception of the starting vector itself, as that can be expressed by any arbitrary&lt;br /&gt;
rotation around itself, so that information was lost and it is not possible&lt;br /&gt;
to know which of those rotations was used. In fact, any vector&lt;br /&gt;
close to the starting vector would give inaccurate results in the light&lt;br /&gt;
of floating point round off errors and is not a good way to represent&lt;br /&gt;
a rotation. Of course, the two dimensional vector (&amp;amp;theta;, &amp;amp;phi;) would be excellent&lt;br /&gt;
to represent both: the unit vector, as well as any rotation; but LSL stores&lt;br /&gt;
vectors in x, y, z coordinates, not in spherical coordinates.&lt;br /&gt;
&lt;br /&gt;
=== Converting between coordinate systems ===&lt;br /&gt;
&lt;br /&gt;
Consider a child prim of an object that is not the root prim and express&lt;br /&gt;
its position with the vector pos_oc, and its orientation with the rotation rot_oc,&lt;br /&gt;
both relative to the Object Coordinates system.&lt;br /&gt;
&lt;br /&gt;
A script inside that prim can easily obtain those values:&lt;br /&gt;
&lt;br /&gt;
 vector pos_oc = [[llGetLocalPos]]();&lt;br /&gt;
 rotation rot_oc = [[llGetLocalRot]]();&lt;br /&gt;
&lt;br /&gt;
The postfix &#039;_oc&#039; stands for Object Coordinates and is used to make clear&lt;br /&gt;
relative to which coordinate system the x, y and z values of both&lt;br /&gt;
variables are. Remember that also the rotation contains a vector&lt;br /&gt;
(the axis around which we rotate), so from now on we&#039;ll talk about&lt;br /&gt;
&#039;coordinates&#039; relative to a coordinate system for both, the position&lt;br /&gt;
as well as the rotation, where the coordinates refer to the x, y and z&lt;br /&gt;
components of the position and the rotation. For example, the first&lt;br /&gt;
sentence of this paragraph will read &amp;quot;...express its position with the&lt;br /&gt;
vector pos_oc, and its orientation with the rotation rot_oc, &#039;&#039;both in Object Coordinates&#039;&#039;.&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Note that&#039;&#039;&#039; one has to be careful here, because a script in the&lt;br /&gt;
root prim of the object will &#039;&#039;&#039;&#039;&#039;not&#039;&#039;&#039;&#039;&#039; obtain&lt;br /&gt;
Object Coordinates but instead Region Coordinates!&lt;br /&gt;
The reason is that the &#039;Local&#039; functions return coordinates relative to&lt;br /&gt;
the &#039;parent&#039; coordinate system, where the parent of a non-root prim is the root prim,&lt;br /&gt;
but the parent of the root prim is the region (or avatar in case&lt;br /&gt;
of an attachment). The position and rotation of the root prim in&lt;br /&gt;
Object Coordinates is trivial (ZERO_VECTOR and ZERO_ROTATION respectively).&lt;br /&gt;
&lt;br /&gt;
Back to the script in the child prim. It can also easily obtain its position&lt;br /&gt;
and rotation in Region Coordinates:&lt;br /&gt;
&lt;br /&gt;
 vector pos_rc = [[llGetPos]]();&lt;br /&gt;
 rotation rot_rc = [[llGetRot]]();&lt;br /&gt;
&lt;br /&gt;
Both sets, (pos_oc, rot_oc) and (pos_rc, rot_rc) refer to the same thing,&lt;br /&gt;
so it should be possible to convert them into each other.&lt;br /&gt;
&lt;br /&gt;
One can do this by looking at the orientation (position and rotation) of&lt;br /&gt;
one coordinate system relative to the other and expressed&lt;br /&gt;
in the coordinates of that other. The position and rotation&lt;br /&gt;
of the Object Coordinate System relative to the Region Coordinate&lt;br /&gt;
System, and in Region Coordinates, could be obtained as follows:&lt;br /&gt;
&lt;br /&gt;
 vector oc_pos_rc = [[llGetRootPosition]]();&lt;br /&gt;
 rotation oc_rot_rc = [[llGetRootRotation]]();&lt;br /&gt;
&lt;br /&gt;
As indicated by the &#039;_rc&#039; postfix, these are again in Region Coordinates.&lt;br /&gt;
&lt;br /&gt;
Having the relative orientation of the Object Coordinate System in Region Coordinates, it is&lt;br /&gt;
possible to convert Object Coordinates into Region Coordinates. More&lt;br /&gt;
abstractly put, if you have two coordinate systems A and B, and you have&lt;br /&gt;
their relative orientation expressed in A then you can convert orientations&lt;br /&gt;
expressed in B into A.&lt;br /&gt;
&lt;br /&gt;
The formula is as follows:&lt;br /&gt;
&lt;br /&gt;
 &#039;&#039;&#039;vector   pos_A = pos_B * B_rot_A + B_pos_A;            (1)&#039;&#039;&#039;&lt;br /&gt;
 &#039;&#039;&#039;rotation rot_A = rot_B * B_rot_A;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
The order of the multiplications is important; swapping the B_rot_A to the front will not work!&lt;br /&gt;
&lt;br /&gt;
Note that the B_*_A are the position and rotation of the coordinate system B expressed&lt;br /&gt;
in terms of the coordinate system A. The reason that I use the prefix and postfix in&lt;br /&gt;
this order is directly related to the order enforced for rotation multiplications.&lt;br /&gt;
Written this way, the left-hand postfix of a multiplication must match the right-hand prefix&lt;br /&gt;
and conviently short-circuits the notation:&lt;br /&gt;
&lt;br /&gt;
 something_A = something&#039;&#039;&#039;_B&#039;&#039;&#039; * &#039;&#039;&#039;B_&#039;&#039;&#039;rot_A&lt;br /&gt;
&lt;br /&gt;
the two B&#039;s &#039;connect&#039; and drop out (along with the &#039;_rot_&#039;) to give something_ ... A.&lt;br /&gt;
This &#039;&#039;only&#039;&#039; works when the postfix (_A or _B) refers to the coordinate system that the variables&lt;br /&gt;
are in, and the prefix is whatever is described by the variable, possibly another&lt;br /&gt;
coordinate system (B_ in this example).&lt;br /&gt;
&lt;br /&gt;
A complete example script follows:&lt;br /&gt;
&amp;lt;lsl&amp;gt;&lt;br /&gt;
default&lt;br /&gt;
{&lt;br /&gt;
    touch(integer num_detected)&lt;br /&gt;
    {&lt;br /&gt;
        llSay(0, &amp;quot;---------&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
        // Get the pos and rot in Object Coordinates.&lt;br /&gt;
        vector pos_oc = llGetLocalPos();&lt;br /&gt;
        rotation rot_oc = llGetLocalRot();&lt;br /&gt;
        &lt;br /&gt;
        // Fix these values when this script is in the root prim!&lt;br /&gt;
        if (llGetLinkNumber() &amp;lt;= 1)&lt;br /&gt;
        {&lt;br /&gt;
            pos_oc = ZERO_VECTOR;&lt;br /&gt;
            rot_oc = ZERO_ROTATION;&lt;br /&gt;
        }&lt;br /&gt;
        &lt;br /&gt;
        // Get the pos and rot in Region Coordinates.&lt;br /&gt;
        vector pos_rc = llGetPos();&lt;br /&gt;
        rotation rot_rc = llGetRot();&lt;br /&gt;
        &lt;br /&gt;
        // Get the pos and rot of the Object Coordinate System in Region Coordinates.&lt;br /&gt;
        vector oc_pos_rc = llGetRootPosition();&lt;br /&gt;
        rotation oc_rot_rc = llGetRootRotation();&lt;br /&gt;
        &lt;br /&gt;
        // Print the values of the positions (the rotations are too hard to understand).&lt;br /&gt;
        llSay(0, &amp;quot;oc_pos_rc = &amp;quot; + (string)oc_pos_rc);&lt;br /&gt;
        llSay(0, &amp;quot;pos_os = &amp;quot; + (string)pos_os);&lt;br /&gt;
        llSay(0, &amp;quot;pos_rc = &amp;quot; + (string)pos_rc);&lt;br /&gt;
        &lt;br /&gt;
        // Calculate pos_rc and rot_rc from pos_oc and rot_oc : converting between _oc and _rc.&lt;br /&gt;
        vector   pos2_rc = pos_oc * oc_rot_rc + oc_pos_rc;&lt;br /&gt;
        rotation rot2_rc = rot_oc * oc_rot_rc;&lt;br /&gt;
        &lt;br /&gt;
        // Print the result for the position, and show the difference with what llGetPos() and llGetRot() returned.&lt;br /&gt;
        llSay(0, &amp;quot;pos2_rc = &amp;quot; + (string)pos2_rc);&lt;br /&gt;
        // These values should be ZERO_VECTOR and ZERO_ROTATION (or -ZERO_ROTATION).&lt;br /&gt;
        llSay(0, &amp;quot;pos_rc - pos2_rc = &amp;quot; + (string)(pos_rc - pos2_rc));&lt;br /&gt;
        llSay(0, &amp;quot;rot_rc / rot2_rc = &amp;quot; + (string)(rot_rc / rot2_rc));&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/lsl&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Obviously there is no preference for one coordinate system over the other for this conversion;&lt;br /&gt;
one can equally as well convert orientations in A into B:&lt;br /&gt;
&lt;br /&gt;
 vector   pos_B = pos_A * A_rot_B + A_pos_B;&lt;br /&gt;
 rotation rot_B = rot_A * A_rot_B;&lt;br /&gt;
&lt;br /&gt;
The question arises then how to obtain the A_*_B values; there is no LSL function that returns directly&lt;br /&gt;
the position or rotation of the region relative to a prim (aka, rc_*_oc).&lt;br /&gt;
&lt;br /&gt;
Intuitively one would say that it has to be possible to express A_*_B in B_*_A on grounds of symmetry, and that&lt;br /&gt;
is indeed the case.&lt;br /&gt;
&lt;br /&gt;
To show how this works, lets just take the formula for pos_A and rot_A (see (1) above) and rework&lt;br /&gt;
them to get pos_B and rot_B on the left-hand side. This results first in&lt;br /&gt;
&lt;br /&gt;
 pos_B * B_rot_A = pos_A - B_pos_A&lt;br /&gt;
 rot_B * B_rot_A = rot_A&lt;br /&gt;
&lt;br /&gt;
Then divide both sides by B_rot_A to get:&lt;br /&gt;
&lt;br /&gt;
 pos_B = pos_A / B_rot_A - B_pos_A / B_rot_A&lt;br /&gt;
 rot_B = rot_A / B_rot_A&lt;br /&gt;
&lt;br /&gt;
from which we can conclude that&lt;br /&gt;
&lt;br /&gt;
 &#039;&#039;&#039;A_pos_B = - B_pos_A / B_rot_A                           (2)&#039;&#039;&#039;&lt;br /&gt;
 &#039;&#039;&#039;A_rot_B = ZERO_ROTATION / B_rot_A&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Note how A_rot_B is the inverse of B_rot_A: A_rot_B * B_rot_A = ZERO_ROTATION.&lt;br /&gt;
As per our notation convention you&#039;d expect A_rot_B * B_rot_A to be A_rot_A, and that is&lt;br /&gt;
actually the case as A_rot_A means the relative orientation of coordinate system A&lt;br /&gt;
expressed in A&#039;s coordinates, which is the trivial ZERO_VECTOR and ZERO_ROTATION as&lt;br /&gt;
we saw before for the root prim orientation expressed in Object Coordinates.&lt;br /&gt;
&lt;br /&gt;
And for fun, note that if we do this inversion again we get:&lt;br /&gt;
&lt;br /&gt;
 B_pos_A = - A_pos_B / A_rot_B = - (- B_pos_A / B_rot_A) / (ZERO_ROTATION / B_rot_A) = B_pos_A / B_rot_A * B_rot_A = B_pos_A&lt;br /&gt;
 B_rot_A = ZERO_ROTATION / A_rot_B = ZERO_ROTATION / (ZERO_ROTATION / B_rot_A) = B_rot_A&lt;br /&gt;
&lt;br /&gt;
as expected.&lt;br /&gt;
&lt;br /&gt;
We can now also convert Region Coordinates to Object Coordinates.&lt;br /&gt;
&lt;br /&gt;
One could first calculate,&lt;br /&gt;
&lt;br /&gt;
 vector rc_pos_oc = - llGetRootPosition() / llGetRootRotation();&lt;br /&gt;
 rotation rc_rot_oc = ZERO_ROTATION / llGetRootRotation();&lt;br /&gt;
&lt;br /&gt;
and then convert as usual:&lt;br /&gt;
&lt;br /&gt;
 vector   pos_oc = pos_rc * rc_rot_oc + rc_pos_oc;&lt;br /&gt;
 rotation rot_oc = rot_rc * rc_rot_oc;&lt;br /&gt;
&lt;br /&gt;
or if you don&#039;t want to calculate the intermediate rc_*_oc values, you could do immediately:&lt;br /&gt;
&lt;br /&gt;
 vector   pos_oc = (pos_rc - llGetRootPosition()) / llGetRootRotation();&lt;br /&gt;
 rotation rot_oc = rot_rc / llGetRootRotation();&lt;br /&gt;
&lt;br /&gt;
To verify this, you could extend the above script with&lt;br /&gt;
&amp;lt;lsl&amp;gt;&lt;br /&gt;
        // Calculate pos_oc and rot_oc from pos_rc and rot_rc.&lt;br /&gt;
        vector   pos2_oc = (pos_rc - llGetRootPosition()) / llGetRootRotation();&lt;br /&gt;
        rotation rot2_oc = rot_rc / llGetRootRotation();&lt;br /&gt;
        &lt;br /&gt;
        llSay(0, &amp;quot;pos2_oc = &amp;quot; + (string)pos2_oc);&lt;br /&gt;
        // These values should again be ZERO_VECTOR and +/- ZERO_ROTATION.&lt;br /&gt;
        llSay(0, &amp;quot;pos_oc - pos2_oc = &amp;quot; + (string)(pos_oc - pos2_oc));&lt;br /&gt;
        llSay(0, &amp;quot;rot_oc / rot2_oc = &amp;quot; + (string)(rot_oc / rot2_oc));&lt;br /&gt;
&amp;lt;/lsl&amp;gt;&lt;br /&gt;
&lt;br /&gt;
More in general, if you want to convert from B to A, but you only have A_*_B instead of B_*_A, then (combining (1) and (2))&lt;br /&gt;
you can do:&lt;br /&gt;
&lt;br /&gt;
 &#039;&#039;&#039;vector   pos_A = (pos_B - A_pos_B) / A_rot_B;           (3)&#039;&#039;&#039;&lt;br /&gt;
 &#039;&#039;&#039;rotation rot_A = rot_B / A_rot_B;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
=== Cascading coordinate systems ===&lt;br /&gt;
&lt;br /&gt;
Imagine you have a castle object where the floor is the root prim. Everything is linked because you&lt;br /&gt;
want it to be easy to move the castle around. One of the child prims is a sculpty representing the hinges&lt;br /&gt;
around which you want to rotate a large gate. The gate has a rotating wheel on it.&lt;br /&gt;
&lt;br /&gt;
You want that the object (castle) to keep working when it is moved and/or rotated, but also when it is edited&lt;br /&gt;
and the hinges are moved and/or rotated. This means that the state of the gate prims&lt;br /&gt;
must be &#039;&#039;stored&#039;&#039; relative to the hinges, which is by far the easiest thing to do to begin with,&lt;br /&gt;
after all, the gate rotates around the hinges and has no relation with the rest of the castle.&lt;br /&gt;
&lt;br /&gt;
Hence, we have the Region Coordinate System, the Object Coordinate System (the castle) and the Hinges Coordinate System.&lt;br /&gt;
The latter is our first example of a Prim Coordinates System, but I&#039;ll use the postfix &#039;_hc&#039; for &amp;quot;Hinges Coordinates&amp;quot;&lt;br /&gt;
instead of &#039;_pc&#039;. Finally we have the Spill Coordinate System (or Gate Coordinates) where the spill is a prim&lt;br /&gt;
around which we want to rotate the wheel, and I&#039;ll use &#039;_sc&#039; as postfix for that.&lt;br /&gt;
&lt;br /&gt;
The variables used then would be an orientation for the wheel in *_sc coordinates, the orientation of the spill,&lt;br /&gt;
and other gate prims, in *_hc coordinates and the orientation of the hinges in *_oc coordinates. Finally we could&lt;br /&gt;
have variables for the orientation of the castle (root prim) in *_rc coordinates of course.&lt;br /&gt;
&lt;br /&gt;
 vector   castle_pos_rc; // The position of the castle in Region Coordinates.&lt;br /&gt;
 rotation castle_rot_rc; // The rotation of the castle in Region Coordinates.&lt;br /&gt;
 &lt;br /&gt;
 vector   hinges_pos_oc; // The position of the hinges in Object Coordinates.&lt;br /&gt;
 rotation hinges_rot_oc; // The rotation of the hinges in Object Coordinates.&lt;br /&gt;
 &lt;br /&gt;
 vector   spill_pos_hc;  // The position of the spill in Hinges Coordinates.&lt;br /&gt;
 rotation spill_rot_hc;  // The rotation of the spill in Hinges Coordinates.&lt;br /&gt;
 &lt;br /&gt;
 vector   wheel_pos_sc;  // The position of the wheel in Spill Coordinates.&lt;br /&gt;
 rotation wheel_rot_sc;  // The rotation of the wheel in Spill Coordinates.&lt;br /&gt;
&lt;br /&gt;
Now because we used existing prims orientations as coordinate system for the next prim, the position&lt;br /&gt;
and rotation of those prims &#039;&#039;are&#039;&#039; the position and rotation of that coordinate system.&lt;br /&gt;
Just like before we saw that llGetPos/llGetRot returns the global orientation of the root prim&lt;br /&gt;
when used in a script in the root prim, while llGetRootPos/llGetRootRot gave us the relative&lt;br /&gt;
orientation of the Object Coordinate System in Region Coordinates, but is in fact the same as&lt;br /&gt;
what llGetPos/llGetRot in the root prim returns: the position/rotation of the root prim &#039;&#039;&#039;is&#039;&#039;&#039;&lt;br /&gt;
the orientation of the Object Coordinate System relative to the Region.&lt;br /&gt;
&lt;br /&gt;
Likewise, in this case, castle_*_rc is the relative orientation of the Object Coordinate System&lt;br /&gt;
in Region Coordinates as well as the orientation of the root prim in Region Coordinates; they&lt;br /&gt;
are the same thing.&lt;br /&gt;
&lt;br /&gt;
The same then applies to the *_oc variables, which we defined as the orientation of&lt;br /&gt;
the hinges in Object Coordinates, but at the same time are the relative orientation&lt;br /&gt;
of the Hinges Coordinate System in Object Coordinates. The *_hc variables are the&lt;br /&gt;
orientation of spill in Hinges Coordinates, but also the relative orientation of&lt;br /&gt;
the Spill Coordinates in Hinges Coordinates.&lt;br /&gt;
&lt;br /&gt;
Lets write it out using the same notation convention as used above, then&lt;br /&gt;
we have:&lt;br /&gt;
&lt;br /&gt;
 vector   oc_pos_rc = castle_pos_rc; // The Object Coordinate System orientation in Region Coordinates.&lt;br /&gt;
 rotation oc_rot_rc = castle_rot_rc;&lt;br /&gt;
 &lt;br /&gt;
 vector   hc_pos_oc = hinges_pos_oc; // The Hinges Coordinate System orientation in Object Coordinates.&lt;br /&gt;
 rotation hc_rot_oc = hinges_rot_oc;&lt;br /&gt;
 &lt;br /&gt;
 vector   sc_pos_hc = spill_pos_hc;  // The Spill Coordinate System orientation in Hinges Coordinates.&lt;br /&gt;
 rotation sc_rot_hc = spill_rot_hc;&lt;br /&gt;
&lt;br /&gt;
It will therefore probably not surprise you that&lt;br /&gt;
&lt;br /&gt;
 vector   hc_pos_rc = hc_pos_oc * oc_rot_rc + oc_pos_rc; // The Hinges Coordinate System orientation in Region Coordinates.&lt;br /&gt;
 rotation hc_rot_rc = hc_rot_oc * oc_rot_rc;&lt;br /&gt;
 &lt;br /&gt;
 vector   sc_pos_rc = sc_pos_hc * hc_rot_rc + hc_pos_rc; // The Spill Coordinate System orientation in Region Coordinates.&lt;br /&gt;
 rotation sc_rot_rc = sc_rot_hc * hc_rot_rc;&lt;br /&gt;
&lt;br /&gt;
And finally, using the latter, we can express the wheel orientation in region coordinates:&lt;br /&gt;
&lt;br /&gt;
 vector   wheel_pos_rc = wheel_pos_sc * sc_rot_rc + sc_pos_rc;&lt;br /&gt;
 rotation wheel_rot_rc = wheel_rot_sc * sc_rot_rc;&lt;br /&gt;
&lt;br /&gt;
Although this was nothing else but applying the coordinate system conversion formula ((1)) three times,&lt;br /&gt;
it might give some insight to get rid of the intermediate variables and express the wheel&lt;br /&gt;
orientation in region coordinates without them, giving:&lt;br /&gt;
&lt;br /&gt;
 wheel_pos_rc = ((wheel_pos_sc * sc_rot_hc + sc_pos_hc) * hc_rot_oc + hc_pos_oc) * oc_rot_rc + oc_pos_rc&lt;br /&gt;
 wheel_rot_rc = wheel_rot_sc * sc_rot_hc * hc_rot_oc * oc_rot_rc&lt;br /&gt;
&lt;br /&gt;
=== Applying rotations and translations ===&lt;br /&gt;
&lt;br /&gt;
Applying rotations and translations (moving) is very much the same as coordinate system transformations described above.&lt;br /&gt;
To show this consider the following: imagine you have a prim &#039;pa&#039; with its own coordinate system A.&lt;br /&gt;
Then it trivially has position ZERO_VECTOR and rotation ZERO_ROTATION relative to A, per definition.&lt;br /&gt;
&lt;br /&gt;
 vector   pa_pos_A = ZERO_VECTOR;&lt;br /&gt;
 rotation pa_rot_A = ZERO_ROTATION;&lt;br /&gt;
&lt;br /&gt;
Now consider a prim &#039;pb&#039; that has some relative position pb_pos_A and rotation pb_rot_A given in A coordinates.&lt;br /&gt;
For example,&lt;br /&gt;
&lt;br /&gt;
 vector   pb_pos_A = &amp;lt;0.5, 0.6, 0.7&amp;gt;;&lt;br /&gt;
 rotation pb_rot_A = &amp;lt;0.38, 0.26, 0.34, 0.82&amp;gt;;&lt;br /&gt;
&lt;br /&gt;
Note that 0.38&amp;amp;sup2; + 0.26&amp;amp;sup2; + 0.34&amp;amp;sup2; + 0.82&amp;amp;sup2; = 1, as it must be since rotations are normalized.&lt;br /&gt;
&lt;br /&gt;
As seen before, the orientation of pb relative to pa is the same as the orientation of pb relative to A,&lt;br /&gt;
and the same as the orientation of B relative to A. pa and A are interchangeable as long as pa has&lt;br /&gt;
ZERO_VECTOR and ZERO_ROTATION relative to A. Thus, with B being the coordinate system where pb currently&lt;br /&gt;
is, we also have:&lt;br /&gt;
&lt;br /&gt;
 vector   B_pos_A = pb_pos_A; // The orientation of coordinate system B, in coordinates of A.&lt;br /&gt;
 rotation B_rot_A = pb_rot_A;&lt;br /&gt;
&lt;br /&gt;
Now suppose we want move the prim pa (without moving the coordinate system A),&lt;br /&gt;
by applying the translation &#039;B_pos_A&#039;, after all a translation is stored in a vector&lt;br /&gt;
and B_pos_A is a vector. Likewise, we want to rotate pa (again without influencing A)&lt;br /&gt;
by applying the rotation B_rot_A. Then the most logical order to this in is by&lt;br /&gt;
&#039;&#039;first&#039;&#039; applying the rotation and &#039;&#039;then&#039;&#039; applying the translation, because then&lt;br /&gt;
the meaning of the translation is preserved and will match the meaning of B_pos_A&lt;br /&gt;
in that pa will end up where pb is now. If you&#039;d first apply the translation so that&lt;br /&gt;
pa ends up where pb is, and then apply the rotation (around A!) then pa would swoop&lt;br /&gt;
around the origin of A and move away from its desired position.&lt;br /&gt;
&lt;br /&gt;
Doing this correctly should leave us with pa_pos_A == pb_pos_A and pa_rot_A == pb_rot_A,&lt;br /&gt;
so that pa ended up precisely where pb is now. We can&#039;t just assign those values&lt;br /&gt;
however, because we&#039;re looking for a formula that works in general; a way to apply&lt;br /&gt;
B_rot_A and then B_pos_A to any prim with -say- orientation pc_pos_A, pc_rot_A.&lt;br /&gt;
&lt;br /&gt;
Thus, first we apply the rotation:&lt;br /&gt;
&lt;br /&gt;
 pc_rot_A *= B_rot_A;&lt;br /&gt;
 pc_pos_A *= B_rot_A;&lt;br /&gt;
&lt;br /&gt;
And then apply the translation:&lt;br /&gt;
&lt;br /&gt;
 pc_pos_A += B_pos_A;&lt;br /&gt;
&lt;br /&gt;
Now lets check if indeed this would cause pa to end up where pb is.&lt;br /&gt;
The effect on pa_*_A would be:&lt;br /&gt;
&lt;br /&gt;
 pa_rot_A = pa_rot_A * B_rot_A = ZERO_ROTATION * B_rot_A = B_rot_A = pb_rot_A;&lt;br /&gt;
 pa_pos_A = pa_pos_A * B_rot_A = ZERO_VECTOR * B_rot_A = ZERO_VECTOR;&lt;br /&gt;
 &lt;br /&gt;
 and then the translation&lt;br /&gt;
 &lt;br /&gt;
 pa_pos_A = pa_pos_A + B_pos_A = ZERO_VECTOR + B_pos_A = B_pos_A = pb_pos_A;&lt;br /&gt;
&lt;br /&gt;
So yes, pa_*_A ends up as pb_*_A!&lt;br /&gt;
&lt;br /&gt;
The real test however would be if we first applied some transformation to pa&lt;br /&gt;
to bring it to some arbitrary orientation (aka, pc), then apply the transformation&lt;br /&gt;
B_rot_A,B_pos_A and then reverse the first transformation but now relative to B,&lt;br /&gt;
and then find that we indeed end up at pb.&lt;br /&gt;
&lt;br /&gt;
Let us first define a &#039;transformation&#039;, which exists of a vector for the&lt;br /&gt;
translation and a rotation for the rotation. We will have two transformations&lt;br /&gt;
during this test: t1: pa -&amp;gt; pc, and t2: pa -&amp;gt; pb.&lt;br /&gt;
&lt;br /&gt;
As we just saw (or we hope this is going to be the case), t2 can be defined as:&lt;br /&gt;
&lt;br /&gt;
 vector   t2_translation = B_pos_A;&lt;br /&gt;
 rotation t2_rotation = B_rot_A;&lt;br /&gt;
&lt;br /&gt;
where as t1 is arbitrary, just some values t1_translation and t1_rotation.&lt;br /&gt;
&lt;br /&gt;
Applying t1 to pa, we get (this is thus the same as above, but now with the &#039;t1&#039; notation):&lt;br /&gt;
&lt;br /&gt;
 pa_rot_A *= t1_rotation;&lt;br /&gt;
 pa_pos_A *= t1_rotation;&lt;br /&gt;
 pa_pos_A += t1_translation;&lt;br /&gt;
&lt;br /&gt;
Next we apply translation t2 to that:&lt;br /&gt;
&lt;br /&gt;
 pa_rot_A *= t2_rotation;&lt;br /&gt;
 pa_pos_A *= t2_rotation;&lt;br /&gt;
 pa_pos_A += t2_translation;&lt;br /&gt;
&lt;br /&gt;
Finally we want to reverse t1, but in the coordinate system of B.&lt;br /&gt;
Therefore, we first convert our coordinates to that of B (formula (1)):&lt;br /&gt;
&lt;br /&gt;
 pa_pos_B = pa_pos_A * A_rot_B + A_pos_B;&lt;br /&gt;
 pa_rot_B = pa_rot_A * A_rot_B;&lt;br /&gt;
&lt;br /&gt;
where (formula (2))&lt;br /&gt;
&lt;br /&gt;
 A_pos_B = - B_pos_A / B_rot_A;&lt;br /&gt;
 A_rot_B = ZERO_ROTATION / B_rot_A;&lt;br /&gt;
&lt;br /&gt;
and then reverse t1. Note now we have to do the translation first!&lt;br /&gt;
&lt;br /&gt;
 pa_pos_B -= t1_translation;&lt;br /&gt;
 pa_pos_B /= t1_rotation;&lt;br /&gt;
 pa_rot_B /= t1_rotation;&lt;br /&gt;
&lt;br /&gt;
And if everything worked out then pa now should be at ZERO_VECTOR, ZERO_ROTATION relative to B!&lt;br /&gt;
&lt;br /&gt;
As pa_pos_A,pa_rot_A started as ZERO_VECTOR,ZERO_ROTATION, the first step&lt;br /&gt;
of applying t1 resulted in pa_rot_A = t1_rotation and pa_pos_A = t1_translation.&lt;br /&gt;
&lt;br /&gt;
After applying t2 we get pa_rot_A = t1_rotation * t2_rotation, and pa_pos_A = t1_translation * t2_rotation + t2_translation.&lt;br /&gt;
&lt;br /&gt;
Converting that to B gives&lt;br /&gt;
&lt;br /&gt;
 pa_pos_B = (t1_translation * t2_rotation + t2_translation) * A_rot_B + A_pos_B&lt;br /&gt;
 pa_rot_B = (t1_rotation * t2_rotation) * A_rot_B&lt;br /&gt;
&lt;br /&gt;
where, remembering that t2_translation = B_pos_A and t2_rotation = B_rot_A,&lt;br /&gt;
&lt;br /&gt;
 A_pos_B = - B_pos_A / B_rot_A = - t2_translation / t2_rotation&lt;br /&gt;
 A_rot_B = ZERO_ROTATION / B_rot_A = ZERO_ROTATION / t2_rotation&lt;br /&gt;
&lt;br /&gt;
so that we get&lt;br /&gt;
&lt;br /&gt;
 pa_pos_B = (t1_translation * t2_rotation + t2_translation) / t2_rotation - t2_translation / t2_rotation = t1_translation&lt;br /&gt;
 pa_rot_B = (t1_rotation * t2_rotation) / t2_rotation = t1_rotation&lt;br /&gt;
&lt;br /&gt;
and finally reversing t1 gives:&lt;br /&gt;
&lt;br /&gt;
 pa_pos_B = (t1_translation - t1_translation) / t1_rotation = ZERO_VECTOR&lt;br /&gt;
 pa_rot_B = t1_rotation / t1_rotation = ZERO_ROTATION&lt;br /&gt;
&lt;br /&gt;
So that we can conclude that if you have two prims pa and pb, each representing their own coordinate system A and B respectively,&lt;br /&gt;
and you express the orientation of B relative to A as the pair (B_pos_A, B_rot_A) &amp;amp;mdash; then the following holds.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;The transformation pair (t_translation, t_rotation) equals (B_pos_A, B_rot_A) as long as you first apply the rotation and then the translation while working in the coordinate system of A&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
The latter is also very practical, because you normally won&#039;t know&lt;br /&gt;
anything about the target coordinate system B until you actually did the transformation.&lt;br /&gt;
&lt;br /&gt;
Now remember that we found that in order to convert variables from being relative to a coordinate system B to a coordinate system A,&lt;br /&gt;
we did (formula (1)):&lt;br /&gt;
&lt;br /&gt;
 pos_A = pos_B * B_rot_A + B_pos_A&lt;br /&gt;
 rot_A = rot_B * B_rot_A&lt;br /&gt;
&lt;br /&gt;
which is thus exactly the same as first applying the rotation t1_rotation and then the translation t1_translation&lt;br /&gt;
on the pair (pos_B, rot_B) where that pair is relative to A! That isn&#039;t too weird because if you consider a prim&lt;br /&gt;
in the origin of A with no rotation, aka (ZERO_VECTOR, ZERO_ROTATION) relative to A and then apply the transformation&lt;br /&gt;
then you expect to end up in the origin of B with no rotation relative to B. Aka pos_B = ZERO_VECTOR and rot_B = ZERO_ROTATION.&lt;br /&gt;
So now work backwards: assume you already have the prim in B like that, then what are its coordinates in A?&lt;br /&gt;
That would be the above conversion thus, with pos_B = ZERO_VECTOR and rot_B = ZERO_ROTATION.&lt;br /&gt;
&lt;br /&gt;
Hence, doing the conversion with ZERO as input gives the same results as doing the t transformation with ZERO as input!&lt;br /&gt;
And the final formula for a transformation just looks exactly the same:&lt;br /&gt;
&lt;br /&gt;
 &#039;&#039;&#039;target_pos_A = source_pos_A * t_rotation + t_translation        (4)&#039;&#039;&#039;&lt;br /&gt;
 &#039;&#039;&#039;target_rot_A = source_rot_A * t_rotation&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
=== Scaling coordinate systems ===&lt;br /&gt;
&lt;br /&gt;
Apart from rotation and translation, there is one more linear operator that can be used to convert&lt;br /&gt;
between coordinate systems: scaling.&lt;br /&gt;
&lt;br /&gt;
Let A_pos_B be the position of the origin of A in the coordinates of B. Let A_rot_B be the orientation of A within B,&lt;br /&gt;
and let the vector A_B_scale be the scaling factors for each axes. Scaling has no influence on the origin of&lt;br /&gt;
a coordinate system, but it matters for the rotation when the scaling factors per axis are different.&lt;br /&gt;
&lt;br /&gt;
I think that a good choice is scale first and rotate afterwards. Because that leaves the values&lt;br /&gt;
of the coordinates of A_rot_B alone: it remains the rotation as defined in B, which makes sense&lt;br /&gt;
since it is written in the coordinates of B. However, it&#039;s just a matter of choice really, which&lt;br /&gt;
in this case will deform B_rot_A instead of A_rot_B. I can imagine that the choice might depend&lt;br /&gt;
on the application.&lt;br /&gt;
&lt;br /&gt;
Chosing that we first scale, a point at pos_A is mapped onto the point pos_B as follows:&lt;br /&gt;
&lt;br /&gt;
 pos_B = (S * pos_A) * A_rot_B + A_pos_B&lt;br /&gt;
&lt;br /&gt;
where S is a 3x3 matrix with as diagonal the vector A_B_scale (and the rest zeroes).&lt;br /&gt;
Note that when each element of A_B_scale is the same then you can just use a scalar for S, equal to the scale of each axis.&lt;br /&gt;
&lt;br /&gt;
Whether or not S is a matrix or a scalar, lets just replace it with &#039;A_B_scale&#039; here. Just keep in&lt;br /&gt;
mind that if it isn&#039;t a scalar then this won&#039;t work in LSL directly: then you&#039;ll have to split&lt;br /&gt;
it up in three different code lines because LSL doesn&#039;t support scaling or matrices.&lt;br /&gt;
&lt;br /&gt;
  pos_B = pos_A;&lt;br /&gt;
  pos_B.x *= A_B_scale.x;  // Scale&lt;br /&gt;
  pos_B.y *= A_B_scale.y;&lt;br /&gt;
  pos_B.z *= A_B_scale.z;&lt;br /&gt;
  pos_B *= A_rot_B;        // Rotate&lt;br /&gt;
  pos_B += A_pos_B;        // Translate&lt;br /&gt;
&lt;br /&gt;
Note that the inverse of S, 1/S, is a 3x3 matrix with as diagonal the inverse of each element of A_B_scale.&lt;br /&gt;
We will either write &#039;B_A_scale&#039;, or divide by &#039;A_B_scale&#039; in our notation.&lt;br /&gt;
&lt;br /&gt;
Therefore our notation becomes:&lt;br /&gt;
&lt;br /&gt;
 pos_B = (&#039;A_B_scale&#039; * pos_A) * A_rot_B + A_pos_B&lt;br /&gt;
&lt;br /&gt;
Since A and B are arbitrary, we would expect the same formula to hold when swapping A and B:&lt;br /&gt;
&lt;br /&gt;
 pos_A = (&#039;B_A_scale&#039; * pos_B) * B_rot_A + B_pos_A&lt;br /&gt;
&lt;br /&gt;
Solving pos_B from that by subtracting B_pos_A from both sides, then dividing both sides by B_rot_A&lt;br /&gt;
and finally left multiplying both sides with the inverse of B_A_scale, gives:&lt;br /&gt;
&lt;br /&gt;
 pos_B = &#039;A_B_scale&#039; * ((pos_A - B_pos_A) / B_rot_A) = &#039;A_B_scale&#039; * (pos_A / B_rot_A) - &#039;A_B_scale&#039; * (B_pos_A / B_rot_A)&lt;br /&gt;
&lt;br /&gt;
from which we can conclude (by setting pos_A to ZERO_VECTOR) that&lt;br /&gt;
&lt;br /&gt;
 A_pos_B = -&#039;A_B_scale&#039; * (B_pos_A / B_rot_A)&lt;br /&gt;
&lt;br /&gt;
Solving B_pos_A from that by left multiplying both sides with -B_A_scale and then right multiplying both sides with B_rot_A, gives:&lt;br /&gt;
&lt;br /&gt;
 B_pos_A = - (&#039;B_A_scale&#039; * A_pos_B) * B_rot_A&lt;br /&gt;
&lt;br /&gt;
By setting A_pos_B to ZERO_VECTOR, and this B_pos_A too, we can also conclude that&lt;br /&gt;
&lt;br /&gt;
 (&#039;A_B_scale&#039; * pos_A) * A_rot_B = &#039;A_B_scale&#039; * (pos_A / B_rot_A)&lt;br /&gt;
&lt;br /&gt;
If &#039;A_B_scale&#039; is a scalar, so that the order of multiplication doesn&#039;t matter,&lt;br /&gt;
then the scale just cancels on both sides and we find the conversion that we&lt;br /&gt;
found before, that B_rot_A is the inverse of A_rot_B. However, if A_B_scale&lt;br /&gt;
is a diagonal matrix then the order matters and the brackets are significant.&lt;br /&gt;
&lt;br /&gt;
There is no way to let pos_A drop out: we cannot write B_rot_A as function&lt;br /&gt;
of A_B_scale and A_rot_B.&lt;br /&gt;
&lt;br /&gt;
The conclusion is that a scale is asymmetrical: if you choose that a scale A_B_scale&lt;br /&gt;
means that you first apply the scale on a vector in A and then rotate, then&lt;br /&gt;
that automatically implies that when going from B to A you first have to rotate&lt;br /&gt;
and &#039;&#039;then&#039;&#039; apply the scale.&lt;br /&gt;
&lt;br /&gt;
To make the choice clear in the name, I suggest to put an &#039;r&#039; in front of the&lt;br /&gt;
coordinate system that need rotation to be applied first. &lt;br /&gt;
&lt;br /&gt;
In summary, if A_rB_scale is defined as&lt;br /&gt;
&lt;br /&gt;
 &#039;&#039;&#039;pos_B = (&#039;A_rB_scale&#039; * pos_A) * A_rot_B + A_pos_B      (5)&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
then that implies that rB_A_scale has to be applied after rotation.&lt;br /&gt;
Note this means braces, NOT changing the left- or right- side of&lt;br /&gt;
multiplications! Matrices (scales) are always on the left side&lt;br /&gt;
of a vector, while rotations are always on the right side. Thus we get: &lt;br /&gt;
&lt;br /&gt;
 &#039;&#039;&#039;pos_A = &#039;rB_A_scale&#039; * (pos_B * B_rot_A) + B_pos_A      (6)&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
If now we solve pos_B from the latter, we get:&lt;br /&gt;
&lt;br /&gt;
 pos_B = (&#039;A_rB_scale&#039; * (pos_A - B_pos_A)) / B_rot_A = (&#039;A_rB_scale&#039; * pos_A) / B_rot_A - (&#039;A_rB_scale&#039; * B_pos_A) / B_rot_A&lt;br /&gt;
&lt;br /&gt;
Hence&lt;br /&gt;
&lt;br /&gt;
 &#039;&#039;&#039;B_pos_A = - &#039;rB_A_scale&#039; * (A_pos_B / A_rot_B)          (7)&#039;&#039;&#039;&lt;br /&gt;
 &#039;&#039;&#039;B_rot_A = ZERO_ROTATION / A_rot_B&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
and&lt;br /&gt;
&lt;br /&gt;
 &#039;&#039;&#039;A_pos_B = - (&#039;A_rB_scale&#039; * B_posA) / B_rot_A           (8)&#039;&#039;&#039;&lt;br /&gt;
 &#039;&#039;&#039;A_rot_B = ZERO_ROTATION / B_rot_A&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Note how these two sets condense into the same thing when the scale is a scalar,&lt;br /&gt;
but also when A_rot_B and B_rot_A are ZERO_ROTATION. In fact, when the rotation&lt;br /&gt;
involved is of the special case of one or more rotations of 90 degrees around&lt;br /&gt;
any of the axes, so that the rotation merely swaps axes, one could define&lt;br /&gt;
the inverse of A_B_scale by applying that rotation to that vector (swapping&lt;br /&gt;
the scaling factors), next to inverting each factor individually.&lt;br /&gt;
That is a different way of how we defined B_A_scale, but it would collapse&lt;br /&gt;
the two sets into one for that special set of rotations. I&#039;m using that trick&lt;br /&gt;
in the example script below.&lt;br /&gt;
&lt;br /&gt;
=== Direction vectors ===&lt;br /&gt;
&lt;br /&gt;
A &#039;direction&#039; is a normalized vector (its length is 1), or unit vector, where only the direction&lt;br /&gt;
it points to is important.&lt;br /&gt;
&lt;br /&gt;
Of course, in the light of rotations between coordinate systems, also the directions&lt;br /&gt;
are relative to some coordinate system.&lt;br /&gt;
&lt;br /&gt;
As stated before, using some &#039;starting&#039; unit vector a rotation can be expressed&lt;br /&gt;
as a direction by applying the rotation to a starting vector. Reversing this&lt;br /&gt;
process runs into floating point round off errors however, or might even have lost&lt;br /&gt;
all information of the rotation when we rotate around the starting vector itself.&lt;br /&gt;
&lt;br /&gt;
There is a better way to convert directions (back) to a rotation however: by using &#039;&#039;two&#039;&#039;&lt;br /&gt;
directions that are perpendicular, each having a unit vector along one of the axes&lt;br /&gt;
as starting vector. That way there is always at least one vector enough rotated away&lt;br /&gt;
from the actual rotation axis in order not to suffer from (too much) information loss.&lt;br /&gt;
&lt;br /&gt;
For example, let us use the unit vector along the positive X axis and the unit vector&lt;br /&gt;
along the positive Z axis. In LSL those are often called fwd and up respectively.&lt;br /&gt;
Furthermore, lets work in a coordinate system A. Then we have the &#039;starting&#039; vectors:&lt;br /&gt;
&lt;br /&gt;
 &#039;&#039;&#039;vector A_fwd_A  = &amp;lt;1, 0, 0&amp;gt;;            (9)&#039;&#039;&#039;&lt;br /&gt;
 &#039;&#039;&#039;vector A_left_A = &amp;lt;0, 1, 0&amp;gt;;&#039;&#039;&#039;&lt;br /&gt;
 &#039;&#039;&#039;vector A_up_A   = &amp;lt;0, 0, 1&amp;gt;;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
We said we only knew the fwd and up directions, but the third can always be&lt;br /&gt;
calculated from the other two with a cross product:&lt;br /&gt;
&lt;br /&gt;
 &#039;&#039;&#039;A_fwd_B  = A_left_B % A_up_B;           (10)&#039;&#039;&#039;&lt;br /&gt;
 &#039;&#039;&#039;A_left_B = A_up_B % A_fwd_B;&#039;&#039;&#039;&lt;br /&gt;
 &#039;&#039;&#039;A_up_B   = A_fwd_B % A_left_B;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Hence, the cross product exists of the other two in the order left to right where after &#039;up&#039; you start at &#039;fwd&#039; again; they rotate: ... left up fwd left up fwd ...&lt;br /&gt;
Put a &#039;=&#039; at any space in that sequence and a &#039;%&#039; at the next space and you have the right formula. Also note that x % y = - y % x, in case you were wondering.&lt;br /&gt;
&lt;br /&gt;
Now assume we have the target directions A_*_B, then we can find the rotation between&lt;br /&gt;
A and B with:&lt;br /&gt;
&lt;br /&gt;
 &#039;&#039;&#039;A_rot_B = [[llAxes2Rot]](A_fwd_B, A_left_B, A_up_B);       (11)&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Where A_rot_B is the rotation that turns A_*_A into A_*_B:&lt;br /&gt;
&lt;br /&gt;
 A_fwd_B  = A_fwd_A  * A_rot_B&lt;br /&gt;
 A_left_B = A_left_A * A_rot_B&lt;br /&gt;
 A_up_B   = A_up_A   * A_rot_B&lt;br /&gt;
&lt;br /&gt;
=== Finding coordinate systems ===&lt;br /&gt;
&lt;br /&gt;
Assume you already have a coordinate system B (for example, region or object coordinates, the orientations of which you can find directly with [[#LSL functions]]).&lt;br /&gt;
&lt;br /&gt;
Finding coordinate system A means that you find A_rot_B (or B_rot_A which is just the inverse), and A_pos_B or B_pos_A.&lt;br /&gt;
&lt;br /&gt;
Finding the rotation is usually the easiest since it doesn&#039;t depend on where the origin is and can most likely&lt;br /&gt;
be derived somehow. For example, in many cases you will have two orthogonal direction vectors in B that you know&lt;br /&gt;
to be parallel with the x, y or z axes of A. Lets say that you have AsX_dir_B and a AsY_dir_B that make an angle&lt;br /&gt;
of 90 degrees and have a length of 1, where AsX_dir_B is known to be parallel with the X axis of A and AsY_dir_B&lt;br /&gt;
is known to be parallel with the Y axis of A. Note that in this case we can also use the notation A_fwd_B for AsX_dir_B since&lt;br /&gt;
&#039;fwd&#039; is in the X direction (AsX_dir_B means &amp;quot;A&#039;s X-axis direction in coordinates of B&amp;quot;, and A_fwd_B means &amp;quot;A&#039;s&lt;br /&gt;
forwards direction in coordinates of B&amp;quot;, so they are the same thing). Then we find:&lt;br /&gt;
&lt;br /&gt;
 A_rot_B = [[llAxes2Rot]](AsX_dir_B, AsY_dir_B, AsX_dir_B % AsY_dir_B);&lt;br /&gt;
&lt;br /&gt;
as discussed in the previous paragraph.&lt;br /&gt;
&lt;br /&gt;
Next, if you have a vector from_B_to_A pointing from the origin of B to the origin of A, then you have&lt;br /&gt;
the translation between A and B too:&lt;br /&gt;
&lt;br /&gt;
If from_B_to_A is in coordinates of A, then&lt;br /&gt;
&lt;br /&gt;
 B_pos_A = -from_B_to_A&lt;br /&gt;
&lt;br /&gt;
while if from_B_to_A is in coordinates of B, then&lt;br /&gt;
&lt;br /&gt;
 A_pos_B = from_B_to_A&lt;br /&gt;
&lt;br /&gt;
Slight counter intuitive you have to read &#039;A_pos_B&#039; as &#039;The vector pointing from the origin of B to the origin of A&#039;,&lt;br /&gt;
but plausible since it is in the coordinates of B and thus you should expect the vector to start in the origin&lt;br /&gt;
of B.&lt;br /&gt;
&lt;br /&gt;
If you have a series of vectors that are stacked, all the way from B to A, then of course you just add them all up&lt;br /&gt;
to get A_pos_B. Likewise, if you have a series of vectors in the coordinates of A that are stacked to add up&lt;br /&gt;
to go from A to B, then add them all up to get B_pos_A.&lt;br /&gt;
&lt;br /&gt;
The interesting case therefore is where you have a vector C_pos_A that points from A to C and is in the coordinates&lt;br /&gt;
of A, and a vector C_pos_B that points from B to C and is in the coordinates of B.&lt;br /&gt;
&lt;br /&gt;
To solve this puzzle, lets first write the vectors slightly different so we&#039;re not confused about&lt;br /&gt;
what they mean, even after converting between the coordinate systems A and B.&lt;br /&gt;
&lt;br /&gt;
Let AC_vec_A be C_pos_A: the vector (arrow) from the origin of A to C (in coordinates of A) and&lt;br /&gt;
let BC_vec_B be C_pos_B: the vector from the origin of B to C (in the coordinates of B).&lt;br /&gt;
Note how the notation of _vec_ is similar to that of _dir_, except that a direction vector has&lt;br /&gt;
a length of 1, and this vector has both a direction and a length: it describes how to get from&lt;br /&gt;
one point to another. Like directions, when converting them between A and B you ONLY&lt;br /&gt;
apply the rotation A_rot_B! Also note that a vector with a minus sign just means &amp;quot;in the opposite direction&amp;quot;,&lt;br /&gt;
hence CA_vec_A = -AC_vec_A.&lt;br /&gt;
&lt;br /&gt;
Thus, we find that&lt;br /&gt;
&lt;br /&gt;
 AC_vec_B = AC_vec_A * A_rot_B&lt;br /&gt;
&lt;br /&gt;
and find&lt;br /&gt;
&lt;br /&gt;
 A_pos_B = BA_vec_B = BC_vec_B + CA_vec_B = BC_vec_B - AC_vec_B = BC_vec_B - AC_vec_A * A_rot_B&lt;br /&gt;
&lt;br /&gt;
then dropping the extra notation again&lt;br /&gt;
&lt;br /&gt;
 &#039;&#039;&#039;A_pos_B = C_pos_B - C_pos_A * A_rot_B         (12)&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Which is rather logical when you read it in English as &amp;quot;To go from B to A in coordinates of B (A_pos_B),&lt;br /&gt;
you first go from B to C in coordinates of B (C_pos_B) and then in the opposite direction (the minus sign)&lt;br /&gt;
of going from A to C (namely from C to A) converted to the coordinates of B.&lt;br /&gt;
&lt;br /&gt;
And oh wonder - if we write this result a little different we find:&lt;br /&gt;
&lt;br /&gt;
 C_pos_A = (C_pos_B - A_pos_B) / A_rot_B&lt;br /&gt;
&lt;br /&gt;
which is the normal conversion (formula (3)) for the position of C from A to B coordinates!&lt;br /&gt;
&lt;br /&gt;
=== LSL functions ===&lt;br /&gt;
&lt;br /&gt;
What all of the above taught you is mainly a coding style: use prefixes and postfixes for your rotations (and translations)!&lt;br /&gt;
It&#039;s all in the &#039;&#039;&#039;&#039;&#039;names&#039;&#039;&#039;&#039;&#039; of your variables. A &#039;rotation&#039; type can be the rotation part of a transformation&lt;br /&gt;
(not tied to a particular coordinate system, but rather rotating around whatever coordinate system you apply it to),&lt;br /&gt;
it can be the representation of a unit vector, it can be the rotation part of the orientation of a prim relative to a&lt;br /&gt;
given coordinate system, or it can represent the rotation part of a coordinate system conversion.&lt;br /&gt;
If you don&#039;t use a consistent way to reflect all that in your variable names then you &#039;&#039;will&#039;&#039; get confused.&lt;br /&gt;
&lt;br /&gt;
The LSL functions mostly deal with two types: orientations (position + rotation) of prims relative to some coordinate system,&lt;br /&gt;
and simply transformations (rotation and/or translation).&lt;br /&gt;
&lt;br /&gt;
The table below shows the coordinate systems involved.&lt;br /&gt;
&lt;br /&gt;
{| rules=&amp;quot;all&amp;quot; style=&amp;quot;margin:2em 1em 2em 1em; border:none 2px #000000; background-color:#F9F9F9; font-size:120%; empty-cells:hide;&amp;quot;&lt;br /&gt;
 |-&lt;br /&gt;
 | colspan=2 |&lt;br /&gt;
 | style=&amp;quot;padding: 5px 10px 5px 10px; background-color: #ffdddd; text-align: center&amp;quot; colspan=2 | Coordinates of the prim containing the script (&#039;&#039;&#039;sc_&#039;&#039;&#039;)&lt;br /&gt;
 |- {{Hl2}}&lt;br /&gt;
 ! style=&amp;quot;padding: 5px 10px 5px 10px; color: blue; background-color: #eeeeb0&amp;quot; | Coordinate System&lt;br /&gt;
 ! style=&amp;quot;padding: 5px 10px 5px 10px; color: green; background-color: lightgray&amp;quot; | Abbreviation &lt;br /&gt;
 ! style=&amp;quot;padding: 5px 10px 5px 10px&amp;quot; | script in child prim&lt;br /&gt;
 ! style=&amp;quot;padding: 5px 10px 5px 10px&amp;quot; | script in root prim&lt;br /&gt;
 |-&lt;br /&gt;
 | style=&amp;quot;padding: 5px 10px 5px 10px; color: blue; background-color: #ffffa0&amp;quot; | World/Map Coordinates&lt;br /&gt;
 | style=&amp;quot;padding: 5px 10px 5px 10px&amp;quot;                                         | &#039;&#039;&#039;wc&#039;&#039;&#039;&lt;br /&gt;
 | style=&amp;quot;padding: 5px 10px 5px 10px&amp;quot; colspan=2                               | &amp;lt;span style=&amp;quot;font-family: mono; font-size: 90%&amp;quot;&amp;gt;sc_pos_&#039;&#039;&#039;wc&#039;&#039;&#039; = sc_pos_rc + [[llGetRegionCorner]]()&amp;lt;br&amp;gt;sc_rot_&#039;&#039;&#039;wc&#039;&#039;&#039; = sc_rot_rc&amp;lt;/span&amp;gt;&lt;br /&gt;
 |-&lt;br /&gt;
 | style=&amp;quot;padding: 5px 10px 5px 10px; color: blue; background-color: #ffffa0&amp;quot; | Region Coordinates&lt;br /&gt;
 | style=&amp;quot;padding: 5px 10px 5px 10px&amp;quot;                                         | &#039;&#039;&#039;rc&#039;&#039;&#039;&lt;br /&gt;
 | style=&amp;quot;padding: 5px 10px 5px 10px&amp;quot; colspan=2                               | &amp;lt;span style=&amp;quot;font-family: mono; font-size: 90%&amp;quot;&amp;gt;sc_pos_&#039;&#039;&#039;rc&#039;&#039;&#039; = [[llGetPos]]()&amp;lt;br&amp;gt;sc_rot_&#039;&#039;&#039;rc&#039;&#039;&#039; = [[llGetRot]]()&amp;lt;/span&amp;gt;&lt;br /&gt;
 |-&lt;br /&gt;
 | style=&amp;quot;padding: 5px 10px 5px 10px; color: blue; background-color: #ffffa0&amp;quot; | Object/Root Coordinates&lt;br /&gt;
 | style=&amp;quot;padding: 5px 10px 5px 10px&amp;quot;                                         | &#039;&#039;&#039;oc&#039;&#039;&#039;&lt;br /&gt;
 | style=&amp;quot;padding: 5px 10px 5px 10px&amp;quot;                                         | &amp;lt;span style=&amp;quot;font-family: mono; font-size: 90%&amp;quot;&amp;gt;sc_pos_&#039;&#039;&#039;oc&#039;&#039;&#039; = [[llGetLocalPos]]()&amp;lt;br&amp;gt;sc_rot_&#039;&#039;&#039;oc&#039;&#039;&#039; = [[llGetLocalRot]]()&amp;lt;/span&amp;gt;&lt;br /&gt;
 | style=&amp;quot;padding: 5px 10px 5px 10px&amp;quot;                                         | &amp;lt;span style=&amp;quot;font-family: mono; font-size: 90%&amp;quot;&amp;gt;sc_pos_&#039;&#039;&#039;oc&#039;&#039;&#039; = [[ZERO_VECTOR]]&amp;lt;br&amp;gt;sc_rot_&#039;&#039;&#039;oc&#039;&#039;&#039; = [[ZERO_ROTATION]]&amp;lt;/span&amp;gt;&lt;br /&gt;
 |-&lt;br /&gt;
 | style=&amp;quot;padding: 5px 10px 5px 10px; color: blue; background-color: #ffffa0&amp;quot; | Self Coordinates&lt;br /&gt;
 | style=&amp;quot;padding: 5px 10px 5px 10px&amp;quot;                                         | &#039;&#039;&#039;sc&#039;&#039;&#039;&lt;br /&gt;
 | style=&amp;quot;padding: 5px 10px 5px 10px&amp;quot; colspan=2                               | &amp;lt;span style=&amp;quot;font-family: mono; font-size: 90%&amp;quot;&amp;gt;sc_pos_&#039;&#039;&#039;sc&#039;&#039;&#039; = [[ZERO_VECTOR]]&amp;lt;br&amp;gt;sc_rot_&#039;&#039;&#039;sc&#039;&#039;&#039; = [[ZERO_ROTATION]]&amp;lt;/span&amp;gt;&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
Where &#039;in the root prim&#039; can be detect by testing that [[llGetLinkNumber]]() returns a value &amp;lt;= 1.&lt;br /&gt;
&lt;br /&gt;
Alternatively, you can set link = [[llGetLinkNumber]]() and use the following table which&lt;br /&gt;
shows how to obtain the coordinates of a prim with link number &#039;link&#039; from a script anywhere in the same object.&lt;br /&gt;
Note that this doesn&#039;t work when the object exist of a single prim: then [[llGetLinkNumber]]() returns 0,&lt;br /&gt;
while &#039;link&#039; must be larger than 0 here. If you need to get Object Coordinates (_oc) then do not use the&lt;br /&gt;
negative value [[LINK_THIS]]. You can use [[LINK_THIS]] for the other coordinate systems, provided&lt;br /&gt;
the object exists of at least two prims.&lt;br /&gt;
&lt;br /&gt;
{| rules=&amp;quot;all&amp;quot; style=&amp;quot;margin:2em 1em 2em 1em; border:none 2px #000000; background-color:#F9F9F9; font-size:120%; empty-cells:hide;&amp;quot;&lt;br /&gt;
 |-&lt;br /&gt;
 | colspan=2 |&lt;br /&gt;
 | style=&amp;quot;padding: 5px 10px 5px 10px; background-color: #ffdddd; text-align: center&amp;quot; colspan=2 | Coordinates of a linked prim (&#039;&#039;&#039;link_&#039;&#039;&#039;)&lt;br /&gt;
 |- {{Hl2}}&lt;br /&gt;
 ! style=&amp;quot;padding: 5px 10px 5px 10px; color: blue; background-color: #eeeeb0&amp;quot; | Coordinate System&lt;br /&gt;
 ! style=&amp;quot;padding: 5px 10px 5px 10px; color: green; background-color: lightgray&amp;quot; | Abbreviation &lt;br /&gt;
 ! style=&amp;quot;padding: 5px 10px 5px 10px&amp;quot; | link &amp;gt; 1&lt;br /&gt;
 ! style=&amp;quot;padding: 5px 10px 5px 10px&amp;quot; | link = 1&lt;br /&gt;
 |-&lt;br /&gt;
 | style=&amp;quot;padding: 5px 10px 5px 10px; color: blue; background-color: #ffffa0&amp;quot; | World/Map Coordinates&lt;br /&gt;
 | style=&amp;quot;padding: 5px 10px 5px 10px&amp;quot;                                         | &#039;&#039;&#039;wc&#039;&#039;&#039;&lt;br /&gt;
 | style=&amp;quot;padding: 5px 10px 5px 10px&amp;quot; colspan=2                               | &amp;lt;span style=&amp;quot;font-family: mono; font-size: 90%&amp;quot;&amp;gt;link_pos_&#039;&#039;&#039;wc&#039;&#039;&#039; = link_pos_rc + [[llGetRegionCorner]]()&amp;lt;br&amp;gt;link_rot_&#039;&#039;&#039;wc&#039;&#039;&#039; = link_rot_rc&amp;lt;/span&amp;gt;&lt;br /&gt;
 |-&lt;br /&gt;
 | style=&amp;quot;padding: 5px 10px 5px 10px; color: blue; background-color: #ffffa0&amp;quot; | Region Coordinates&lt;br /&gt;
 | style=&amp;quot;padding: 5px 10px 5px 10px&amp;quot;                                         | &#039;&#039;&#039;rc&#039;&#039;&#039;&lt;br /&gt;
 | style=&amp;quot;padding: 5px 10px 5px 10px&amp;quot; colspan=2                               | &amp;lt;span style=&amp;quot;font-family: mono; font-size: 90%&amp;quot;&amp;gt;link_pos_&#039;&#039;&#039;rc&#039;&#039;&#039; = [[llList2Vector]]([[llGetLinkPrimitiveParams]](&#039;&#039;&#039;link&#039;&#039;&#039;, [&amp;lt;span&amp;gt;&amp;lt;/span&amp;gt;[[PRIM_POSITION]]]), 0)&amp;lt;br&amp;gt;link_rot_&#039;&#039;&#039;rc&#039;&#039;&#039; = [[llList2Rot]]([[llGetLinkPrimitiveParams]](&#039;&#039;&#039;link&#039;&#039;&#039;, [&amp;lt;span&amp;gt;&amp;lt;/span&amp;gt;[[PRIM_ROTATION]]]), 0)&amp;lt;/span&amp;gt;&lt;br /&gt;
 |-&lt;br /&gt;
 | style=&amp;quot;padding: 5px 10px 5px 10px; color: blue; background-color: #ffffa0&amp;quot; | Object/Root Coordinates&lt;br /&gt;
 | style=&amp;quot;padding: 5px 10px 5px 10px&amp;quot;                                         | &#039;&#039;&#039;oc&#039;&#039;&#039;&lt;br /&gt;
 | style=&amp;quot;padding: 5px 10px 5px 10px&amp;quot;                                         | &amp;lt;span style=&amp;quot;font-family: mono; font-size: 90%&amp;quot;&amp;gt;link_pos_&#039;&#039;&#039;oc&#039;&#039;&#039; = [[llList2Vector]]([[llGetLinkPrimitiveParams]](&#039;&#039;&#039;link&#039;&#039;&#039;, [&amp;lt;span&amp;gt;&amp;lt;/span&amp;gt;[[PRIM_POS_LOCAL]]]), 0)&amp;lt;br&amp;gt;link_rot_&#039;&#039;&#039;oc&#039;&#039;&#039; = [[llList2Rot]]([[llGetLinkPrimitiveParams]](&#039;&#039;&#039;link&#039;&#039;&#039;, [&amp;lt;span&amp;gt;&amp;lt;/span&amp;gt;[[PRIM_ROT_LOCAL]]]), 0)&amp;lt;/span&amp;gt;&lt;br /&gt;
 | style=&amp;quot;padding: 5px 10px 5px 10px&amp;quot;                                         | &amp;lt;span style=&amp;quot;font-family: mono; font-size: 90%&amp;quot;&amp;gt;link_pos_&#039;&#039;&#039;oc&#039;&#039;&#039; = [[ZERO_VECTOR]]&amp;lt;br&amp;gt;link_rot_&#039;&#039;&#039;oc&#039;&#039;&#039; = [[ZERO_ROTATION]]&amp;lt;/span&amp;gt;&lt;br /&gt;
 |-&lt;br /&gt;
 | style=&amp;quot;padding: 5px 10px 5px 10px; color: blue; background-color: #ffffa0&amp;quot; | Self Coordinates&lt;br /&gt;
 | style=&amp;quot;padding: 5px 10px 5px 10px&amp;quot;                                         | &#039;&#039;&#039;sc&#039;&#039;&#039;&lt;br /&gt;
 | style=&amp;quot;padding: 5px 10px 5px 10px&amp;quot; colspan=2                               | &amp;lt;span style=&amp;quot;font-family: mono; font-size: 90%&amp;quot;&amp;gt;link_pos_&#039;&#039;&#039;sc&#039;&#039;&#039; = (link_pos_oc - sc_pos_oc) / sc_rot_oc&amp;lt;br&amp;gt;link_rot_&#039;&#039;&#039;sc&#039;&#039;&#039; = link_rot_oc / sc_rot_oc&amp;lt;/span&amp;gt;&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
While the above table works for link = [[LINK_ROOT]], it is probably more convenient to use the following table:&lt;br /&gt;
&lt;br /&gt;
{| rules=&amp;quot;all&amp;quot; style=&amp;quot;margin:2em 1em 2em 1em; border:none 2px #000000; background-color:#F9F9F9; font-size:120%; empty-cells:hide;&amp;quot;&lt;br /&gt;
 |-&lt;br /&gt;
 | colspan=2 |&lt;br /&gt;
 | style=&amp;quot;padding: 5px 10px 5px 10px; background-color: #ffdddd; text-align: center&amp;quot; colspan=2 | Coordinates of the root prim (&#039;&#039;&#039;oc_&#039;&#039;&#039;)&lt;br /&gt;
 |- {{Hl2}}&lt;br /&gt;
 ! style=&amp;quot;padding: 5px 10px 5px 10px; color: blue; background-color: #eeeeb0&amp;quot; | Coordinate System&lt;br /&gt;
 ! style=&amp;quot;padding: 5px 10px 5px 10px; color: green; background-color: lightgray&amp;quot; | Abbreviation &lt;br /&gt;
 ! style=&amp;quot;padding: 5px 10px 5px 10px&amp;quot; | script in any prim&lt;br /&gt;
 |-&lt;br /&gt;
 | style=&amp;quot;padding: 5px 10px 5px 10px; color: blue; background-color: #ffffa0&amp;quot; | World/Map Coordinates&lt;br /&gt;
 | style=&amp;quot;padding: 5px 10px 5px 10px&amp;quot;                                         | &#039;&#039;&#039;wc&#039;&#039;&#039;&lt;br /&gt;
 | style=&amp;quot;padding: 5px 10px 5px 10px&amp;quot;                                         | &amp;lt;span style=&amp;quot;font-family: mono; font-size: 90%&amp;quot;&amp;gt;oc_pos_&#039;&#039;&#039;wc&#039;&#039;&#039; = oc_pos_rc + [[llGetRegionCorner]]()&amp;lt;br&amp;gt;oc_rot_&#039;&#039;&#039;wc&#039;&#039;&#039; = oc_rot_rc&amp;lt;/span&amp;gt;&lt;br /&gt;
 |-&lt;br /&gt;
 | style=&amp;quot;padding: 5px 10px 5px 10px; color: blue; background-color: #ffffa0&amp;quot; | Region Coordinates&lt;br /&gt;
 | style=&amp;quot;padding: 5px 10px 5px 10px&amp;quot;                                         | &#039;&#039;&#039;rc&#039;&#039;&#039;&lt;br /&gt;
 | style=&amp;quot;padding: 5px 10px 5px 10px&amp;quot;                                         | &amp;lt;span style=&amp;quot;font-family: mono; font-size: 90%&amp;quot;&amp;gt;oc_pos_&#039;&#039;&#039;rc&#039;&#039;&#039; = [[llGetRootPosition]]()&amp;lt;br&amp;gt;oc_rot_&#039;&#039;&#039;rc&#039;&#039;&#039; = [[llGetRootRotation]]()&amp;lt;/span&amp;gt;&lt;br /&gt;
 |-&lt;br /&gt;
 | style=&amp;quot;padding: 5px 10px 5px 10px; color: blue; background-color: #ffffa0&amp;quot; | Object/Root Coordinates&lt;br /&gt;
 | style=&amp;quot;padding: 5px 10px 5px 10px&amp;quot;                                         | &#039;&#039;&#039;oc&#039;&#039;&#039;&lt;br /&gt;
 | style=&amp;quot;padding: 5px 10px 5px 10px&amp;quot;                                         | &amp;lt;span style=&amp;quot;font-family: mono; font-size: 90%&amp;quot;&amp;gt;oc_pos_&#039;&#039;&#039;oc&#039;&#039;&#039; = [[ZERO_VECTOR]]&amp;lt;br&amp;gt;oc_rot_&#039;&#039;&#039;oc&#039;&#039;&#039; = [[ZERO_ROTATION]]&amp;lt;/span&amp;gt;&lt;br /&gt;
 |-&lt;br /&gt;
 | style=&amp;quot;padding: 5px 10px 5px 10px; color: blue; background-color: #ffffa0&amp;quot; | Self Coordinates&lt;br /&gt;
 | style=&amp;quot;padding: 5px 10px 5px 10px&amp;quot;                                         | &#039;&#039;&#039;sc&#039;&#039;&#039;&lt;br /&gt;
 | style=&amp;quot;padding: 5px 10px 5px 10px&amp;quot;                                         | &amp;lt;span style=&amp;quot;font-family: mono; font-size: 90%&amp;quot;&amp;gt;oc_pos_&#039;&#039;&#039;sc&#039;&#039;&#039; = - sc_pos_oc / sc_rot_oc&amp;lt;br&amp;gt;oc_rot_&#039;&#039;&#039;sc&#039;&#039;&#039; = [[ZERO_ROTATION]] / sc_rot_oc&amp;lt;/span&amp;gt;&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
As shows from the above table, LSL does not directly support &#039;&#039;&#039;_sc&#039;&#039;&#039; coordinates,&lt;br /&gt;
and I used conversions to fill in the tables. All in all, we listed four coordinate systems (wc, rc, oc and sc; not including the &#039;link_&#039; stuff,&lt;br /&gt;
which isn&#039;t really a separate coordinate system)&lt;br /&gt;
and thus could write out four times four is sixteen ways to convert one into the other. Four of those would be trivial, and of the remaining&lt;br /&gt;
twelve we can express six as the inverse of the other six.&lt;br /&gt;
&lt;br /&gt;
However, lets ignore the World Coordinates for now, which are just the same as the Region Coordinates with an offset for the position.&lt;br /&gt;
Then we have three coordinate systems (rc, oc and sc), leading to nine conversion, three of which are trivial, and of the remaining&lt;br /&gt;
six three can be expressed as the inverse of the other three. Those three are: oc_*_rc, sc_*_rc and sc_*_oc, which are all listed above.&lt;br /&gt;
The trivial ones, rc_*_rc, oc_*_oc and sc_*_sc, are all ZERO_* (the latter two also are listed in the tables above).&lt;br /&gt;
Finally, the inverse values, rc_*_oc, rc_*_sc and oc_*_sc can be expressed with the inversion formula given in [[#Converting between coordinate systems]].&lt;br /&gt;
So this is really all there is.&lt;br /&gt;
&lt;br /&gt;
=== The fourth dimension ===&lt;br /&gt;
&lt;br /&gt;
Picture a coordinate system as three perpendicular lines, like an object in-world perhaps existing of&lt;br /&gt;
three really long prims in the colors red, green and blue. You can toss them into the region&lt;br /&gt;
where they randomly bounce around like dice &amp;amp;ndash; a whole bunch of them!&lt;br /&gt;
And then you freeze time - make a snapshot.&lt;br /&gt;
&lt;br /&gt;
With the knowledge so far you can now express the position and rotation of an object or prim relative&lt;br /&gt;
to any of those coordinate systems &amp;amp;ndash; and convert between them at will.&lt;br /&gt;
Apply rotations and translations relative to any chosen system.&lt;br /&gt;
All of the coordinate systems are virtually the same! But in practice this isn&#039;t the case, why is that?&lt;br /&gt;
&lt;br /&gt;
The reason is that in practice coordinate systems change in time, in a way that you cannot predict.&lt;br /&gt;
It&#039;s like they are still tumbling and bouncing around and you have no idea where they are.&lt;br /&gt;
&lt;br /&gt;
This noise comes mainly from one thing: objects are being moved. Taken into repositories and rezzed back,&lt;br /&gt;
rotated and possibly even scaled! In fact, not just objects, but also prims inside objects can be changed&lt;br /&gt;
at will at any moment and a good script must take that into account.&lt;br /&gt;
&lt;br /&gt;
The art of programming therefore becomes &#039;&#039;design&#039;&#039;. You must choose which coordinate systems you&lt;br /&gt;
want to use; what your global variables store, relative to which coordinate system.&lt;br /&gt;
&lt;br /&gt;
Unfortunately, a script can &#039;&#039;not&#039;&#039; detect when this might have happened and only perform extra computations&lt;br /&gt;
or re-computation, of otherwise constant variables, when a prim or object has actually been changed.&lt;br /&gt;
There is an LSL event [[moving_start]] but that only works half on SL and not at all on opensim.&lt;br /&gt;
For rotation detection there is nothing.&lt;br /&gt;
&lt;br /&gt;
As such, it is necessary to call the LSL functions listed in the tables above every time you&lt;br /&gt;
want to do anything that depends on them; which hopefully won&#039;t be too often.&lt;br /&gt;
&lt;br /&gt;
The following example script can be put in the root prim of an object of any number of cubes&lt;br /&gt;
and allows one to sit on each cube, using [[llLinkSitTarget]], even when you move or rotate&lt;br /&gt;
child prims.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;lsl&amp;gt;&lt;br /&gt;
// A script written to show how to use coordinate systems in LSL.&lt;br /&gt;
//&lt;br /&gt;
// Copyright(c) Timmy Songbird @DreamNation&lt;br /&gt;
//              Timmy Foxclaw  @SL,&lt;br /&gt;
//              2014&lt;br /&gt;
//&lt;br /&gt;
// This program is free software; you can redistribute it and/or modify&lt;br /&gt;
// it under the terms of the GNU General Public License as published by&lt;br /&gt;
// the Free Software Foundation; either version 2 of the License, or&lt;br /&gt;
// (at your option) any later version.&lt;br /&gt;
//&lt;br /&gt;
// This program is distributed in the hope that it will be useful,&lt;br /&gt;
// but WITHOUT ANY WARRANTY; without even the implied warranty of&lt;br /&gt;
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the&lt;br /&gt;
// GNU General Public License for more details.&lt;br /&gt;
//&lt;br /&gt;
// You should have received a copy of the GNU General Public License&lt;br /&gt;
// along with this program; if not, write to the Free Software&lt;br /&gt;
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307, USA.&#039;)&lt;br /&gt;
&lt;br /&gt;
//----------------------------------------------------------------------------&lt;br /&gt;
//#line &amp;quot;/opt/secondlife/scripts/scripts/tests/llLinkSitTarget_Test.m4s:5&amp;quot;&lt;br /&gt;
// GitLocation: tests/llLinkSitTarget_Test.m4s&lt;br /&gt;
// GitID: 32c3ab5a6f17d96eafe4e110bb91a700e2fd589b&lt;br /&gt;
&lt;br /&gt;
// This script uses the follow coordinate systems:&lt;br /&gt;
//&lt;br /&gt;
// rc     : Region Coordinates.&lt;br /&gt;
// oc     : Object, or root prim, Coordinates.&lt;br /&gt;
// link   : Coordinates of prim with link number &#039;link&#039;.&lt;br /&gt;
// STc    : Coordinates of the touched face (see llDetectedTouchST)&lt;br /&gt;
//          (x and y in the ranger [0, 1] with (0, 0) in the bottom-left corner).&lt;br /&gt;
// center : Coordinates of the touched face with the origin in the center,&lt;br /&gt;
//          the orientation is the same as STc (z is the normal of the surface),&lt;br /&gt;
//          but scaled to be in meters.&lt;br /&gt;
// ac     : Avatar center Coordinates. This is really the same as stc, but&lt;br /&gt;
//          moved up an offset. Rotations passed to llLinkSitTarget are&lt;br /&gt;
//          relative to this coordinate system.&lt;br /&gt;
&lt;br /&gt;
//----------------------------------------------------------------------------&lt;br /&gt;
//#line &amp;quot;/opt/secondlife/scripts/scripts/tests/llLinkSitTarget_Test.m4s:24&amp;quot;&lt;br /&gt;
// The sit position of the sit target.&lt;br /&gt;
// This value is *different* in SL and opensim, and even changed since opensim version 0.7.6.&lt;br /&gt;
// The currently measured values for the z component are:&lt;br /&gt;
// SL: 0.05, opensim 0.7.6: 0.0, opensim 0.8.x: -agentSize.z / 37.9075&lt;br /&gt;
&lt;br /&gt;
// Use this in SL:&lt;br /&gt;
//vector sittarget_pos_ac = &amp;lt;0.0, 0.0, 0.05&amp;gt;;&lt;br /&gt;
//integer opensimver = 0; // SL&lt;br /&gt;
&lt;br /&gt;
// Use this on opensim:&lt;br /&gt;
vector sittarget_pos_ac = &amp;lt;0.0, 0.0, 0.0&amp;gt;;&lt;br /&gt;
//integer opensimver = 7; // Opensim 0.7.6&lt;br /&gt;
integer opensimver = 8; // Opensim &amp;gt;= 0.8&lt;br /&gt;
&lt;br /&gt;
//----------------------------------------------------------------------------&lt;br /&gt;
//#line &amp;quot;/opt/secondlife/scripts/scripts/tests/llLinkSitTarget_Test.m4s:40&amp;quot;&lt;br /&gt;
// face_link() returns a list of vectors in link coordinates.&lt;br /&gt;
//&lt;br /&gt;
// Returns: [bottomLeft_link, topRight_link].&lt;br /&gt;
//&lt;br /&gt;
// bottomLeft_link is the bottom left corner of the given face,&lt;br /&gt;
// that is - the corner where (S, T) = (0, 0).&lt;br /&gt;
// topRight_link is the top right corner of the given face,&lt;br /&gt;
// that is - the corner where (S, T) = (1, 1).&lt;br /&gt;
list face_link(integer link, integer face)&lt;br /&gt;
{&lt;br /&gt;
  list params = llGetLinkPrimitiveParams(link, [PRIM_TYPE, PRIM_SIZE]);&lt;br /&gt;
  vector bottomLeft_link;&lt;br /&gt;
  vector topRight_link;&lt;br /&gt;
  integer prim_type = llList2Integer(params, 0);&lt;br /&gt;
  if (prim_type == PRIM_TYPE_BOX)&lt;br /&gt;
  {&lt;br /&gt;
    topRight_link = llList2Vector(params, 7) * 0.5;&lt;br /&gt;
    if (face == 0)&lt;br /&gt;
    {&lt;br /&gt;
      bottomLeft_link = -topRight_link;&lt;br /&gt;
      bottomLeft_link.z = topRight_link.z;&lt;br /&gt;
    }&lt;br /&gt;
    else if (face == 1)&lt;br /&gt;
    {&lt;br /&gt;
      bottomLeft_link = -topRight_link;&lt;br /&gt;
      topRight_link.y = bottomLeft_link.y;&lt;br /&gt;
    }&lt;br /&gt;
    else if (face == 2)&lt;br /&gt;
    {&lt;br /&gt;
      bottomLeft_link = -topRight_link;&lt;br /&gt;
      bottomLeft_link.x = topRight_link.x;&lt;br /&gt;
    }&lt;br /&gt;
    else if (face == 3)&lt;br /&gt;
    {&lt;br /&gt;
      topRight_link.x = -topRight_link.x;&lt;br /&gt;
      bottomLeft_link = -topRight_link;&lt;br /&gt;
      bottomLeft_link.y = topRight_link.y;&lt;br /&gt;
    }&lt;br /&gt;
    else if (face == 4)&lt;br /&gt;
    {&lt;br /&gt;
      topRight_link.y = -topRight_link.y;&lt;br /&gt;
      bottomLeft_link = -topRight_link;&lt;br /&gt;
      topRight_link.x = bottomLeft_link.x;&lt;br /&gt;
    }&lt;br /&gt;
    else if (face == 5)&lt;br /&gt;
    {&lt;br /&gt;
      topRight_link.y = -topRight_link.y;&lt;br /&gt;
      topRight_link.z = -topRight_link.z;&lt;br /&gt;
      bottomLeft_link = -topRight_link;&lt;br /&gt;
      bottomLeft_link.z = topRight_link.z;&lt;br /&gt;
    }&lt;br /&gt;
    else&lt;br /&gt;
    {&lt;br /&gt;
      llWhisper(0, &amp;quot;This script only supports sitting on boxes without cuts or holes.&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
  else&lt;br /&gt;
  {&lt;br /&gt;
    llWhisper(0, &amp;quot;This script does not work for non-box prims.&amp;quot;);&lt;br /&gt;
  }&lt;br /&gt;
  return [bottomLeft_link, topRight_link];&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
//----------------------------------------------------------------------------&lt;br /&gt;
//#line &amp;quot;/opt/secondlife/scripts/scripts/tests/llLinkSitTarget_Test.m4s:104&amp;quot;&lt;br /&gt;
default&lt;br /&gt;
{&lt;br /&gt;
  touch_start(integer num)&lt;br /&gt;
  {&lt;br /&gt;
    integer n;&lt;br /&gt;
    // Run over everyone that might have touch a prim (it could be more than one!)&lt;br /&gt;
    for (n = 0; n &amp;lt; num; ++n)&lt;br /&gt;
    {&lt;br /&gt;
      // Get the link number of the touch prim.&lt;br /&gt;
      integer link = llDetectedLinkNumber(n);&lt;br /&gt;
&lt;br /&gt;
      // Some conversion variables we need, copied directly from the table above.&lt;br /&gt;
      vector   link_pos_rc = llList2Vector(llGetLinkPrimitiveParams(link, [PRIM_POSITION]), 0);&lt;br /&gt;
      rotation link_rot_rc = llList2Rot(llGetLinkPrimitiveParams(link, [PRIM_ROTATION]), 0);&lt;br /&gt;
&lt;br /&gt;
      // Get the face of the prim that was touched.&lt;br /&gt;
      integer face = llDetectedTouchFace(n);&lt;br /&gt;
      if (face == TOUCH_INVALID_FACE)&lt;br /&gt;
      {&lt;br /&gt;
        llInstantMessage(llDetectedKey(n), &amp;quot;Sorry, your viewer does not support touched faces.&amp;quot;);&lt;br /&gt;
      }&lt;br /&gt;
      else&lt;br /&gt;
      {&lt;br /&gt;
        // llDetectedTouchPos returns the position where an object was touched in Region Coordinates.&lt;br /&gt;
        vector touch_pos_rc = llDetectedTouchPos(n);&lt;br /&gt;
        // Convert that into link coordinates.&lt;br /&gt;
        vector touch_pos_link = (touch_pos_rc - link_pos_rc) / link_rot_rc;&lt;br /&gt;
&lt;br /&gt;
        // llDetectedTouchBinormal returns a normalized, directional vector in Region Coordinates.&lt;br /&gt;
        // So, it&#039;s not a position; it is a direction (dir), really representing a rotation.&lt;br /&gt;
        vector binormal_dir_rc = llDetectedTouchBinormal(n);&lt;br /&gt;
&lt;br /&gt;
        // In general a direction vector can not be converted to a rotation (when the&lt;br /&gt;
        // starting reference vector is (almost) the same as the direction vector, which&lt;br /&gt;
        // might be the case here since we have no idea where the vector is pointing to).&lt;br /&gt;
        // Therefore we just leave it as a vector, but we treat it the same as a rotation:&lt;br /&gt;
        // leave the origin alone and just correct the rotation when converting to the&lt;br /&gt;
        // local coordinate system of the link prim.&lt;br /&gt;
        vector binormal_dir_link = binormal_dir_rc / link_rot_rc; // binormal_dir_rc * rc_rot_link&lt;br /&gt;
&lt;br /&gt;
        // llDetectedTouchNormal returns a normalized, directional vector in Region Coordinates.&lt;br /&gt;
        // It is perpendicular to the surface (pointing outwards) and makes an angle of 90 degrees&lt;br /&gt;
        // with binormal_dir. Here we immediately convert it to _link coordinates.&lt;br /&gt;
        vector normal_dir_link = llDetectedTouchNormal(n) / link_rot_rc;&lt;br /&gt;
&lt;br /&gt;
        // Calculate the tangent vector.&lt;br /&gt;
        vector tangent_dir_link = binormal_dir_link % normal_dir_link;&lt;br /&gt;
&lt;br /&gt;
        // Get the [bottomLeft_link, topRight_link] positions of the surface &#039;face&#039;, in link coordinates.&lt;br /&gt;
        list surface_link = face_link(link, face);&lt;br /&gt;
        vector bottomLeft_pos_link = llList2Vector(surface_link, 0);&lt;br /&gt;
        vector topRight_pos_link = llList2Vector(surface_link, 1);&lt;br /&gt;
&lt;br /&gt;
        // Calculate the center of the surface.&lt;br /&gt;
        vector center_pos_link = (bottomLeft_pos_link + topRight_pos_link) * 0.5;&lt;br /&gt;
&lt;br /&gt;
        // The unit x vector in link coordinates is obviously &amp;lt;1, 0, 0&amp;gt;, center_rot_link is&lt;br /&gt;
        // therefore the rotation that is needed to rotate that to tangent_dir_link, which&lt;br /&gt;
        // represents &amp;lt;1, 0, 0&amp;gt; in center coordinates (the positive S direction).&lt;br /&gt;
        // The positive T direction, or &amp;lt;0, 1, 0&amp;gt; in center coordinates, is the binormal vector.&lt;br /&gt;
        // llAxes2Rot(fwd, left, up) returns the rotation needed to rotate &amp;lt;1, 0, 0&amp;gt; to fwd,&lt;br /&gt;
        // and &amp;lt;0, 1, 0&amp;gt; to left (and thus &amp;lt;0, 0, 1&amp;gt; to up).&lt;br /&gt;
        rotation center_rot_link = llAxes2Rot(tangent_dir_link, binormal_dir_link, normal_dir_link);&lt;br /&gt;
&lt;br /&gt;
        // llDetectedTouchST returns a vector in the plane of the touched surface,&lt;br /&gt;
        // with x and y ranging from 0,0 in the &amp;quot;bottom left&amp;quot; corner till 1,1 for&lt;br /&gt;
        // opposite corner. The value is thus in ST Coordinates.&lt;br /&gt;
        vector touch_pos_STc = llDetectedTouchST(n);&lt;br /&gt;
&lt;br /&gt;
        // Caluclate the size of the surface and rotate it in the plane of the center coordinates.&lt;br /&gt;
        vector center_link_scale = (topRight_pos_link - bottomLeft_pos_link) / center_rot_link;&lt;br /&gt;
&lt;br /&gt;
        // Convert touch_pos to center coordinates.&lt;br /&gt;
        vector touch_pos_center = &amp;lt;(touch_pos_STc.x - 0.5) * center_link_scale.x, (touch_pos_STc.y - 0.5) * center_link_scale.y, 0.0&amp;gt;;&lt;br /&gt;
&lt;br /&gt;
        // Calculate a unit vector from the touch position to the edge.&lt;br /&gt;
        vector edge_dir_center;&lt;br /&gt;
        // Find the nearest edge.&lt;br /&gt;
        vector edge_pos_center = touch_pos_center;&lt;br /&gt;
        if (center_link_scale.x * 0.5 - llFabs(edge_pos_center.x) &amp;gt; center_link_scale.y * 0.5 - llFabs(edge_pos_center.y))&lt;br /&gt;
        {&lt;br /&gt;
          integer positive = llRound(touch_pos_STc.y);&lt;br /&gt;
          edge_pos_center.y = (positive - 0.5) * center_link_scale.y;&lt;br /&gt;
          edge_dir_center = &amp;lt;0, positive * 2 - 1, 0&amp;gt;;&lt;br /&gt;
        }&lt;br /&gt;
        else&lt;br /&gt;
        {&lt;br /&gt;
          integer positive = llRound(touch_pos_STc.x);&lt;br /&gt;
          edge_pos_center.x = (positive - 0.5) * center_link_scale.x;&lt;br /&gt;
          edge_dir_center = &amp;lt;positive * 2 - 1, 0, 0&amp;gt;;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        // Convert edge_dir_center to link coordinates (because llLinkSitTarget takes link coordinates).&lt;br /&gt;
        vector edge_dir_link = edge_dir_center * center_rot_link;&lt;br /&gt;
&lt;br /&gt;
        // Calculate the rotation of the seated avatar from this direction, using the fact that we still have normal_dir_link.&lt;br /&gt;
        // This puts the fwd direction of the avatar in the direction edge_dir (from touch point to nearest edge)&lt;br /&gt;
        // and the up direction of the avatar perpendicular to the touched surface.&lt;br /&gt;
        rotation ac_rot_link = llAxes2Rot(edge_dir_link, normal_dir_link % edge_dir_link, normal_dir_link);&lt;br /&gt;
&lt;br /&gt;
        // Where do we want to sit?&lt;br /&gt;
        // Currently lets just sit where the user clicked, without limits or corrections.&lt;br /&gt;
        vector sit_pos_center = touch_pos_center;&lt;br /&gt;
&lt;br /&gt;
        // Convert the sit position to link coordinates (because llLinkSitTarget takes link coordinates).&lt;br /&gt;
        vector sit_pos_link = sit_pos_center * center_rot_link + center_pos_link;&lt;br /&gt;
&lt;br /&gt;
        // This vector is really a function of avatar shape and what looks&lt;br /&gt;
        // aesthetically pleasing. However, it is only minimal a function&lt;br /&gt;
        // avatar height (the only thing we can roughly know from a script)&lt;br /&gt;
        // and much more a function of shape values that we can&#039;t know.&lt;br /&gt;
        // So for now, just leave this as a constant.&lt;br /&gt;
        //&lt;br /&gt;
        // In ascii art, a sitting avatar looks more or less like this:&lt;br /&gt;
        //                ^&lt;br /&gt;
        //                |z&lt;br /&gt;
        //            ac_ |&lt;br /&gt;
        //               \S           &#039;S&#039; is the sittarget_pos_ac, in SL it is 0.05m above(_ac) &#039;O&#039;.&lt;br /&gt;
        //         &amp;lt;--x---O   ()      &#039;O&#039; is the Origin of ac (Avatar center (attach point) Coordinates).&lt;br /&gt;
        //                |   /|      &#039;*&#039; is the sittarget (as passed to llSitTarget) and is 0.4m below(_link) S.&lt;br /&gt;
        //    sittarget--&amp;gt;*__/_/&lt;br /&gt;
        //               _/   ^__ sit_pos_ac, 0.62 below(_ac) &#039;O&#039;, and 0.34 backwards(_ac).&lt;br /&gt;
        //                |&lt;br /&gt;
        vector sit_pos_ac = &amp;lt;-0.34, 0.0, -0.62&amp;gt;;&lt;br /&gt;
&lt;br /&gt;
        // Correct grid dependent sittarget_pos_ac.&lt;br /&gt;
        if (opensimver == 7)&lt;br /&gt;
        {&lt;br /&gt;
          sittarget_pos_ac.z = 0.0;&lt;br /&gt;
        }&lt;br /&gt;
        else if (opensimver == 8)&lt;br /&gt;
        {&lt;br /&gt;
          vector agentSize = llGetAgentSize(llDetectedKey(n));&lt;br /&gt;
          sittarget_pos_ac.z = agentSize.z / -37.9075; // Constant determined on &amp;quot;OpenSim 0.8.0 Dev&amp;quot;, April 2014.&lt;br /&gt;
          llSay(0, &amp;quot;sittarget_pos_ac = &amp;quot; + (string)sittarget_pos_ac);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        // Find the translation of the ac coordinate system.&lt;br /&gt;
        vector ac_pos_link = sit_pos_link - sit_pos_ac * ac_rot_link;&lt;br /&gt;
&lt;br /&gt;
        // Convert the sittarget from ac coordinates to link coordinates.&lt;br /&gt;
        vector sittarget_pos_link = sittarget_pos_ac * ac_rot_link + ac_pos_link;&lt;br /&gt;
&lt;br /&gt;
        // Grid dependent vertical offset.&lt;br /&gt;
        //&lt;br /&gt;
        // This is a historical offset introduced by Linden Lab from the beginning.&lt;br /&gt;
        // It is actually a mistake because when the avatar is rotated this causes&lt;br /&gt;
        // the avatar to move sideways! Apparently also Philips Linden found rotations&lt;br /&gt;
        // hard to understand.&lt;br /&gt;
        if (opensimver == 7)&lt;br /&gt;
        {&lt;br /&gt;
          // opensim version 0.7.6&lt;br /&gt;
          // Obviously, this should have been the same as on SL.&lt;br /&gt;
          // Later it got &amp;quot;corrected&amp;quot;, but in a wrong way (sittarget_pos_ac still differs with SL).&lt;br /&gt;
          sittarget_pos_link.z -= 0.418;&lt;br /&gt;
        }&lt;br /&gt;
        else&lt;br /&gt;
        {&lt;br /&gt;
          // SL and opensim &amp;gt;= 0.8.&lt;br /&gt;
          sittarget_pos_link.z -= 0.4;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        // Set the sit target.&lt;br /&gt;
        llLinkSitTarget(link, sittarget_pos_link, ac_rot_link);&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/lsl&amp;gt;&lt;/div&gt;</summary>
		<author><name>Timmy Foxclaw</name></author>
	</entry>
	<entry>
		<id>https://wiki.secondlife.com/w/index.php?title=User:Timmy_Foxclaw/About_Coordinate_Systems_and_Rotations&amp;diff=1189467</id>
		<title>User:Timmy Foxclaw/About Coordinate Systems and Rotations</title>
		<link rel="alternate" type="text/html" href="https://wiki.secondlife.com/w/index.php?title=User:Timmy_Foxclaw/About_Coordinate_Systems_and_Rotations&amp;diff=1189467"/>
		<updated>2014-04-15T15:13:23Z</updated>

		<summary type="html">&lt;p&gt;Timmy Foxclaw: Number important formulas.&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== About Coordinate Systems and Rotations ==&lt;br /&gt;
&lt;br /&gt;
=== The four coordinate systems ===&lt;br /&gt;
&lt;br /&gt;
There are four coordinate systems that are related to LSL programming:&lt;br /&gt;
# World coordinates&lt;br /&gt;
# Region coordinates&lt;br /&gt;
# Object coordinates (root prim coordinates)&lt;br /&gt;
# Child prim coordinates (coordinates relative to the prim that the script is in, or refered to by link number)&lt;br /&gt;
&lt;br /&gt;
The World coordinates refer to the map, and allow to include the sim&lt;br /&gt;
in the coordinates, or refer to void water.&lt;br /&gt;
&lt;br /&gt;
Region coordinates are relative to a given sim.&lt;br /&gt;
The origin is in the South/West corner at height 0.&lt;br /&gt;
The North/East corner then is 256, 256 and a Z coordinate&lt;br /&gt;
for the height up to 4096 meter (on opensim you can go even&lt;br /&gt;
higher).&lt;br /&gt;
&lt;br /&gt;
Object coordinates are relative to the root prim. Hence, if the object&lt;br /&gt;
is moved or rotated then the orientation of a child prim, when given&lt;br /&gt;
in object coordinates, doesn&#039;t change. In LSL &amp;quot;local position&amp;quot; and&lt;br /&gt;
&amp;quot;local rotation&amp;quot; refer to this coordinate system. &amp;quot;local&amp;quot; means&lt;br /&gt;
relative to the root prim.&lt;br /&gt;
&lt;br /&gt;
Prim Coordinates are relative to a given prim. If this prim is the root&lt;br /&gt;
prim then the Prim Coordinates are the same as the Object Coordinates.&lt;br /&gt;
For example, if a child prim is a cube with a size of 1,1,1 and one&lt;br /&gt;
red surface where the center of that surface is at 0.5,0,0 then it will&lt;br /&gt;
still be at 0.5,0,0 no matter how you move or rotate that child prim&lt;br /&gt;
(relative to the other linked prims).&lt;br /&gt;
&lt;br /&gt;
=== Positions ===&lt;br /&gt;
&lt;br /&gt;
A different position of the origin of a coordinate system is easy to understand:&lt;br /&gt;
You can think of positions as vectors that start in the origin of the&lt;br /&gt;
coordinate system that they are given in and end in the point that they&lt;br /&gt;
refer to. While the length of the vector is independent of the rotation of&lt;br /&gt;
the coordinate system, the three coordinates are not; but a mental picture&lt;br /&gt;
of an arrow doesn&#039;t have little numbers for three coordinates, so that&lt;br /&gt;
picture works independent of the rotation too.&lt;br /&gt;
&lt;br /&gt;
Since the rotation of the World Coordinate system and the Region Coordinate&lt;br /&gt;
system is the same (X, Y and Z axis are parallel of both), and since&lt;br /&gt;
World Coordinates aren&#039;t used in many LSL functions to begin with, we&lt;br /&gt;
will ignore World Coordinates for now and only refer to Region Coordinates,&lt;br /&gt;
or say &amp;quot;global&amp;quot; when we mean Region Coordinates.&lt;br /&gt;
&lt;br /&gt;
=== Rotations ===&lt;br /&gt;
&lt;br /&gt;
An LSL rotation internally stores a vector that is the axis around which&lt;br /&gt;
to rotate and the angle of the rotation around that axis.&lt;br /&gt;
Let &#039;&#039;&#039;V&#039;&#039;&#039; = &amp;amp;lt;u, v, w&amp;amp;gt; be the normalized vector (that is, with length 1) around&lt;br /&gt;
which we rotate and let &amp;amp;alpha; (alpha) be the angle around which we have to rotate.&lt;br /&gt;
Then the LSL rotation is a quaternion stored as r = &amp;amp;lt;x, y, z, s&amp;amp;gt; = &amp;amp;lt; &#039;&#039;&#039;V&#039;&#039;&#039; * sin(&amp;amp;alpha;/2), cos(&amp;amp;alpha;/2) &amp;amp;gt;.&lt;br /&gt;
Thus, r.x = x * sin(&amp;amp;alpha;/2), and r.s = cos(&amp;amp;alpha;/2) etc. Note that the quaternion&lt;br /&gt;
is also normalized.&lt;br /&gt;
Also note that there is a duality here because inverting &#039;&#039;&#039;V&#039;&#039;&#039; (making it point the&lt;br /&gt;
opposite way) and inverting the angle gives the same rotation; r and -r have&lt;br /&gt;
different values but are the same rotation.&lt;br /&gt;
Also note that if you don&#039;t rotate at all (&amp;amp;alpha; == 0) then it doesn&#039;t matter&lt;br /&gt;
what axis &#039;&#039;&#039;V&#039;&#039;&#039; you pick, which is apparent because &#039;&#039;&#039;V&#039;&#039;&#039; drops out since sin(0) = 0.&lt;br /&gt;
The quaternion &amp;amp;lt;0, 0, 0, 1&amp;amp;gt; is the ZERO_ROTATION quaternion.&lt;br /&gt;
&lt;br /&gt;
The point of this technical story is to show that for an LSL rotation to&lt;br /&gt;
make sense in terms of orientation, you need to be able to express a vector&lt;br /&gt;
in three coordinates (u, v, w above): the axis around which we rotate is&lt;br /&gt;
expressed relative to the X-, Y- and Z-axes of the coordinate system. Hence,&lt;br /&gt;
it is the orientation of the X-, Y- and Z-axes that defines the meaning&lt;br /&gt;
of a rotation in LSL.&lt;br /&gt;
&lt;br /&gt;
In terms of a mental picture the origin with the (orientation of the) three axis,&lt;br /&gt;
the red X-axis, the green Y-axis and the blue Z-axis is all the reference&lt;br /&gt;
we need, combined with a vector for position or a quaternion for rotation.&lt;br /&gt;
&lt;br /&gt;
When you edit an object, the viewer shows either &#039;World&#039; (meaning Region here) or &#039;Local&#039; axes, but&lt;br /&gt;
really the &#039;World&#039; (region) axes show the wrong origin, shifted to an averaged center&lt;br /&gt;
of the object, because if the origin was drawn at (0, 0, 0) you&#039;d most likely&lt;br /&gt;
not see it. The &#039;Local&#039; ruler shows the correct coordinate system for the&lt;br /&gt;
selected prim as its Prim Coordinate System. Selecting the root prim with&lt;br /&gt;
&#039;Local&#039; ruler on then shows the Object Coordinate System.&lt;br /&gt;
&lt;br /&gt;
=== The dimension of rotations ===&lt;br /&gt;
&lt;br /&gt;
As said before, given some coordinate system, any point in space can&lt;br /&gt;
be represented with a vector. Obviously space is three dimensional,&lt;br /&gt;
and thus vectors exists of three real values:&lt;br /&gt;
one needs three distinct floating point numbers, the x coordinate,&lt;br /&gt;
the y coordinate and the z coordinate to uniquely&lt;br /&gt;
identify a position in a given coordinate system.&lt;br /&gt;
&lt;br /&gt;
However, if one limits oneself to only normalized vectors, vectors&lt;br /&gt;
with a length of one, then those represent all points on the surface&lt;br /&gt;
of a sphere with radius 1.&lt;br /&gt;
A surface is obviously two dimensional, so it should be possible to&lt;br /&gt;
uniquely identify any point on the surface of such a sphere with&lt;br /&gt;
only two floating point numbers.&lt;br /&gt;
&lt;br /&gt;
One might think that selecting just two coordinates of the three of&lt;br /&gt;
the vector will suffice because the third is fixed by the length requirement,&lt;br /&gt;
but that only works for half spheres; for example, if x and y are known&lt;br /&gt;
then z can still be either plus the square root of x squared plus y squared,&lt;br /&gt;
&#039;&#039;or&#039;&#039; minus that value.&lt;br /&gt;
&lt;br /&gt;
Instead, a better choice would be the [http://mathworld.wolfram.com/SphericalCoordinates.html spherical coordinate system]&lt;br /&gt;
and express the unit vectors with the two angular coordinates &amp;amp;phi; (phi) and &amp;amp;theta; (theta),&lt;br /&gt;
where &amp;amp;phi; is the angle between the vector and the positive Z axis, and&lt;br /&gt;
&amp;amp;theta; the angle that the projection of the vector on to the X,Y plane makes&lt;br /&gt;
with the positive X axis. In other words, starting with a unit vector&lt;br /&gt;
along the positive Z-axis, one can obtain the required point on&lt;br /&gt;
the surface of the sphere by first rotating this vector around the&lt;br /&gt;
Y axis (towards the positive X axis) by an angle of &amp;amp;phi; and then rotating&lt;br /&gt;
the result around the Z-axis by an angle of &amp;amp;theta;. Note that in both cases&lt;br /&gt;
the rotations are counter-clockwise when one looks at it from the positive&lt;br /&gt;
side of the axis that one rotates around (towards the origin).&lt;br /&gt;
&lt;br /&gt;
What we just did was expressing a unit vector in terms of two rotations:&lt;br /&gt;
one around the Z axis and one around the Y axis; and indeed every rotation&lt;br /&gt;
can be expressed as two rotations around those two axis (or really, any&lt;br /&gt;
two arbitrary axes, as long as they are independent (not parallel)).&lt;br /&gt;
&lt;br /&gt;
It is therefore possible to represent unit vectors (aka, a &#039;&#039;direction&#039;&#039;)&lt;br /&gt;
with a rotation, as both are two dimensional. The mental picture here is&lt;br /&gt;
that any unit vector can be expressed as some fixed unit vector (for example&lt;br /&gt;
the one pointing along the positive Z axis, but any other would do as well)&lt;br /&gt;
and the rotation needed to turn that &#039;starting vector&#039; into the unit vector&lt;br /&gt;
that one wants to represent. The other way around almost works as well, with the&lt;br /&gt;
exception of the starting vector itself, as that can be expressed by any arbitrary&lt;br /&gt;
rotation around itself, so that information was lost and it is not possible&lt;br /&gt;
to know which of those rotations was used. In fact, any vector&lt;br /&gt;
close to the starting vector would give inaccurate results in the light&lt;br /&gt;
of floating point round off errors and is not a good way to represent&lt;br /&gt;
a rotation. Of course, the two dimensional vector (&amp;amp;theta;, &amp;amp;phi;) would be excellent&lt;br /&gt;
to represent both: the unit vector, as well as any rotation; but LSL stores&lt;br /&gt;
vectors in x, y, z coordinates, not in spherical coordinates.&lt;br /&gt;
&lt;br /&gt;
=== Converting between coordinate systems ===&lt;br /&gt;
&lt;br /&gt;
Consider a child prim of an object that is not the root prim and express&lt;br /&gt;
its position with the vector pos_oc, and its orientation with the rotation rot_oc,&lt;br /&gt;
both relative to the Object Coordinates system.&lt;br /&gt;
&lt;br /&gt;
A script inside that prim can easily obtain those values:&lt;br /&gt;
&lt;br /&gt;
 vector pos_oc = [[llGetLocalPos]]();&lt;br /&gt;
 rotation rot_oc = [[llGetLocalRot]]();&lt;br /&gt;
&lt;br /&gt;
The postfix &#039;_oc&#039; stands for Object Coordinates and is used to make clear&lt;br /&gt;
relative to which coordinate system the x, y and z values of both&lt;br /&gt;
variables are. Remember that also the rotation contains a vector&lt;br /&gt;
(the axis around which we rotate), so from now on we&#039;ll talk about&lt;br /&gt;
&#039;coordinates&#039; relative to a coordinate system for both, the position&lt;br /&gt;
as well as the rotation, where the coordinates refer to the x, y and z&lt;br /&gt;
components of the position and the rotation. For example, the first&lt;br /&gt;
sentence of this paragraph will read &amp;quot;...express its position with the&lt;br /&gt;
vector pos_oc, and its orientation with the rotation rot_oc, &#039;&#039;both in Object Coordinates&#039;&#039;.&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Note that&#039;&#039;&#039; one has to be careful here, because a script in the&lt;br /&gt;
root prim of the object will &#039;&#039;&#039;&#039;&#039;not&#039;&#039;&#039;&#039;&#039; obtain&lt;br /&gt;
Object Coordinates but instead Region Coordinates!&lt;br /&gt;
The reason is that the &#039;Local&#039; functions return coordinates relative to&lt;br /&gt;
the &#039;parent&#039; coordinate system, where the parent of a non-root prim is the root prim,&lt;br /&gt;
but the parent of the root prim is the region (or avatar in case&lt;br /&gt;
of an attachment). The position and rotation of the root prim in&lt;br /&gt;
Object Coordinates is trivial (ZERO_VECTOR and ZERO_ROTATION respectively).&lt;br /&gt;
&lt;br /&gt;
Back to the script in the child prim. It can also easily obtain its position&lt;br /&gt;
and rotation in Region Coordinates:&lt;br /&gt;
&lt;br /&gt;
 vector pos_rc = [[llGetPos]]();&lt;br /&gt;
 rotation rot_rc = [[llGetRot]]();&lt;br /&gt;
&lt;br /&gt;
Both sets, (pos_oc, rot_oc) and (pos_rc, rot_rc) refer to the same thing,&lt;br /&gt;
so it should be possible to convert them into each other.&lt;br /&gt;
&lt;br /&gt;
One can do this by looking at the orientation (position and rotation) of&lt;br /&gt;
one coordinate system relative to the other and expressed&lt;br /&gt;
in the coordinates of that other. The position and rotation&lt;br /&gt;
of the Object Coordinate System relative to the Region Coordinate&lt;br /&gt;
System, and in Region Coordinates, could be obtained as follows:&lt;br /&gt;
&lt;br /&gt;
 vector oc_pos_rc = [[llGetRootPosition]]();&lt;br /&gt;
 rotation oc_rot_rc = [[llGetRootRotation]]();&lt;br /&gt;
&lt;br /&gt;
As indicated by the &#039;_rc&#039; postfix, these are again in Region Coordinates.&lt;br /&gt;
&lt;br /&gt;
Having the relative orientation of the Object Coordinate System in Region Coordinates, it is&lt;br /&gt;
possible to convert Object Coordinates into Region Coordinates. More&lt;br /&gt;
abstractly put, if you have two coordinate systems A and B, and you have&lt;br /&gt;
their relative orientation expressed in A then you can convert orientations&lt;br /&gt;
expressed in B into A.&lt;br /&gt;
&lt;br /&gt;
The formula is as follows:&lt;br /&gt;
&lt;br /&gt;
 &#039;&#039;&#039;vector   pos_A = pos_B * B_rot_A + B_pos_A;            (1)&#039;&#039;&#039;&lt;br /&gt;
 &#039;&#039;&#039;rotation rot_A = rot_B * B_rot_A;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
The order of the multiplications is important; swapping the B_rot_A to the front will not work!&lt;br /&gt;
&lt;br /&gt;
Note that the B_*_A are the position and rotation of the coordinate system B expressed&lt;br /&gt;
in terms of the coordinate system A. The reason that I use the prefix and postfix in&lt;br /&gt;
this order is directly related to the order enforced for rotation multiplications.&lt;br /&gt;
Written this way, the left-hand postfix of a multiplication must match the right-hand prefix&lt;br /&gt;
and conviently short-circuits the notation:&lt;br /&gt;
&lt;br /&gt;
 something_A = something&#039;&#039;&#039;_B&#039;&#039;&#039; * &#039;&#039;&#039;B_&#039;&#039;&#039;rot_A&lt;br /&gt;
&lt;br /&gt;
the two B&#039;s &#039;connect&#039; and drop out (along with the &#039;_rot_&#039;) to give something_ ... A.&lt;br /&gt;
This &#039;&#039;only&#039;&#039; works when the postfix (_A or _B) refers to the coordinate system that the variables&lt;br /&gt;
are in, and the prefix is whatever is described by the variable, possibly another&lt;br /&gt;
coordinate system (B_ in this example).&lt;br /&gt;
&lt;br /&gt;
A complete example script follows:&lt;br /&gt;
&amp;lt;lsl&amp;gt;&lt;br /&gt;
default&lt;br /&gt;
{&lt;br /&gt;
    touch(integer num_detected)&lt;br /&gt;
    {&lt;br /&gt;
        llSay(0, &amp;quot;---------&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
        // Get the pos and rot in Object Coordinates.&lt;br /&gt;
        vector pos_oc = llGetLocalPos();&lt;br /&gt;
        rotation rot_oc = llGetLocalRot();&lt;br /&gt;
        &lt;br /&gt;
        // Fix these values when this script is in the root prim!&lt;br /&gt;
        if (llGetLinkNumber() &amp;lt;= 1)&lt;br /&gt;
        {&lt;br /&gt;
            pos_oc = ZERO_VECTOR;&lt;br /&gt;
            rot_oc = ZERO_ROTATION;&lt;br /&gt;
        }&lt;br /&gt;
        &lt;br /&gt;
        // Get the pos and rot in Region Coordinates.&lt;br /&gt;
        vector pos_rc = llGetPos();&lt;br /&gt;
        rotation rot_rc = llGetRot();&lt;br /&gt;
        &lt;br /&gt;
        // Get the pos and rot of the Object Coordinate System in Region Coordinates.&lt;br /&gt;
        vector oc_pos_rc = llGetRootPosition();&lt;br /&gt;
        rotation oc_rot_rc = llGetRootRotation();&lt;br /&gt;
        &lt;br /&gt;
        // Print the values of the positions (the rotations are too hard to understand).&lt;br /&gt;
        llSay(0, &amp;quot;oc_pos_rc = &amp;quot; + (string)oc_pos_rc);&lt;br /&gt;
        llSay(0, &amp;quot;pos_os = &amp;quot; + (string)pos_os);&lt;br /&gt;
        llSay(0, &amp;quot;pos_rc = &amp;quot; + (string)pos_rc);&lt;br /&gt;
        &lt;br /&gt;
        // Calculate pos_rc and rot_rc from pos_oc and rot_oc : converting between _oc and _rc.&lt;br /&gt;
        vector   pos2_rc = pos_oc * oc_rot_rc + oc_pos_rc;&lt;br /&gt;
        rotation rot2_rc = rot_oc * oc_rot_rc;&lt;br /&gt;
        &lt;br /&gt;
        // Print the result for the position, and show the difference with what llGetPos() and llGetRot() returned.&lt;br /&gt;
        llSay(0, &amp;quot;pos2_rc = &amp;quot; + (string)pos2_rc);&lt;br /&gt;
        // These values should be ZERO_VECTOR and ZERO_ROTATION (or -ZERO_ROTATION).&lt;br /&gt;
        llSay(0, &amp;quot;pos_rc - pos2_rc = &amp;quot; + (string)(pos_rc - pos2_rc));&lt;br /&gt;
        llSay(0, &amp;quot;rot_rc / rot2_rc = &amp;quot; + (string)(rot_rc / rot2_rc));&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/lsl&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Obviously there is no preference for one coordinate system over the other for this conversion;&lt;br /&gt;
one can equally as well convert orientations in A into B:&lt;br /&gt;
&lt;br /&gt;
 vector   pos_B = pos_A * A_rot_B + A_pos_B;&lt;br /&gt;
 rotation rot_B = rot_A * A_rot_B;&lt;br /&gt;
&lt;br /&gt;
The question arises then how to obtain the A_*_B values; there is no LSL function that returns directly&lt;br /&gt;
the position or rotation of the region relative to a prim (aka, rc_*_oc).&lt;br /&gt;
&lt;br /&gt;
Intuitively one would say that it has to be possible to express A_*_B in B_*_A on grounds of symmetry, and that&lt;br /&gt;
is indeed the case.&lt;br /&gt;
&lt;br /&gt;
To show how this works, lets just take the formula for pos_A and rot_A (see (1) above) and rework&lt;br /&gt;
them to get pos_B and rot_B on the left-hand side. This results first in&lt;br /&gt;
&lt;br /&gt;
 pos_B * B_rot_A = pos_A - B_pos_A&lt;br /&gt;
 rot_B * B_rot_A = rot_A&lt;br /&gt;
&lt;br /&gt;
Then divide both sides by B_rot_A to get:&lt;br /&gt;
&lt;br /&gt;
 pos_B = pos_A / B_rot_A - B_pos_A / B_rot_A&lt;br /&gt;
 rot_B = rot_A / B_rot_A&lt;br /&gt;
&lt;br /&gt;
from which we can conclude that&lt;br /&gt;
&lt;br /&gt;
 &#039;&#039;&#039;A_pos_B = - B_pos_A / B_rot_A                           (2)&#039;&#039;&#039;&lt;br /&gt;
 &#039;&#039;&#039;A_rot_B = ZERO_ROTATION / B_rot_A&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Note how A_rot_B is the inverse of B_rot_A: A_rot_B * B_rot_A = ZERO_ROTATION.&lt;br /&gt;
As per our notation convention you&#039;d expect A_rot_B * B_rot_A to be A_rot_A, and that is&lt;br /&gt;
actually the case as A_rot_A means the relative orientation of coordinate system A&lt;br /&gt;
expressed in A&#039;s coordinates, which is the trivial ZERO_VECTOR and ZERO_ROTATION as&lt;br /&gt;
we saw before for the root prim orientation expressed in Object Coordinates.&lt;br /&gt;
&lt;br /&gt;
And for fun, note that if we do this inversion again we get:&lt;br /&gt;
&lt;br /&gt;
 B_pos_A = - A_pos_B / A_rot_B = - (- B_pos_A / B_rot_A) / (ZERO_ROTATION / B_rot_A) = B_pos_A / B_rot_A * B_rot_A = B_pos_A&lt;br /&gt;
 B_rot_A = ZERO_ROTATION / A_rot_B = ZERO_ROTATION / (ZERO_ROTATION / B_rot_A) = B_rot_A&lt;br /&gt;
&lt;br /&gt;
as expected.&lt;br /&gt;
&lt;br /&gt;
We can now also convert Region Coordinates to Object Coordinates.&lt;br /&gt;
&lt;br /&gt;
One could first calculate,&lt;br /&gt;
&lt;br /&gt;
 vector rc_pos_oc = - llGetRootPosition() / llGetRootRotation();&lt;br /&gt;
 rotation rc_rot_oc = ZERO_ROTATION / llGetRootRotation();&lt;br /&gt;
&lt;br /&gt;
and then convert as usual:&lt;br /&gt;
&lt;br /&gt;
 vector   pos_oc = pos_rc * rc_rot_oc + rc_pos_oc;&lt;br /&gt;
 rotation rot_oc = rot_rc * rc_rot_oc;&lt;br /&gt;
&lt;br /&gt;
or if you don&#039;t want to calculate the intermediate rc_*_oc values, you could do immediately:&lt;br /&gt;
&lt;br /&gt;
 vector   pos_oc = (pos_rc - llGetRootPosition()) / llGetRootRotation();&lt;br /&gt;
 rotation rot_oc = rot_rc / llGetRootRotation();&lt;br /&gt;
&lt;br /&gt;
To verify this, you could extend the above script with&lt;br /&gt;
&amp;lt;lsl&amp;gt;&lt;br /&gt;
        // Calculate pos_oc and rot_oc from pos_rc and rot_rc.&lt;br /&gt;
        vector   pos2_oc = (pos_rc - llGetRootPosition()) / llGetRootRotation();&lt;br /&gt;
        rotation rot2_oc = rot_rc / llGetRootRotation();&lt;br /&gt;
        &lt;br /&gt;
        llSay(0, &amp;quot;pos2_oc = &amp;quot; + (string)pos2_oc);&lt;br /&gt;
        // These values should again be ZERO_VECTOR and +/- ZERO_ROTATION.&lt;br /&gt;
        llSay(0, &amp;quot;pos_oc - pos2_oc = &amp;quot; + (string)(pos_oc - pos2_oc));&lt;br /&gt;
        llSay(0, &amp;quot;rot_oc / rot2_oc = &amp;quot; + (string)(rot_oc / rot2_oc));&lt;br /&gt;
&amp;lt;/lsl&amp;gt;&lt;br /&gt;
&lt;br /&gt;
More in general, if you want to convert from B to A, but you only have A_*_B instead of B_*_A, then (combining (1) and (2))&lt;br /&gt;
you can do:&lt;br /&gt;
&lt;br /&gt;
 &#039;&#039;&#039;vector   pos_A = (pos_B - A_pos_B) / A_rot_B;           (3)&#039;&#039;&#039;&lt;br /&gt;
 &#039;&#039;&#039;rotation rot_A = rot_B / A_rot_B;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
=== Cascading coordinate systems ===&lt;br /&gt;
&lt;br /&gt;
Imagine you have a castle object where the floor is the root prim. Everything is linked because you&lt;br /&gt;
want it to be easy to move the castle around. One of the child prims is a sculpty representing the hinges&lt;br /&gt;
around which you want to rotate a large gate. The gate has a rotating wheel on it.&lt;br /&gt;
&lt;br /&gt;
You want that the object (castle) to keep working when it is moved and/or rotated, but also when it is edited&lt;br /&gt;
and the hinges are moved and/or rotated. This means that the state of the gate prims&lt;br /&gt;
must be &#039;&#039;stored&#039;&#039; relative to the hinges, which is by far the easiest thing to do to begin with,&lt;br /&gt;
after all, the gate rotates around the hinges and has no relation with the rest of the castle.&lt;br /&gt;
&lt;br /&gt;
Hence, we have the Region Coordinate System, the Object Coordinate System (the castle) and the Hinges Coordinate System.&lt;br /&gt;
The latter is our first example of a Prim Coordinates System, but I&#039;ll use the postfix &#039;_hc&#039; for &amp;quot;Hinges Coordinates&amp;quot;&lt;br /&gt;
instead of &#039;_pc&#039;. Finally we have the Spill Coordinate System (or Gate Coordinates) where the spill is a prim&lt;br /&gt;
around which we want to rotate the wheel, and I&#039;ll use &#039;_sc&#039; as postfix for that.&lt;br /&gt;
&lt;br /&gt;
The variables used then would be an orientation for the wheel in *_sc coordinates, the orientation of the spill,&lt;br /&gt;
and other gate prims, in *_hc coordinates and the orientation of the hinges in *_oc coordinates. Finally we could&lt;br /&gt;
have variables for the orientation of the castle (root prim) in *_rc coordinates of course.&lt;br /&gt;
&lt;br /&gt;
 vector   castle_pos_rc; // The position of the castle in Region Coordinates.&lt;br /&gt;
 rotation castle_rot_rc; // The rotation of the castle in Region Coordinates.&lt;br /&gt;
 &lt;br /&gt;
 vector   hinges_pos_oc; // The position of the hinges in Object Coordinates.&lt;br /&gt;
 rotation hinges_rot_oc; // The rotation of the hinges in Object Coordinates.&lt;br /&gt;
 &lt;br /&gt;
 vector   spill_pos_hc;  // The position of the spill in Hinges Coordinates.&lt;br /&gt;
 rotation spill_rot_hc;  // The rotation of the spill in Hinges Coordinates.&lt;br /&gt;
 &lt;br /&gt;
 vector   wheel_pos_sc;  // The position of the wheel in Spill Coordinates.&lt;br /&gt;
 rotation wheel_rot_sc;  // The rotation of the wheel in Spill Coordinates.&lt;br /&gt;
&lt;br /&gt;
Now because we used existing prims orientations as coordinate system for the next prim, the position&lt;br /&gt;
and rotation of those prims &#039;&#039;are&#039;&#039; the position and rotation of that coordinate system.&lt;br /&gt;
Just like before we saw that llGetPos/llGetRot returns the global orientation of the root prim&lt;br /&gt;
when used in a script in the root prim, while llGetRootPos/llGetRootRot gave us the relative&lt;br /&gt;
orientation of the Object Coordinate System in Region Coordinates, but is in fact the same as&lt;br /&gt;
what llGetPos/llGetRot in the root prim returns: the position/rotation of the root prim &#039;&#039;&#039;is&#039;&#039;&#039;&lt;br /&gt;
the orientation of the Object Coordinate System relative to the Region.&lt;br /&gt;
&lt;br /&gt;
Likewise, in this case, castle_*_rc is the relative orientation of the Object Coordinate System&lt;br /&gt;
in Region Coordinates as well as the orientation of the root prim in Region Coordinates; they&lt;br /&gt;
are the same thing.&lt;br /&gt;
&lt;br /&gt;
The same then applies to the *_oc variables, which we defined as the orientation of&lt;br /&gt;
the hinges in Object Coordinates, but at the same time are the relative orientation&lt;br /&gt;
of the Hinges Coordinate System in Object Coordinates. The *_hc variables are the&lt;br /&gt;
orientation of spill in Hinges Coordinates, but also the relative orientation of&lt;br /&gt;
the Spill Coordinates in Hinges Coordinates.&lt;br /&gt;
&lt;br /&gt;
Lets write it out using the same notation convention as used above, then&lt;br /&gt;
we have:&lt;br /&gt;
&lt;br /&gt;
 vector   oc_pos_rc = castle_pos_rc; // The Object Coordinate System orientation in Region Coordinates.&lt;br /&gt;
 rotation oc_rot_rc = castle_rot_rc;&lt;br /&gt;
 &lt;br /&gt;
 vector   hc_pos_oc = hinges_pos_oc; // The Hinges Coordinate System orientation in Object Coordinates.&lt;br /&gt;
 rotation hc_rot_oc = hinges_rot_oc;&lt;br /&gt;
 &lt;br /&gt;
 vector   sc_pos_hc = spill_pos_hc;  // The Spill Coordinate System orientation in Hinges Coordinates.&lt;br /&gt;
 rotation sc_rot_hc = spill_rot_hc;&lt;br /&gt;
&lt;br /&gt;
It will therefore probably not surprise you that&lt;br /&gt;
&lt;br /&gt;
 vector   hc_pos_rc = hc_pos_oc * oc_rot_rc + oc_pos_rc; // The Hinges Coordinate System orientation in Region Coordinates.&lt;br /&gt;
 rotation hc_rot_rc = hc_rot_oc * oc_rot_rc;&lt;br /&gt;
 &lt;br /&gt;
 vector   sc_pos_rc = sc_pos_hc * hc_rot_rc + hc_pos_rc; // The Spill Coordinate System orientation in Region Coordinates.&lt;br /&gt;
 rotation sc_rot_rc = sc_rot_hc * hc_rot_rc;&lt;br /&gt;
&lt;br /&gt;
And finally, using the latter, we can express the wheel orientation in region coordinates:&lt;br /&gt;
&lt;br /&gt;
 vector   wheel_pos_rc = wheel_pos_sc * sc_rot_rc + sc_pos_rc;&lt;br /&gt;
 rotation wheel_rot_rc = wheel_rot_sc * sc_rot_rc;&lt;br /&gt;
&lt;br /&gt;
Although this was nothing else but applying the coordinate system conversion formula ((1)) three times,&lt;br /&gt;
it might give some insight to get rid of the intermediate variables and express the wheel&lt;br /&gt;
orientation in region coordinates without them, giving:&lt;br /&gt;
&lt;br /&gt;
 wheel_pos_rc = ((wheel_pos_sc * sc_rot_hc + sc_pos_hc) * hc_rot_oc + hc_pos_oc) * oc_rot_rc + oc_pos_rc&lt;br /&gt;
 wheel_rot_rc = wheel_rot_sc * sc_rot_hc * hc_rot_oc * oc_rot_rc&lt;br /&gt;
&lt;br /&gt;
=== Applying rotations and translations ===&lt;br /&gt;
&lt;br /&gt;
Applying rotations and translations (moving) is very much the same as coordinate system transformations described above.&lt;br /&gt;
To show this consider the following: imagine you have a prim &#039;pa&#039; with its own coordinate system A.&lt;br /&gt;
Then it trivially has position ZERO_VECTOR and rotation ZERO_ROTATION relative to A, per definition.&lt;br /&gt;
&lt;br /&gt;
 vector   pa_pos_A = ZERO_VECTOR;&lt;br /&gt;
 rotation pa_rot_A = ZERO_ROTATION;&lt;br /&gt;
&lt;br /&gt;
Now consider a prim &#039;pb&#039; that has some relative position pb_pos_A and rotation pb_rot_A given in A coordinates.&lt;br /&gt;
For example,&lt;br /&gt;
&lt;br /&gt;
 vector   pb_pos_A = &amp;lt;0.5, 0.6, 0.7&amp;gt;;&lt;br /&gt;
 rotation pb_rot_A = &amp;lt;0.38, 0.26, 0.34, 0.82&amp;gt;;&lt;br /&gt;
&lt;br /&gt;
Note that 0.38&amp;amp;sup2; + 0.26&amp;amp;sup2; + 0.34&amp;amp;sup2; + 0.82&amp;amp;sup2; = 1, as it must be since rotations are normalized.&lt;br /&gt;
&lt;br /&gt;
As seen before, the orientation of pb relative to pa is the same as the orientation of pb relative to A,&lt;br /&gt;
and the same as the orientation of B relative to A. pa and A are interchangeable as long as pa has&lt;br /&gt;
ZERO_VECTOR and ZERO_ROTATION relative to A. Thus, with B being the coordinate system where pb currently&lt;br /&gt;
is, we also have:&lt;br /&gt;
&lt;br /&gt;
 vector   B_pos_A = pb_pos_A; // The orientation of coordinate system B, in coordinates of A.&lt;br /&gt;
 rotation B_rot_A = pb_rot_A;&lt;br /&gt;
&lt;br /&gt;
Now suppose we want move the prim pa (without moving the coordinate system A),&lt;br /&gt;
by applying the translation &#039;B_pos_A&#039;, after all a translation is stored in a vector&lt;br /&gt;
and B_pos_A is a vector. Likewise, we want to rotate pa (again without influencing A)&lt;br /&gt;
by applying the rotation B_rot_A. Then the most logical order to this in is by&lt;br /&gt;
&#039;&#039;first&#039;&#039; applying the rotation and &#039;&#039;then&#039;&#039; applying the translation, because then&lt;br /&gt;
the meaning of the translation is preserved and will match the meaning of B_pos_A&lt;br /&gt;
in that pa will end up where pb is now. If you&#039;d first apply the translation so that&lt;br /&gt;
pa ends up where pb is, and then apply the rotation (around A!) then pa would swoop&lt;br /&gt;
around the origin of A and move away from its desired position.&lt;br /&gt;
&lt;br /&gt;
Doing this correctly should leave us with pa_pos_A == pb_pos_A and pa_rot_A == pb_rot_A,&lt;br /&gt;
so that pa ended up precisely where pb is now. We can&#039;t just assign those values&lt;br /&gt;
however, because we&#039;re looking for a formula that works in general; a way to apply&lt;br /&gt;
B_rot_A and then B_pos_A to any prim with -say- orientation pc_pos_A, pc_rot_A.&lt;br /&gt;
&lt;br /&gt;
Thus, first we apply the rotation:&lt;br /&gt;
&lt;br /&gt;
 pc_rot_A *= B_rot_A;&lt;br /&gt;
 pc_pos_A *= B_rot_A;&lt;br /&gt;
&lt;br /&gt;
And then apply the translation:&lt;br /&gt;
&lt;br /&gt;
 pc_pos_A += B_pos_A;&lt;br /&gt;
&lt;br /&gt;
Now lets check if indeed this would cause pa to end up where pb is.&lt;br /&gt;
The effect on pa_*_A would be:&lt;br /&gt;
&lt;br /&gt;
 pa_rot_A = pa_rot_A * B_rot_A = ZERO_ROTATION * B_rot_A = B_rot_A = pb_rot_A;&lt;br /&gt;
 pa_pos_A = pa_pos_A * B_rot_A = ZERO_VECTOR * B_rot_A = ZERO_VECTOR;&lt;br /&gt;
 &lt;br /&gt;
 and then the translation&lt;br /&gt;
 &lt;br /&gt;
 pa_pos_A = pa_pos_A + B_pos_A = ZERO_VECTOR + B_pos_A = B_pos_A = pb_pos_A;&lt;br /&gt;
&lt;br /&gt;
So yes, pa_*_A ends up as pb_*_A!&lt;br /&gt;
&lt;br /&gt;
The real test however would be if we first applied some transformation to pa&lt;br /&gt;
to bring it to some arbitrary orientation (aka, pc), then apply the transformation&lt;br /&gt;
B_rot_A,B_pos_A and then reverse the first transformation but now relative to B,&lt;br /&gt;
and then find that we indeed end up at pb.&lt;br /&gt;
&lt;br /&gt;
Let us first define a &#039;transformation&#039;, which exists of a vector for the&lt;br /&gt;
translation and a rotation for the rotation. We will have two transformations&lt;br /&gt;
during this test: t1: pa -&amp;gt; pc, and t2: pa -&amp;gt; pb.&lt;br /&gt;
&lt;br /&gt;
As we just saw (or we hope this is going to be the case), t2 can be defined as:&lt;br /&gt;
&lt;br /&gt;
 vector   t2_translation = B_pos_A;&lt;br /&gt;
 rotation t2_rotation = B_rot_A;&lt;br /&gt;
&lt;br /&gt;
where as t1 is arbitrary, just some values t1_translation and t1_rotation.&lt;br /&gt;
&lt;br /&gt;
Applying t1 to pa, we get (this is thus the same as above, but now with the &#039;t1&#039; notation):&lt;br /&gt;
&lt;br /&gt;
 pa_rot_A *= t1_rotation;&lt;br /&gt;
 pa_pos_A *= t1_rotation;&lt;br /&gt;
 pa_pos_A += t1_translation;&lt;br /&gt;
&lt;br /&gt;
Next we apply translation t2 to that:&lt;br /&gt;
&lt;br /&gt;
 pa_rot_A *= t2_rotation;&lt;br /&gt;
 pa_pos_A *= t2_rotation;&lt;br /&gt;
 pa_pos_A += t2_translation;&lt;br /&gt;
&lt;br /&gt;
Finally we want to reverse t1, but in the coordinate system of B.&lt;br /&gt;
Therefore, we first convert our coordinates to that of B (formula (1)):&lt;br /&gt;
&lt;br /&gt;
 pa_pos_B = pa_pos_A * A_rot_B + A_pos_B;&lt;br /&gt;
 pa_rot_B = pa_rot_A * A_rot_B;&lt;br /&gt;
&lt;br /&gt;
where (formula (2))&lt;br /&gt;
&lt;br /&gt;
 A_pos_B = - B_pos_A / B_rot_A;&lt;br /&gt;
 A_rot_B = ZERO_ROTATION / B_rot_A;&lt;br /&gt;
&lt;br /&gt;
and then reverse t1. Note now we have to do the translation first!&lt;br /&gt;
&lt;br /&gt;
 pa_pos_B -= t1_translation;&lt;br /&gt;
 pa_pos_B /= t1_rotation;&lt;br /&gt;
 pa_rot_B /= t1_rotation;&lt;br /&gt;
&lt;br /&gt;
And if everything worked out then pa now should be at ZERO_VECTOR, ZERO_ROTATION relative to B!&lt;br /&gt;
&lt;br /&gt;
As pa_pos_A,pa_rot_A started as ZERO_VECTOR,ZERO_ROTATION, the first step&lt;br /&gt;
of applying t1 resulted in pa_rot_A = t1_rotation and pa_pos_A = t1_translation.&lt;br /&gt;
&lt;br /&gt;
After applying t2 we get pa_rot_A = t1_rotation * t2_rotation, and pa_pos_A = t1_translation * t2_rotation + t2_translation.&lt;br /&gt;
&lt;br /&gt;
Converting that to B gives&lt;br /&gt;
&lt;br /&gt;
 pa_pos_B = (t1_translation * t2_rotation + t2_translation) * A_rot_B + A_pos_B&lt;br /&gt;
 pa_rot_B = (t1_rotation * t2_rotation) * A_rot_B&lt;br /&gt;
&lt;br /&gt;
where, remembering that t2_translation = B_pos_A and t2_rotation = B_rot_A,&lt;br /&gt;
&lt;br /&gt;
 A_pos_B = - B_pos_A / B_rot_A = - t2_translation / t2_rotation&lt;br /&gt;
 A_rot_B = ZERO_ROTATION / B_rot_A = ZERO_ROTATION / t2_rotation&lt;br /&gt;
&lt;br /&gt;
so that we get&lt;br /&gt;
&lt;br /&gt;
 pa_pos_B = (t1_translation * t2_rotation + t2_translation) / t2_rotation - t2_translation / t2_rotation = t1_translation&lt;br /&gt;
 pa_rot_B = (t1_rotation * t2_rotation) / t2_rotation = t1_rotation&lt;br /&gt;
&lt;br /&gt;
and finally reversing t1 gives:&lt;br /&gt;
&lt;br /&gt;
 pa_pos_B = (t1_translation - t1_translation) / t1_rotation = ZERO_VECTOR&lt;br /&gt;
 pa_rot_B = t1_rotation / t1_rotation = ZERO_ROTATION&lt;br /&gt;
&lt;br /&gt;
So that we can conclude that if you have two prims pa and pb, each representing their own coordinate system A and B respectively,&lt;br /&gt;
and you express the orientation of B relative to A as the pair (B_pos_A, B_rot_A) &amp;amp;mdash; then the following holds.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;The transformation pair (t_translation, t_rotation) equals (B_pos_A, B_rot_A) as long as you first apply the rotation and then the translation while working in the coordinate system of A&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
The latter is also very practical, because you normally won&#039;t know&lt;br /&gt;
anything about the target coordinate system B until you actually did the transformation.&lt;br /&gt;
&lt;br /&gt;
Now remember that we found that in order to convert variables from being relative to a coordinate system B to a coordinate system A,&lt;br /&gt;
we did (formula (1)):&lt;br /&gt;
&lt;br /&gt;
 pos_A = pos_B * B_rot_A + B_pos_A&lt;br /&gt;
 rot_A = rot_B * B_rot_A&lt;br /&gt;
&lt;br /&gt;
which is thus exactly the same as first applying the rotation t1_rotation and then the translation t1_translation&lt;br /&gt;
on the pair (pos_B, rot_B) where that pair is relative to A! That isn&#039;t too weird because if you consider a prim&lt;br /&gt;
in the origin of A with no rotation, aka (ZERO_VECTOR, ZERO_ROTATION) relative to A and then apply the transformation&lt;br /&gt;
then you expect to end up in the origin of B with no rotation relative to B. Aka pos_B = ZERO_VECTOR and rot_B = ZERO_ROTATION.&lt;br /&gt;
So now work backwards: assume you already have the prim in B like that, then what are its coordinates in A?&lt;br /&gt;
That would be the above conversion thus, with pos_B = ZERO_VECTOR and rot_B = ZERO_ROTATION.&lt;br /&gt;
&lt;br /&gt;
Hence, doing the conversion with ZERO as input gives the same results as doing the t transformation with ZERO as input!&lt;br /&gt;
And the final formula for a transformation just looks exactly the same:&lt;br /&gt;
&lt;br /&gt;
 &#039;&#039;&#039;target_pos_A = source_pos_A * t_rotation + t_translation        (4)&#039;&#039;&#039;&lt;br /&gt;
 &#039;&#039;&#039;target_rot_A = source_rot_A * t_rotation&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
=== Scaling coordinate systems ===&lt;br /&gt;
&lt;br /&gt;
Apart from rotation and translation, there is one more linear operator that can be used to convert&lt;br /&gt;
between coordinate systems: scaling.&lt;br /&gt;
&lt;br /&gt;
Let A_pos_B be the position of the origin of A in the coordinates of B. Let A_rot_B be the orientation of A within B,&lt;br /&gt;
and let the vector A_B_scale be the scaling factors for each axes. Scaling has no influence on the origin of&lt;br /&gt;
a coordinate system, but it matters for the rotation when the scaling factors per axis are different.&lt;br /&gt;
&lt;br /&gt;
I think that a good choice is scale first and rotate afterwards. Because that leaves the values&lt;br /&gt;
of the coordinates of A_rot_B alone: it remains the rotation as defined in B, which makes sense&lt;br /&gt;
since it is written in the coordinates of B. However, it&#039;s just a matter of choice really, which&lt;br /&gt;
in this case will deform B_rot_A instead of A_rot_B. I can imagine that the choice might depend&lt;br /&gt;
on the application.&lt;br /&gt;
&lt;br /&gt;
Chosing that we first scale, a point at pos_A is mapped onto the point pos_B as follows:&lt;br /&gt;
&lt;br /&gt;
 pos_B = (S * pos_A) * A_rot_B + A_pos_B&lt;br /&gt;
&lt;br /&gt;
where S is a 3x3 matrix with as diagonal the vector A_B_scale (and the rest zeroes).&lt;br /&gt;
Note that when each element of A_B_scale is the same then you can just use a scalar for S, equal to the scale of each axis.&lt;br /&gt;
&lt;br /&gt;
Whether or not S is a matrix or a scalar, lets just replace it with &#039;A_B_scale&#039; here. Just keep in&lt;br /&gt;
mind that if it isn&#039;t a scalar then this won&#039;t work in LSL directly: then you&#039;ll have to split&lt;br /&gt;
it up in three different code lines because LSL doesn&#039;t support scaling or matrices.&lt;br /&gt;
&lt;br /&gt;
  pos_B = pos_A;&lt;br /&gt;
  pos_B.x *= A_B_scale.x;  // Scale&lt;br /&gt;
  pos_B.y *= A_B_scale.y;&lt;br /&gt;
  pos_B.z *= A_B_scale.z;&lt;br /&gt;
  pos_B *= A_rot_B;        // Rotate&lt;br /&gt;
  pos_B += A_pos_B;        // Translate&lt;br /&gt;
&lt;br /&gt;
Note that the inverse of S, 1/S, is a 3x3 matrix with as diagonal the inverse of each element of A_B_scale.&lt;br /&gt;
We will either write &#039;B_A_scale&#039;, or divide by &#039;A_B_scale&#039; in our notation.&lt;br /&gt;
&lt;br /&gt;
Therefore our notation becomes:&lt;br /&gt;
&lt;br /&gt;
 pos_B = (&#039;A_B_scale&#039; * pos_A) * A_rot_B + A_pos_B&lt;br /&gt;
&lt;br /&gt;
Since A and B are arbitrary, we would expect the same formula to hold when swapping A and B:&lt;br /&gt;
&lt;br /&gt;
 pos_A = (&#039;B_A_scale&#039; * pos_B) * B_rot_A + B_pos_A&lt;br /&gt;
&lt;br /&gt;
Solving pos_B from that by subtracting B_pos_A from both sides, then dividing both sides by B_rot_A&lt;br /&gt;
and finally left multiplying both sides with the inverse of B_A_scale, gives:&lt;br /&gt;
&lt;br /&gt;
 pos_B = &#039;A_B_scale&#039; * ((pos_A - B_pos_A) / B_rot_A) = &#039;A_B_scale&#039; * (pos_A / B_rot_A) - &#039;A_B_scale&#039; * (B_pos_A / B_rot_A)&lt;br /&gt;
&lt;br /&gt;
from which we can conclude (by setting pos_A to ZERO_VECTOR) that&lt;br /&gt;
&lt;br /&gt;
 A_pos_B = -&#039;A_B_scale&#039; * (B_pos_A / B_rot_A)&lt;br /&gt;
&lt;br /&gt;
Solving B_pos_A from that by left multiplying both sides with -B_A_scale and then right multiplying both sides with B_rot_A, gives:&lt;br /&gt;
&lt;br /&gt;
 B_pos_A = - (&#039;B_A_scale&#039; * A_pos_B) * B_rot_A&lt;br /&gt;
&lt;br /&gt;
By setting A_pos_B to ZERO_VECTOR, and this B_pos_A too, we can also conclude that&lt;br /&gt;
&lt;br /&gt;
 (&#039;A_B_scale&#039; * pos_A) * A_rot_B = &#039;A_B_scale&#039; * (pos_A / B_rot_A)&lt;br /&gt;
&lt;br /&gt;
If &#039;A_B_scale&#039; is a scalar, so that the order of multiplication doesn&#039;t matter,&lt;br /&gt;
then the scale just cancels on both sides and we find the conversion that we&lt;br /&gt;
found before, that B_rot_A is the inverse of A_rot_B. However, if A_B_scale&lt;br /&gt;
is a diagonal matrix then the order matters and the brackets are significant.&lt;br /&gt;
&lt;br /&gt;
There is no way to let pos_A drop out: we cannot write B_rot_A as function&lt;br /&gt;
of A_B_scale and A_rot_B.&lt;br /&gt;
&lt;br /&gt;
The conclusion is that a scale is asymmetrical: if you choose that a scale A_B_scale&lt;br /&gt;
means that you first apply the scale on a vector in A and then rotate, then&lt;br /&gt;
that automatically implies that when going from B to A you first have to rotate&lt;br /&gt;
and &#039;&#039;then&#039;&#039; apply the scale.&lt;br /&gt;
&lt;br /&gt;
To make the choice clear in the name, I suggest to put an &#039;r&#039; in front of the&lt;br /&gt;
coordinate system that need rotation to be applied first. &lt;br /&gt;
&lt;br /&gt;
In summary, if A_rB_scale is defined as&lt;br /&gt;
&lt;br /&gt;
 &#039;&#039;&#039;pos_B = (&#039;A_rB_scale&#039; * pos_A) * A_rot_B + A_pos_B      (5)&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
then that implies that rB_A_scale has to be applied after rotation.&lt;br /&gt;
Note this means braces, NOT changing the left- or right- side of&lt;br /&gt;
multiplications! Matrices (scales) are always on the left side&lt;br /&gt;
of a vector, while rotations are always on the right side. Thus we get: &lt;br /&gt;
&lt;br /&gt;
 &#039;&#039;&#039;pos_A = &#039;rB_A_scale&#039; * (pos_B * B_rot_A) + B_pos_A      (6)&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
If now we solve pos_B from the latter, we get:&lt;br /&gt;
&lt;br /&gt;
 pos_B = (&#039;A_rB_scale&#039; * (pos_A - B_pos_A)) / B_rot_A = (&#039;A_rB_scale&#039; * pos_A) / B_rot_A - (&#039;A_rB_scale&#039; * B_pos_A) / B_rot_A&lt;br /&gt;
&lt;br /&gt;
Hence&lt;br /&gt;
&lt;br /&gt;
 &#039;&#039;&#039;B_pos_A = - &#039;rB_A_scale&#039; * (A_pos_B / A_rot_B)          (7)&#039;&#039;&#039;&lt;br /&gt;
 &#039;&#039;&#039;B_rot_A = ZERO_ROTATION / A_rot_B&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
and&lt;br /&gt;
&lt;br /&gt;
 &#039;&#039;&#039;A_pos_B = - (&#039;A_rB_scale&#039; * B_posA) / B_rot_A           (8)&#039;&#039;&#039;&lt;br /&gt;
 &#039;&#039;&#039;A_rot_B = ZERO_ROTATION / B_rot_A&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Note how these two sets condense into the same thing when the scale is a scalar,&lt;br /&gt;
but also when A_rot_B and B_rot_A are ZERO_ROTATION. In fact, when the rotation&lt;br /&gt;
involved is of the special case of one or more rotations of 90 degrees around&lt;br /&gt;
any of the axes, so that the rotation merely swaps axes, one could define&lt;br /&gt;
the inverse of A_B_scale by applying that rotation to that vector (swapping&lt;br /&gt;
the scaling factors), next to inverting each factor individually.&lt;br /&gt;
That is a different way of how we defined B_A_scale, but it would collapse&lt;br /&gt;
the two sets into one for that special set of rotations. I&#039;m using that trick&lt;br /&gt;
in the example script below.&lt;br /&gt;
&lt;br /&gt;
=== Direction vectors ===&lt;br /&gt;
&lt;br /&gt;
A &#039;direction&#039; is a normalized vector (its length is 1), or unit vector, where only the direction&lt;br /&gt;
it points to is important.&lt;br /&gt;
&lt;br /&gt;
Of course, in the light of rotations between coordinate systems, also the directions&lt;br /&gt;
are relative to some coordinate system.&lt;br /&gt;
&lt;br /&gt;
As stated before, using some &#039;starting&#039; unit vector a rotation can be expressed&lt;br /&gt;
as a direction by applying the rotation to a starting vector. Reversing this&lt;br /&gt;
process runs into floating point round off errors however, or might even have lost&lt;br /&gt;
all information of the rotation when we rotate around the starting vector itself.&lt;br /&gt;
&lt;br /&gt;
There is a better way to convert directions (back) to a rotation however: by using &#039;&#039;two&#039;&#039;&lt;br /&gt;
directions that are perpendicular, each having a unit vector along one of the axes&lt;br /&gt;
as starting vector. That way there is always at least one vector enough rotated away&lt;br /&gt;
from the actual rotation axis in order not to suffer from (too much) information loss.&lt;br /&gt;
&lt;br /&gt;
For example, let us use the unit vector along the positive X axis and the unit vector&lt;br /&gt;
along the positive Z axis. In LSL those are often called fwd and up respectively.&lt;br /&gt;
Furthermore, lets work in a coordinate system A. Then we have the &#039;starting&#039; vectors:&lt;br /&gt;
&lt;br /&gt;
 &#039;&#039;&#039;vector A_fwd_A  = &amp;lt;1, 0, 0&amp;gt;;            (9)&#039;&#039;&#039;&lt;br /&gt;
 &#039;&#039;&#039;vector A_left_A = &amp;lt;0, 1, 0&amp;gt;;&#039;&#039;&#039;&lt;br /&gt;
 &#039;&#039;&#039;vector A_up_A   = &amp;lt;0, 0, 1&amp;gt;;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
We said we only knew the fwd and up directions, but the third can always be&lt;br /&gt;
calculated from the other two with a cross product:&lt;br /&gt;
&lt;br /&gt;
 &#039;&#039;&#039;A_fwd_B  = A_left_B % A_up_B;           (10)&#039;&#039;&#039;&lt;br /&gt;
 &#039;&#039;&#039;A_left_B = A_up_B % A_fwd_B;&#039;&#039;&#039;&lt;br /&gt;
 &#039;&#039;&#039;A_up_B   = A_fwd_B % A_left_B;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Hence, the cross product exists of the other two in the order left to right where after &#039;up&#039; you start at &#039;fwd&#039; again; they rotate: ... left up fwd left up fwd ...&lt;br /&gt;
Put a &#039;=&#039; at any space in that sequence and a &#039;%&#039; at the next space and you have the right formula. Also note that x % y = - y % x, in case you were wondering.&lt;br /&gt;
&lt;br /&gt;
Now assume we have the target directions A_*_B, then we can find the rotation between&lt;br /&gt;
A and B with:&lt;br /&gt;
&lt;br /&gt;
 &#039;&#039;&#039;A_rot_B = [[llAxes2Rot]](A_fwd_B, A_left_B, A_up_B);       (11)&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Where A_rot_B is the rotation that turns A_*_A into A_*_B:&lt;br /&gt;
&lt;br /&gt;
 A_fwd_B  = A_fwd_A  * A_rot_B&lt;br /&gt;
 A_left_B = A_left_A * A_rot_B&lt;br /&gt;
 A_up_B   = A_up_A   * A_rot_B&lt;br /&gt;
&lt;br /&gt;
=== Finding coordinate systems ===&lt;br /&gt;
&lt;br /&gt;
Assume you already have a coordinate system B (for example, region or object coordinates, the orientations of which you can find directly with [[#LSL functions]]).&lt;br /&gt;
&lt;br /&gt;
Finding coordinate system A means that you find A_rot_B (or B_rot_A which is just the inverse), and A_pos_B or B_pos_A.&lt;br /&gt;
&lt;br /&gt;
Finding the rotation is usually the easiest since it doesn&#039;t depend on where the origin is and can most likely&lt;br /&gt;
be derived somehow. For example, in many cases you will have two orthogonal direction vectors in B that you know&lt;br /&gt;
to be parallel with the x, y or z axes of A. Lets say that you have AsX_dir_B and a AsY_dir_B that make an angle&lt;br /&gt;
of 90 degrees and have a length of 1, where AsX_dir_B is known to be parallel with the X axis of A and AsY_dir_B&lt;br /&gt;
is known to be parallel with the Y axis of A. Note that in this case we can also use the notation A_fwd_B for AsX_dir_B since&lt;br /&gt;
&#039;fwd&#039; is in the X direction (AsX_dir_B means &amp;quot;A&#039;s X-axis direction in coordinates of B&amp;quot;, and A_fwd_B means &amp;quot;A&#039;s&lt;br /&gt;
forwards direction in coordinates of B&amp;quot;, so they are the same thing). Then we find:&lt;br /&gt;
&lt;br /&gt;
 A_rot_B = [[llAxes2Rot]](AsX_dir_B, AsY_dir_B, AsX_dir_B % AsY_dir_B);&lt;br /&gt;
&lt;br /&gt;
as discussed in the previous paragraph.&lt;br /&gt;
&lt;br /&gt;
Next, if you have a vector from_B_to_A pointing from the origin of B to the origin of A, then you have&lt;br /&gt;
the translation between A and B too:&lt;br /&gt;
&lt;br /&gt;
If from_B_to_A is in coordinates of A, then&lt;br /&gt;
&lt;br /&gt;
 B_pos_A = -from_B_to_A&lt;br /&gt;
&lt;br /&gt;
while if from_B_to_A is in coordinates of B, then&lt;br /&gt;
&lt;br /&gt;
 A_pos_B = from_B_to_A&lt;br /&gt;
&lt;br /&gt;
Slight counter intuitive you have to read &#039;A_pos_B&#039; as &#039;The vector pointing from the origin of B to the origin of A&#039;,&lt;br /&gt;
but plausible since it is in the coordinates of B and thus you should expect the vector to start in the origin&lt;br /&gt;
of B.&lt;br /&gt;
&lt;br /&gt;
If you have a series of vectors that are stacked, all the way from B to A, then of course you just add them all up&lt;br /&gt;
to get A_pos_B. Likewise, if you have a series of vectors in the coordinates of A that are stacked to add up&lt;br /&gt;
to go from A to B, then add them all up to get B_pos_A.&lt;br /&gt;
&lt;br /&gt;
The interesting case therefore is where you have a vector C_pos_A that points from A to C and is in the coordinates&lt;br /&gt;
of A, and a vector C_pos_B that points from B to C and is in the coordinates of B.&lt;br /&gt;
&lt;br /&gt;
To solve this puzzle, lets first write the vectors slightly different so we&#039;re not confused about&lt;br /&gt;
what they mean, even after converting between the coordinate systems A and B.&lt;br /&gt;
&lt;br /&gt;
Let AC_vec_A be C_pos_A: the vector (arrow) from the origin of A to C (in coordinates of A) and&lt;br /&gt;
let BC_vec_B be C_pos_B: the vector from the origin of B to C (in the coordinates of B).&lt;br /&gt;
Note how the notation of _vec_ is similar to that of _dir_, except that a direction vector has&lt;br /&gt;
a length of 1, and this vector has both a direction and a length: it describes how to get from&lt;br /&gt;
one point to another. Like directions, when converting them between A and B you ONLY&lt;br /&gt;
apply the rotation A_rot_B! Also note that a vector with a minus sign just means &amp;quot;in the opposite direction&amp;quot;,&lt;br /&gt;
hence CA_vec_A = -AC_vec_A.&lt;br /&gt;
&lt;br /&gt;
Thus, we find that&lt;br /&gt;
&lt;br /&gt;
 AC_vec_B = AC_vec_A * A_rot_B&lt;br /&gt;
&lt;br /&gt;
and find&lt;br /&gt;
&lt;br /&gt;
 A_pos_B = BA_vec_B = BC_vec_B + CA_vec_B = BC_vec_B - AC_vec_B = BC_vec_B - AC_vec_A * A_rot_B&lt;br /&gt;
&lt;br /&gt;
then dropping the extra notation again&lt;br /&gt;
&lt;br /&gt;
 &#039;&#039;&#039;A_pos_B = C_pos_B - C_pos_A * A_rot_B&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Which is rather logical when you read it in English as &amp;quot;To go from B to A in coordinates of B (A_pos_B),&lt;br /&gt;
you first go from B to C in coordinates of B (C_pos_B) and then in the opposite direction (the minus sign)&lt;br /&gt;
of going from A to C (namely from C to A) converted to the coordinates of B.&lt;br /&gt;
&lt;br /&gt;
And oh wonder - if we write this result a little different we find:&lt;br /&gt;
&lt;br /&gt;
 C_pos_A = (C_pos_B - A_pos_B) / A_rot_B&lt;br /&gt;
&lt;br /&gt;
which is the normal conversion (formula (3)) for the position of C from A to B coordinates!&lt;br /&gt;
&lt;br /&gt;
=== LSL functions ===&lt;br /&gt;
&lt;br /&gt;
What all of the above taught you is mainly a coding style: use prefixes and postfixes for your rotations (and translations)!&lt;br /&gt;
It&#039;s all in the &#039;&#039;&#039;&#039;&#039;names&#039;&#039;&#039;&#039;&#039; of your variables. A &#039;rotation&#039; type can be the rotation part of a transformation&lt;br /&gt;
(not tied to a particular coordinate system, but rather rotating around whatever coordinate system you apply it to),&lt;br /&gt;
it can be the representation of a unit vector, it can be the rotation part of the orientation of a prim relative to a&lt;br /&gt;
given coordinate system, or it can represent the rotation part of a coordinate system conversion.&lt;br /&gt;
If you don&#039;t use a consistent way to reflect all that in your variable names then you &#039;&#039;will&#039;&#039; get confused.&lt;br /&gt;
&lt;br /&gt;
The LSL functions mostly deal with two types: orientations (position + rotation) of prims relative to some coordinate system,&lt;br /&gt;
and simply transformations (rotation and/or translation).&lt;br /&gt;
&lt;br /&gt;
The table below shows the coordinate systems involved.&lt;br /&gt;
&lt;br /&gt;
{| rules=&amp;quot;all&amp;quot; style=&amp;quot;margin:2em 1em 2em 1em; border:none 2px #000000; background-color:#F9F9F9; font-size:120%; empty-cells:hide;&amp;quot;&lt;br /&gt;
 |-&lt;br /&gt;
 | colspan=2 |&lt;br /&gt;
 | style=&amp;quot;padding: 5px 10px 5px 10px; background-color: #ffdddd; text-align: center&amp;quot; colspan=2 | Coordinates of the prim containing the script (&#039;&#039;&#039;sc_&#039;&#039;&#039;)&lt;br /&gt;
 |- {{Hl2}}&lt;br /&gt;
 ! style=&amp;quot;padding: 5px 10px 5px 10px; color: blue; background-color: #eeeeb0&amp;quot; | Coordinate System&lt;br /&gt;
 ! style=&amp;quot;padding: 5px 10px 5px 10px; color: green; background-color: lightgray&amp;quot; | Abbreviation &lt;br /&gt;
 ! style=&amp;quot;padding: 5px 10px 5px 10px&amp;quot; | script in child prim&lt;br /&gt;
 ! style=&amp;quot;padding: 5px 10px 5px 10px&amp;quot; | script in root prim&lt;br /&gt;
 |-&lt;br /&gt;
 | style=&amp;quot;padding: 5px 10px 5px 10px; color: blue; background-color: #ffffa0&amp;quot; | World/Map Coordinates&lt;br /&gt;
 | style=&amp;quot;padding: 5px 10px 5px 10px&amp;quot;                                         | &#039;&#039;&#039;wc&#039;&#039;&#039;&lt;br /&gt;
 | style=&amp;quot;padding: 5px 10px 5px 10px&amp;quot; colspan=2                               | &amp;lt;span style=&amp;quot;font-family: mono; font-size: 90%&amp;quot;&amp;gt;sc_pos_&#039;&#039;&#039;wc&#039;&#039;&#039; = sc_pos_rc + [[llGetRegionCorner]]()&amp;lt;br&amp;gt;sc_rot_&#039;&#039;&#039;wc&#039;&#039;&#039; = sc_rot_rc&amp;lt;/span&amp;gt;&lt;br /&gt;
 |-&lt;br /&gt;
 | style=&amp;quot;padding: 5px 10px 5px 10px; color: blue; background-color: #ffffa0&amp;quot; | Region Coordinates&lt;br /&gt;
 | style=&amp;quot;padding: 5px 10px 5px 10px&amp;quot;                                         | &#039;&#039;&#039;rc&#039;&#039;&#039;&lt;br /&gt;
 | style=&amp;quot;padding: 5px 10px 5px 10px&amp;quot; colspan=2                               | &amp;lt;span style=&amp;quot;font-family: mono; font-size: 90%&amp;quot;&amp;gt;sc_pos_&#039;&#039;&#039;rc&#039;&#039;&#039; = [[llGetPos]]()&amp;lt;br&amp;gt;sc_rot_&#039;&#039;&#039;rc&#039;&#039;&#039; = [[llGetRot]]()&amp;lt;/span&amp;gt;&lt;br /&gt;
 |-&lt;br /&gt;
 | style=&amp;quot;padding: 5px 10px 5px 10px; color: blue; background-color: #ffffa0&amp;quot; | Object/Root Coordinates&lt;br /&gt;
 | style=&amp;quot;padding: 5px 10px 5px 10px&amp;quot;                                         | &#039;&#039;&#039;oc&#039;&#039;&#039;&lt;br /&gt;
 | style=&amp;quot;padding: 5px 10px 5px 10px&amp;quot;                                         | &amp;lt;span style=&amp;quot;font-family: mono; font-size: 90%&amp;quot;&amp;gt;sc_pos_&#039;&#039;&#039;oc&#039;&#039;&#039; = [[llGetLocalPos]]()&amp;lt;br&amp;gt;sc_rot_&#039;&#039;&#039;oc&#039;&#039;&#039; = [[llGetLocalRot]]()&amp;lt;/span&amp;gt;&lt;br /&gt;
 | style=&amp;quot;padding: 5px 10px 5px 10px&amp;quot;                                         | &amp;lt;span style=&amp;quot;font-family: mono; font-size: 90%&amp;quot;&amp;gt;sc_pos_&#039;&#039;&#039;oc&#039;&#039;&#039; = [[ZERO_VECTOR]]&amp;lt;br&amp;gt;sc_rot_&#039;&#039;&#039;oc&#039;&#039;&#039; = [[ZERO_ROTATION]]&amp;lt;/span&amp;gt;&lt;br /&gt;
 |-&lt;br /&gt;
 | style=&amp;quot;padding: 5px 10px 5px 10px; color: blue; background-color: #ffffa0&amp;quot; | Self Coordinates&lt;br /&gt;
 | style=&amp;quot;padding: 5px 10px 5px 10px&amp;quot;                                         | &#039;&#039;&#039;sc&#039;&#039;&#039;&lt;br /&gt;
 | style=&amp;quot;padding: 5px 10px 5px 10px&amp;quot; colspan=2                               | &amp;lt;span style=&amp;quot;font-family: mono; font-size: 90%&amp;quot;&amp;gt;sc_pos_&#039;&#039;&#039;sc&#039;&#039;&#039; = [[ZERO_VECTOR]]&amp;lt;br&amp;gt;sc_rot_&#039;&#039;&#039;sc&#039;&#039;&#039; = [[ZERO_ROTATION]]&amp;lt;/span&amp;gt;&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
Where &#039;in the root prim&#039; can be detect by testing that [[llGetLinkNumber]]() returns a value &amp;lt;= 1.&lt;br /&gt;
&lt;br /&gt;
Alternatively, you can set link = [[llGetLinkNumber]]() and use the following table which&lt;br /&gt;
shows how to obtain the coordinates of a prim with link number &#039;link&#039; from a script anywhere in the same object.&lt;br /&gt;
Note that this doesn&#039;t work when the object exist of a single prim: then [[llGetLinkNumber]]() returns 0,&lt;br /&gt;
while &#039;link&#039; must be larger than 0 here. If you need to get Object Coordinates (_oc) then do not use the&lt;br /&gt;
negative value [[LINK_THIS]]. You can use [[LINK_THIS]] for the other coordinate systems, provided&lt;br /&gt;
the object exists of at least two prims.&lt;br /&gt;
&lt;br /&gt;
{| rules=&amp;quot;all&amp;quot; style=&amp;quot;margin:2em 1em 2em 1em; border:none 2px #000000; background-color:#F9F9F9; font-size:120%; empty-cells:hide;&amp;quot;&lt;br /&gt;
 |-&lt;br /&gt;
 | colspan=2 |&lt;br /&gt;
 | style=&amp;quot;padding: 5px 10px 5px 10px; background-color: #ffdddd; text-align: center&amp;quot; colspan=2 | Coordinates of a linked prim (&#039;&#039;&#039;link_&#039;&#039;&#039;)&lt;br /&gt;
 |- {{Hl2}}&lt;br /&gt;
 ! style=&amp;quot;padding: 5px 10px 5px 10px; color: blue; background-color: #eeeeb0&amp;quot; | Coordinate System&lt;br /&gt;
 ! style=&amp;quot;padding: 5px 10px 5px 10px; color: green; background-color: lightgray&amp;quot; | Abbreviation &lt;br /&gt;
 ! style=&amp;quot;padding: 5px 10px 5px 10px&amp;quot; | link &amp;gt; 1&lt;br /&gt;
 ! style=&amp;quot;padding: 5px 10px 5px 10px&amp;quot; | link = 1&lt;br /&gt;
 |-&lt;br /&gt;
 | style=&amp;quot;padding: 5px 10px 5px 10px; color: blue; background-color: #ffffa0&amp;quot; | World/Map Coordinates&lt;br /&gt;
 | style=&amp;quot;padding: 5px 10px 5px 10px&amp;quot;                                         | &#039;&#039;&#039;wc&#039;&#039;&#039;&lt;br /&gt;
 | style=&amp;quot;padding: 5px 10px 5px 10px&amp;quot; colspan=2                               | &amp;lt;span style=&amp;quot;font-family: mono; font-size: 90%&amp;quot;&amp;gt;link_pos_&#039;&#039;&#039;wc&#039;&#039;&#039; = link_pos_rc + [[llGetRegionCorner]]()&amp;lt;br&amp;gt;link_rot_&#039;&#039;&#039;wc&#039;&#039;&#039; = link_rot_rc&amp;lt;/span&amp;gt;&lt;br /&gt;
 |-&lt;br /&gt;
 | style=&amp;quot;padding: 5px 10px 5px 10px; color: blue; background-color: #ffffa0&amp;quot; | Region Coordinates&lt;br /&gt;
 | style=&amp;quot;padding: 5px 10px 5px 10px&amp;quot;                                         | &#039;&#039;&#039;rc&#039;&#039;&#039;&lt;br /&gt;
 | style=&amp;quot;padding: 5px 10px 5px 10px&amp;quot; colspan=2                               | &amp;lt;span style=&amp;quot;font-family: mono; font-size: 90%&amp;quot;&amp;gt;link_pos_&#039;&#039;&#039;rc&#039;&#039;&#039; = [[llList2Vector]]([[llGetLinkPrimitiveParams]](&#039;&#039;&#039;link&#039;&#039;&#039;, [&amp;lt;span&amp;gt;&amp;lt;/span&amp;gt;[[PRIM_POSITION]]]), 0)&amp;lt;br&amp;gt;link_rot_&#039;&#039;&#039;rc&#039;&#039;&#039; = [[llList2Rot]]([[llGetLinkPrimitiveParams]](&#039;&#039;&#039;link&#039;&#039;&#039;, [&amp;lt;span&amp;gt;&amp;lt;/span&amp;gt;[[PRIM_ROTATION]]]), 0)&amp;lt;/span&amp;gt;&lt;br /&gt;
 |-&lt;br /&gt;
 | style=&amp;quot;padding: 5px 10px 5px 10px; color: blue; background-color: #ffffa0&amp;quot; | Object/Root Coordinates&lt;br /&gt;
 | style=&amp;quot;padding: 5px 10px 5px 10px&amp;quot;                                         | &#039;&#039;&#039;oc&#039;&#039;&#039;&lt;br /&gt;
 | style=&amp;quot;padding: 5px 10px 5px 10px&amp;quot;                                         | &amp;lt;span style=&amp;quot;font-family: mono; font-size: 90%&amp;quot;&amp;gt;link_pos_&#039;&#039;&#039;oc&#039;&#039;&#039; = [[llList2Vector]]([[llGetLinkPrimitiveParams]](&#039;&#039;&#039;link&#039;&#039;&#039;, [&amp;lt;span&amp;gt;&amp;lt;/span&amp;gt;[[PRIM_POS_LOCAL]]]), 0)&amp;lt;br&amp;gt;link_rot_&#039;&#039;&#039;oc&#039;&#039;&#039; = [[llList2Rot]]([[llGetLinkPrimitiveParams]](&#039;&#039;&#039;link&#039;&#039;&#039;, [&amp;lt;span&amp;gt;&amp;lt;/span&amp;gt;[[PRIM_ROT_LOCAL]]]), 0)&amp;lt;/span&amp;gt;&lt;br /&gt;
 | style=&amp;quot;padding: 5px 10px 5px 10px&amp;quot;                                         | &amp;lt;span style=&amp;quot;font-family: mono; font-size: 90%&amp;quot;&amp;gt;link_pos_&#039;&#039;&#039;oc&#039;&#039;&#039; = [[ZERO_VECTOR]]&amp;lt;br&amp;gt;link_rot_&#039;&#039;&#039;oc&#039;&#039;&#039; = [[ZERO_ROTATION]]&amp;lt;/span&amp;gt;&lt;br /&gt;
 |-&lt;br /&gt;
 | style=&amp;quot;padding: 5px 10px 5px 10px; color: blue; background-color: #ffffa0&amp;quot; | Self Coordinates&lt;br /&gt;
 | style=&amp;quot;padding: 5px 10px 5px 10px&amp;quot;                                         | &#039;&#039;&#039;sc&#039;&#039;&#039;&lt;br /&gt;
 | style=&amp;quot;padding: 5px 10px 5px 10px&amp;quot; colspan=2                               | &amp;lt;span style=&amp;quot;font-family: mono; font-size: 90%&amp;quot;&amp;gt;link_pos_&#039;&#039;&#039;sc&#039;&#039;&#039; = (link_pos_oc - sc_pos_oc) / sc_rot_oc&amp;lt;br&amp;gt;link_rot_&#039;&#039;&#039;sc&#039;&#039;&#039; = link_rot_oc / sc_rot_oc&amp;lt;/span&amp;gt;&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
While the above table works for link = [[LINK_ROOT]], it is probably more convenient to use the following table:&lt;br /&gt;
&lt;br /&gt;
{| rules=&amp;quot;all&amp;quot; style=&amp;quot;margin:2em 1em 2em 1em; border:none 2px #000000; background-color:#F9F9F9; font-size:120%; empty-cells:hide;&amp;quot;&lt;br /&gt;
 |-&lt;br /&gt;
 | colspan=2 |&lt;br /&gt;
 | style=&amp;quot;padding: 5px 10px 5px 10px; background-color: #ffdddd; text-align: center&amp;quot; colspan=2 | Coordinates of the root prim (&#039;&#039;&#039;oc_&#039;&#039;&#039;)&lt;br /&gt;
 |- {{Hl2}}&lt;br /&gt;
 ! style=&amp;quot;padding: 5px 10px 5px 10px; color: blue; background-color: #eeeeb0&amp;quot; | Coordinate System&lt;br /&gt;
 ! style=&amp;quot;padding: 5px 10px 5px 10px; color: green; background-color: lightgray&amp;quot; | Abbreviation &lt;br /&gt;
 ! style=&amp;quot;padding: 5px 10px 5px 10px&amp;quot; | script in any prim&lt;br /&gt;
 |-&lt;br /&gt;
 | style=&amp;quot;padding: 5px 10px 5px 10px; color: blue; background-color: #ffffa0&amp;quot; | World/Map Coordinates&lt;br /&gt;
 | style=&amp;quot;padding: 5px 10px 5px 10px&amp;quot;                                         | &#039;&#039;&#039;wc&#039;&#039;&#039;&lt;br /&gt;
 | style=&amp;quot;padding: 5px 10px 5px 10px&amp;quot;                                         | &amp;lt;span style=&amp;quot;font-family: mono; font-size: 90%&amp;quot;&amp;gt;oc_pos_&#039;&#039;&#039;wc&#039;&#039;&#039; = oc_pos_rc + [[llGetRegionCorner]]()&amp;lt;br&amp;gt;oc_rot_&#039;&#039;&#039;wc&#039;&#039;&#039; = oc_rot_rc&amp;lt;/span&amp;gt;&lt;br /&gt;
 |-&lt;br /&gt;
 | style=&amp;quot;padding: 5px 10px 5px 10px; color: blue; background-color: #ffffa0&amp;quot; | Region Coordinates&lt;br /&gt;
 | style=&amp;quot;padding: 5px 10px 5px 10px&amp;quot;                                         | &#039;&#039;&#039;rc&#039;&#039;&#039;&lt;br /&gt;
 | style=&amp;quot;padding: 5px 10px 5px 10px&amp;quot;                                         | &amp;lt;span style=&amp;quot;font-family: mono; font-size: 90%&amp;quot;&amp;gt;oc_pos_&#039;&#039;&#039;rc&#039;&#039;&#039; = [[llGetRootPosition]]()&amp;lt;br&amp;gt;oc_rot_&#039;&#039;&#039;rc&#039;&#039;&#039; = [[llGetRootRotation]]()&amp;lt;/span&amp;gt;&lt;br /&gt;
 |-&lt;br /&gt;
 | style=&amp;quot;padding: 5px 10px 5px 10px; color: blue; background-color: #ffffa0&amp;quot; | Object/Root Coordinates&lt;br /&gt;
 | style=&amp;quot;padding: 5px 10px 5px 10px&amp;quot;                                         | &#039;&#039;&#039;oc&#039;&#039;&#039;&lt;br /&gt;
 | style=&amp;quot;padding: 5px 10px 5px 10px&amp;quot;                                         | &amp;lt;span style=&amp;quot;font-family: mono; font-size: 90%&amp;quot;&amp;gt;oc_pos_&#039;&#039;&#039;oc&#039;&#039;&#039; = [[ZERO_VECTOR]]&amp;lt;br&amp;gt;oc_rot_&#039;&#039;&#039;oc&#039;&#039;&#039; = [[ZERO_ROTATION]]&amp;lt;/span&amp;gt;&lt;br /&gt;
 |-&lt;br /&gt;
 | style=&amp;quot;padding: 5px 10px 5px 10px; color: blue; background-color: #ffffa0&amp;quot; | Self Coordinates&lt;br /&gt;
 | style=&amp;quot;padding: 5px 10px 5px 10px&amp;quot;                                         | &#039;&#039;&#039;sc&#039;&#039;&#039;&lt;br /&gt;
 | style=&amp;quot;padding: 5px 10px 5px 10px&amp;quot;                                         | &amp;lt;span style=&amp;quot;font-family: mono; font-size: 90%&amp;quot;&amp;gt;oc_pos_&#039;&#039;&#039;sc&#039;&#039;&#039; = - sc_pos_oc / sc_rot_oc&amp;lt;br&amp;gt;oc_rot_&#039;&#039;&#039;sc&#039;&#039;&#039; = [[ZERO_ROTATION]] / sc_rot_oc&amp;lt;/span&amp;gt;&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
As shows from the above table, LSL does not directly support &#039;&#039;&#039;_sc&#039;&#039;&#039; coordinates,&lt;br /&gt;
and I used conversions to fill in the tables. All in all, we listed four coordinate systems (wc, rc, oc and sc; not including the &#039;link_&#039; stuff,&lt;br /&gt;
which isn&#039;t really a separate coordinate system)&lt;br /&gt;
and thus could write out four times four is sixteen ways to convert one into the other. Four of those would be trivial, and of the remaining&lt;br /&gt;
twelve we can express six as the inverse of the other six.&lt;br /&gt;
&lt;br /&gt;
However, lets ignore the World Coordinates for now, which are just the same as the Region Coordinates with an offset for the position.&lt;br /&gt;
Then we have three coordinate systems (rc, oc and sc), leading to nine conversion, three of which are trivial, and of the remaining&lt;br /&gt;
six three can be expressed as the inverse of the other three. Those three are: oc_*_rc, sc_*_rc and sc_*_oc, which are all listed above.&lt;br /&gt;
The trivial ones, rc_*_rc, oc_*_oc and sc_*_sc, are all ZERO_* (the latter two also are listed in the tables above).&lt;br /&gt;
Finally, the inverse values, rc_*_oc, rc_*_sc and oc_*_sc can be expressed with the inversion formula given in [[#Converting between coordinate systems]].&lt;br /&gt;
So this is really all there is.&lt;br /&gt;
&lt;br /&gt;
=== The fourth dimension ===&lt;br /&gt;
&lt;br /&gt;
Picture a coordinate system as three perpendicular lines, like an object in-world perhaps existing of&lt;br /&gt;
three really long prims in the colors red, green and blue. You can toss them into the region&lt;br /&gt;
where they randomly bounce around like dice &amp;amp;ndash; a whole bunch of them!&lt;br /&gt;
And then you freeze time - make a snapshot.&lt;br /&gt;
&lt;br /&gt;
With the knowledge so far you can now express the position and rotation of an object or prim relative&lt;br /&gt;
to any of those coordinate systems &amp;amp;ndash; and convert between them at will.&lt;br /&gt;
Apply rotations and translations relative to any chosen system.&lt;br /&gt;
All of the coordinate systems are virtually the same! But in practice this isn&#039;t the case, why is that?&lt;br /&gt;
&lt;br /&gt;
The reason is that in practice coordinate systems change in time, in a way that you cannot predict.&lt;br /&gt;
It&#039;s like they are still tumbling and bouncing around and you have no idea where they are.&lt;br /&gt;
&lt;br /&gt;
This noise comes mainly from one thing: objects are being moved. Taken into repositories and rezzed back,&lt;br /&gt;
rotated and possibly even scaled! In fact, not just objects, but also prims inside objects can be changed&lt;br /&gt;
at will at any moment and a good script must take that into account.&lt;br /&gt;
&lt;br /&gt;
The art of programming therefore becomes &#039;&#039;design&#039;&#039;. You must choose which coordinate systems you&lt;br /&gt;
want to use; what your global variables store, relative to which coordinate system.&lt;br /&gt;
&lt;br /&gt;
Unfortunately, a script can &#039;&#039;not&#039;&#039; detect when this might have happened and only perform extra computations&lt;br /&gt;
or re-computation, of otherwise constant variables, when a prim or object has actually been changed.&lt;br /&gt;
There is an LSL event [[moving_start]] but that only works half on SL and not at all on opensim.&lt;br /&gt;
For rotation detection there is nothing.&lt;br /&gt;
&lt;br /&gt;
As such, it is necessary to call the LSL functions listed in the tables above every time you&lt;br /&gt;
want to do anything that depends on them; which hopefully won&#039;t be too often.&lt;br /&gt;
&lt;br /&gt;
The following example script can be put in the root prim of an object of any number of cubes&lt;br /&gt;
and allows one to sit on each cube, using [[llLinkSitTarget]], even when you move or rotate&lt;br /&gt;
child prims.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;lsl&amp;gt;&lt;br /&gt;
// A script written to show how to use coordinate systems in LSL.&lt;br /&gt;
//&lt;br /&gt;
// Copyright(c) Timmy Songbird @DreamNation&lt;br /&gt;
//              Timmy Foxclaw  @SL,&lt;br /&gt;
//              2014&lt;br /&gt;
//&lt;br /&gt;
// This program is free software; you can redistribute it and/or modify&lt;br /&gt;
// it under the terms of the GNU General Public License as published by&lt;br /&gt;
// the Free Software Foundation; either version 2 of the License, or&lt;br /&gt;
// (at your option) any later version.&lt;br /&gt;
//&lt;br /&gt;
// This program is distributed in the hope that it will be useful,&lt;br /&gt;
// but WITHOUT ANY WARRANTY; without even the implied warranty of&lt;br /&gt;
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the&lt;br /&gt;
// GNU General Public License for more details.&lt;br /&gt;
//&lt;br /&gt;
// You should have received a copy of the GNU General Public License&lt;br /&gt;
// along with this program; if not, write to the Free Software&lt;br /&gt;
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307, USA.&#039;)&lt;br /&gt;
&lt;br /&gt;
//----------------------------------------------------------------------------&lt;br /&gt;
//#line &amp;quot;/opt/secondlife/scripts/scripts/tests/llLinkSitTarget_Test.m4s:5&amp;quot;&lt;br /&gt;
// GitLocation: tests/llLinkSitTarget_Test.m4s&lt;br /&gt;
// GitID: 32c3ab5a6f17d96eafe4e110bb91a700e2fd589b&lt;br /&gt;
&lt;br /&gt;
// This script uses the follow coordinate systems:&lt;br /&gt;
//&lt;br /&gt;
// rc     : Region Coordinates.&lt;br /&gt;
// oc     : Object, or root prim, Coordinates.&lt;br /&gt;
// link   : Coordinates of prim with link number &#039;link&#039;.&lt;br /&gt;
// STc    : Coordinates of the touched face (see llDetectedTouchST)&lt;br /&gt;
//          (x and y in the ranger [0, 1] with (0, 0) in the bottom-left corner).&lt;br /&gt;
// center : Coordinates of the touched face with the origin in the center,&lt;br /&gt;
//          the orientation is the same as STc (z is the normal of the surface),&lt;br /&gt;
//          but scaled to be in meters.&lt;br /&gt;
// ac     : Avatar center Coordinates. This is really the same as stc, but&lt;br /&gt;
//          moved up an offset. Rotations passed to llLinkSitTarget are&lt;br /&gt;
//          relative to this coordinate system.&lt;br /&gt;
&lt;br /&gt;
//----------------------------------------------------------------------------&lt;br /&gt;
//#line &amp;quot;/opt/secondlife/scripts/scripts/tests/llLinkSitTarget_Test.m4s:24&amp;quot;&lt;br /&gt;
// The sit position of the sit target.&lt;br /&gt;
// This value is *different* in SL and opensim, and even changed since opensim version 0.7.6.&lt;br /&gt;
// The currently measured values for the z component are:&lt;br /&gt;
// SL: 0.05, opensim 0.7.6: 0.0, opensim 0.8.x: -agentSize.z / 37.9075&lt;br /&gt;
&lt;br /&gt;
// Use this in SL:&lt;br /&gt;
//vector sittarget_pos_ac = &amp;lt;0.0, 0.0, 0.05&amp;gt;;&lt;br /&gt;
//integer opensimver = 0; // SL&lt;br /&gt;
&lt;br /&gt;
// Use this on opensim:&lt;br /&gt;
vector sittarget_pos_ac = &amp;lt;0.0, 0.0, 0.0&amp;gt;;&lt;br /&gt;
//integer opensimver = 7; // Opensim 0.7.6&lt;br /&gt;
integer opensimver = 8; // Opensim &amp;gt;= 0.8&lt;br /&gt;
&lt;br /&gt;
//----------------------------------------------------------------------------&lt;br /&gt;
//#line &amp;quot;/opt/secondlife/scripts/scripts/tests/llLinkSitTarget_Test.m4s:40&amp;quot;&lt;br /&gt;
// face_link() returns a list of vectors in link coordinates.&lt;br /&gt;
//&lt;br /&gt;
// Returns: [bottomLeft_link, topRight_link].&lt;br /&gt;
//&lt;br /&gt;
// bottomLeft_link is the bottom left corner of the given face,&lt;br /&gt;
// that is - the corner where (S, T) = (0, 0).&lt;br /&gt;
// topRight_link is the top right corner of the given face,&lt;br /&gt;
// that is - the corner where (S, T) = (1, 1).&lt;br /&gt;
list face_link(integer link, integer face)&lt;br /&gt;
{&lt;br /&gt;
  list params = llGetLinkPrimitiveParams(link, [PRIM_TYPE, PRIM_SIZE]);&lt;br /&gt;
  vector bottomLeft_link;&lt;br /&gt;
  vector topRight_link;&lt;br /&gt;
  integer prim_type = llList2Integer(params, 0);&lt;br /&gt;
  if (prim_type == PRIM_TYPE_BOX)&lt;br /&gt;
  {&lt;br /&gt;
    topRight_link = llList2Vector(params, 7) * 0.5;&lt;br /&gt;
    if (face == 0)&lt;br /&gt;
    {&lt;br /&gt;
      bottomLeft_link = -topRight_link;&lt;br /&gt;
      bottomLeft_link.z = topRight_link.z;&lt;br /&gt;
    }&lt;br /&gt;
    else if (face == 1)&lt;br /&gt;
    {&lt;br /&gt;
      bottomLeft_link = -topRight_link;&lt;br /&gt;
      topRight_link.y = bottomLeft_link.y;&lt;br /&gt;
    }&lt;br /&gt;
    else if (face == 2)&lt;br /&gt;
    {&lt;br /&gt;
      bottomLeft_link = -topRight_link;&lt;br /&gt;
      bottomLeft_link.x = topRight_link.x;&lt;br /&gt;
    }&lt;br /&gt;
    else if (face == 3)&lt;br /&gt;
    {&lt;br /&gt;
      topRight_link.x = -topRight_link.x;&lt;br /&gt;
      bottomLeft_link = -topRight_link;&lt;br /&gt;
      bottomLeft_link.y = topRight_link.y;&lt;br /&gt;
    }&lt;br /&gt;
    else if (face == 4)&lt;br /&gt;
    {&lt;br /&gt;
      topRight_link.y = -topRight_link.y;&lt;br /&gt;
      bottomLeft_link = -topRight_link;&lt;br /&gt;
      topRight_link.x = bottomLeft_link.x;&lt;br /&gt;
    }&lt;br /&gt;
    else if (face == 5)&lt;br /&gt;
    {&lt;br /&gt;
      topRight_link.y = -topRight_link.y;&lt;br /&gt;
      topRight_link.z = -topRight_link.z;&lt;br /&gt;
      bottomLeft_link = -topRight_link;&lt;br /&gt;
      bottomLeft_link.z = topRight_link.z;&lt;br /&gt;
    }&lt;br /&gt;
    else&lt;br /&gt;
    {&lt;br /&gt;
      llWhisper(0, &amp;quot;This script only supports sitting on boxes without cuts or holes.&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
  else&lt;br /&gt;
  {&lt;br /&gt;
    llWhisper(0, &amp;quot;This script does not work for non-box prims.&amp;quot;);&lt;br /&gt;
  }&lt;br /&gt;
  return [bottomLeft_link, topRight_link];&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
//----------------------------------------------------------------------------&lt;br /&gt;
//#line &amp;quot;/opt/secondlife/scripts/scripts/tests/llLinkSitTarget_Test.m4s:104&amp;quot;&lt;br /&gt;
default&lt;br /&gt;
{&lt;br /&gt;
  touch_start(integer num)&lt;br /&gt;
  {&lt;br /&gt;
    integer n;&lt;br /&gt;
    // Run over everyone that might have touch a prim (it could be more than one!)&lt;br /&gt;
    for (n = 0; n &amp;lt; num; ++n)&lt;br /&gt;
    {&lt;br /&gt;
      // Get the link number of the touch prim.&lt;br /&gt;
      integer link = llDetectedLinkNumber(n);&lt;br /&gt;
&lt;br /&gt;
      // Some conversion variables we need, copied directly from the table above.&lt;br /&gt;
      vector   link_pos_rc = llList2Vector(llGetLinkPrimitiveParams(link, [PRIM_POSITION]), 0);&lt;br /&gt;
      rotation link_rot_rc = llList2Rot(llGetLinkPrimitiveParams(link, [PRIM_ROTATION]), 0);&lt;br /&gt;
&lt;br /&gt;
      // Get the face of the prim that was touched.&lt;br /&gt;
      integer face = llDetectedTouchFace(n);&lt;br /&gt;
      if (face == TOUCH_INVALID_FACE)&lt;br /&gt;
      {&lt;br /&gt;
        llInstantMessage(llDetectedKey(n), &amp;quot;Sorry, your viewer does not support touched faces.&amp;quot;);&lt;br /&gt;
      }&lt;br /&gt;
      else&lt;br /&gt;
      {&lt;br /&gt;
        // llDetectedTouchPos returns the position where an object was touched in Region Coordinates.&lt;br /&gt;
        vector touch_pos_rc = llDetectedTouchPos(n);&lt;br /&gt;
        // Convert that into link coordinates.&lt;br /&gt;
        vector touch_pos_link = (touch_pos_rc - link_pos_rc) / link_rot_rc;&lt;br /&gt;
&lt;br /&gt;
        // llDetectedTouchBinormal returns a normalized, directional vector in Region Coordinates.&lt;br /&gt;
        // So, it&#039;s not a position; it is a direction (dir), really representing a rotation.&lt;br /&gt;
        vector binormal_dir_rc = llDetectedTouchBinormal(n);&lt;br /&gt;
&lt;br /&gt;
        // In general a direction vector can not be converted to a rotation (when the&lt;br /&gt;
        // starting reference vector is (almost) the same as the direction vector, which&lt;br /&gt;
        // might be the case here since we have no idea where the vector is pointing to).&lt;br /&gt;
        // Therefore we just leave it as a vector, but we treat it the same as a rotation:&lt;br /&gt;
        // leave the origin alone and just correct the rotation when converting to the&lt;br /&gt;
        // local coordinate system of the link prim.&lt;br /&gt;
        vector binormal_dir_link = binormal_dir_rc / link_rot_rc; // binormal_dir_rc * rc_rot_link&lt;br /&gt;
&lt;br /&gt;
        // llDetectedTouchNormal returns a normalized, directional vector in Region Coordinates.&lt;br /&gt;
        // It is perpendicular to the surface (pointing outwards) and makes an angle of 90 degrees&lt;br /&gt;
        // with binormal_dir. Here we immediately convert it to _link coordinates.&lt;br /&gt;
        vector normal_dir_link = llDetectedTouchNormal(n) / link_rot_rc;&lt;br /&gt;
&lt;br /&gt;
        // Calculate the tangent vector.&lt;br /&gt;
        vector tangent_dir_link = binormal_dir_link % normal_dir_link;&lt;br /&gt;
&lt;br /&gt;
        // Get the [bottomLeft_link, topRight_link] positions of the surface &#039;face&#039;, in link coordinates.&lt;br /&gt;
        list surface_link = face_link(link, face);&lt;br /&gt;
        vector bottomLeft_pos_link = llList2Vector(surface_link, 0);&lt;br /&gt;
        vector topRight_pos_link = llList2Vector(surface_link, 1);&lt;br /&gt;
&lt;br /&gt;
        // Calculate the center of the surface.&lt;br /&gt;
        vector center_pos_link = (bottomLeft_pos_link + topRight_pos_link) * 0.5;&lt;br /&gt;
&lt;br /&gt;
        // The unit x vector in link coordinates is obviously &amp;lt;1, 0, 0&amp;gt;, center_rot_link is&lt;br /&gt;
        // therefore the rotation that is needed to rotate that to tangent_dir_link, which&lt;br /&gt;
        // represents &amp;lt;1, 0, 0&amp;gt; in center coordinates (the positive S direction).&lt;br /&gt;
        // The positive T direction, or &amp;lt;0, 1, 0&amp;gt; in center coordinates, is the binormal vector.&lt;br /&gt;
        // llAxes2Rot(fwd, left, up) returns the rotation needed to rotate &amp;lt;1, 0, 0&amp;gt; to fwd,&lt;br /&gt;
        // and &amp;lt;0, 1, 0&amp;gt; to left (and thus &amp;lt;0, 0, 1&amp;gt; to up).&lt;br /&gt;
        rotation center_rot_link = llAxes2Rot(tangent_dir_link, binormal_dir_link, normal_dir_link);&lt;br /&gt;
&lt;br /&gt;
        // llDetectedTouchST returns a vector in the plane of the touched surface,&lt;br /&gt;
        // with x and y ranging from 0,0 in the &amp;quot;bottom left&amp;quot; corner till 1,1 for&lt;br /&gt;
        // opposite corner. The value is thus in ST Coordinates.&lt;br /&gt;
        vector touch_pos_STc = llDetectedTouchST(n);&lt;br /&gt;
&lt;br /&gt;
        // Caluclate the size of the surface and rotate it in the plane of the center coordinates.&lt;br /&gt;
        vector center_link_scale = (topRight_pos_link - bottomLeft_pos_link) / center_rot_link;&lt;br /&gt;
&lt;br /&gt;
        // Convert touch_pos to center coordinates.&lt;br /&gt;
        vector touch_pos_center = &amp;lt;(touch_pos_STc.x - 0.5) * center_link_scale.x, (touch_pos_STc.y - 0.5) * center_link_scale.y, 0.0&amp;gt;;&lt;br /&gt;
&lt;br /&gt;
        // Calculate a unit vector from the touch position to the edge.&lt;br /&gt;
        vector edge_dir_center;&lt;br /&gt;
        // Find the nearest edge.&lt;br /&gt;
        vector edge_pos_center = touch_pos_center;&lt;br /&gt;
        if (center_link_scale.x * 0.5 - llFabs(edge_pos_center.x) &amp;gt; center_link_scale.y * 0.5 - llFabs(edge_pos_center.y))&lt;br /&gt;
        {&lt;br /&gt;
          integer positive = llRound(touch_pos_STc.y);&lt;br /&gt;
          edge_pos_center.y = (positive - 0.5) * center_link_scale.y;&lt;br /&gt;
          edge_dir_center = &amp;lt;0, positive * 2 - 1, 0&amp;gt;;&lt;br /&gt;
        }&lt;br /&gt;
        else&lt;br /&gt;
        {&lt;br /&gt;
          integer positive = llRound(touch_pos_STc.x);&lt;br /&gt;
          edge_pos_center.x = (positive - 0.5) * center_link_scale.x;&lt;br /&gt;
          edge_dir_center = &amp;lt;positive * 2 - 1, 0, 0&amp;gt;;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        // Convert edge_dir_center to link coordinates (because llLinkSitTarget takes link coordinates).&lt;br /&gt;
        vector edge_dir_link = edge_dir_center * center_rot_link;&lt;br /&gt;
&lt;br /&gt;
        // Calculate the rotation of the seated avatar from this direction, using the fact that we still have normal_dir_link.&lt;br /&gt;
        // This puts the fwd direction of the avatar in the direction edge_dir (from touch point to nearest edge)&lt;br /&gt;
        // and the up direction of the avatar perpendicular to the touched surface.&lt;br /&gt;
        rotation ac_rot_link = llAxes2Rot(edge_dir_link, normal_dir_link % edge_dir_link, normal_dir_link);&lt;br /&gt;
&lt;br /&gt;
        // Where do we want to sit?&lt;br /&gt;
        // Currently lets just sit where the user clicked, without limits or corrections.&lt;br /&gt;
        vector sit_pos_center = touch_pos_center;&lt;br /&gt;
&lt;br /&gt;
        // Convert the sit position to link coordinates (because llLinkSitTarget takes link coordinates).&lt;br /&gt;
        vector sit_pos_link = sit_pos_center * center_rot_link + center_pos_link;&lt;br /&gt;
&lt;br /&gt;
        // This vector is really a function of avatar shape and what looks&lt;br /&gt;
        // aesthetically pleasing. However, it is only minimal a function&lt;br /&gt;
        // avatar height (the only thing we can roughly know from a script)&lt;br /&gt;
        // and much more a function of shape values that we can&#039;t know.&lt;br /&gt;
        // So for now, just leave this as a constant.&lt;br /&gt;
        //&lt;br /&gt;
        // In ascii art, a sitting avatar looks more or less like this:&lt;br /&gt;
        //                ^&lt;br /&gt;
        //                |z&lt;br /&gt;
        //            ac_ |&lt;br /&gt;
        //               \S           &#039;S&#039; is the sittarget_pos_ac, in SL it is 0.05m above(_ac) &#039;O&#039;.&lt;br /&gt;
        //         &amp;lt;--x---O   ()      &#039;O&#039; is the Origin of ac (Avatar center (attach point) Coordinates).&lt;br /&gt;
        //                |   /|      &#039;*&#039; is the sittarget (as passed to llSitTarget) and is 0.4m below(_link) S.&lt;br /&gt;
        //    sittarget--&amp;gt;*__/_/&lt;br /&gt;
        //               _/   ^__ sit_pos_ac, 0.62 below(_ac) &#039;O&#039;, and 0.34 backwards(_ac).&lt;br /&gt;
        //                |&lt;br /&gt;
        vector sit_pos_ac = &amp;lt;-0.34, 0.0, -0.62&amp;gt;;&lt;br /&gt;
&lt;br /&gt;
        // Correct grid dependent sittarget_pos_ac.&lt;br /&gt;
        if (opensimver == 7)&lt;br /&gt;
        {&lt;br /&gt;
          sittarget_pos_ac.z = 0.0;&lt;br /&gt;
        }&lt;br /&gt;
        else if (opensimver == 8)&lt;br /&gt;
        {&lt;br /&gt;
          vector agentSize = llGetAgentSize(llDetectedKey(n));&lt;br /&gt;
          sittarget_pos_ac.z = agentSize.z / -37.9075; // Constant determined on &amp;quot;OpenSim 0.8.0 Dev&amp;quot;, April 2014.&lt;br /&gt;
          llSay(0, &amp;quot;sittarget_pos_ac = &amp;quot; + (string)sittarget_pos_ac);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        // Find the translation of the ac coordinate system.&lt;br /&gt;
        vector ac_pos_link = sit_pos_link - sit_pos_ac * ac_rot_link;&lt;br /&gt;
&lt;br /&gt;
        // Convert the sittarget from ac coordinates to link coordinates.&lt;br /&gt;
        vector sittarget_pos_link = sittarget_pos_ac * ac_rot_link + ac_pos_link;&lt;br /&gt;
&lt;br /&gt;
        // Grid dependent vertical offset.&lt;br /&gt;
        //&lt;br /&gt;
        // This is a historical offset introduced by Linden Lab from the beginning.&lt;br /&gt;
        // It is actually a mistake because when the avatar is rotated this causes&lt;br /&gt;
        // the avatar to move sideways! Apparently also Philips Linden found rotations&lt;br /&gt;
        // hard to understand.&lt;br /&gt;
        if (opensimver == 7)&lt;br /&gt;
        {&lt;br /&gt;
          // opensim version 0.7.6&lt;br /&gt;
          // Obviously, this should have been the same as on SL.&lt;br /&gt;
          // Later it got &amp;quot;corrected&amp;quot;, but in a wrong way (sittarget_pos_ac still differs with SL).&lt;br /&gt;
          sittarget_pos_link.z -= 0.418;&lt;br /&gt;
        }&lt;br /&gt;
        else&lt;br /&gt;
        {&lt;br /&gt;
          // SL and opensim &amp;gt;= 0.8.&lt;br /&gt;
          sittarget_pos_link.z -= 0.4;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        // Set the sit target.&lt;br /&gt;
        llLinkSitTarget(link, sittarget_pos_link, ac_rot_link);&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/lsl&amp;gt;&lt;/div&gt;</summary>
		<author><name>Timmy Foxclaw</name></author>
	</entry>
	<entry>
		<id>https://wiki.secondlife.com/w/index.php?title=Talk:LlSitTarget&amp;diff=1189278</id>
		<title>Talk:LlSitTarget</title>
		<link rel="alternate" type="text/html" href="https://wiki.secondlife.com/w/index.php?title=Talk:LlSitTarget&amp;diff=1189278"/>
		<updated>2014-04-07T22:44:38Z</updated>

		<summary type="html">&lt;p&gt;Timmy Foxclaw: fixed indentation&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Unsitting on wrong side or camera rotation ==&lt;br /&gt;
&lt;br /&gt;
Hi, i am getting frustrated with this. I create a board and set the sit target with&lt;br /&gt;
&amp;lt;code&amp;gt;llSitTarget(&amp;lt;0.4, 0.0, 0.0&amp;gt;, ZERO_ROTATION);&amp;lt;/code&amp;gt;&lt;br /&gt;
and an animation which for &amp;quot;standing&amp;quot;. So while the person technical sits, she stands in front of the board. &lt;br /&gt;
But I have a problem with that: If the board stand freely, the person unsits right through it towards the other side. I can put the board with the back  facing a large wall. In the case the unsitting is correctly in front of it. But on sit down the camera rotates, so that it is behind the avatar again; on the other side of the wall.&lt;br /&gt;
&lt;br /&gt;
If anyone has an idea how to fix, please tell me (even if it is just an idea where to look for more information). --[[User:Maike Short|Maike Short]] 12:41, 24 February 2008 (PST)&lt;br /&gt;
&lt;br /&gt;
:You could position the camera with the {{LSLGC|Camera}} functions.  -- [[User:Strife Onizuka|Strife Onizuka]] 04:46, 25 February 2008 (PST)&lt;br /&gt;
&lt;br /&gt;
==GetSitTarget==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;lsl&amp;gt;&lt;br /&gt;
list GetSitTarget(integer prim, key av)&lt;br /&gt;
{//WARNING: llGetObjectDetails can introduce an error that goes as far as the 5th decimal place.&lt;br /&gt;
    vector tp = llGetAgentSize(av);&lt;br /&gt;
    if(tp)&lt;br /&gt;
    {&lt;br /&gt;
        if(prim == LINK_THIS)//llGetLinkKey doesn&#039;t like LINK_THIS&lt;br /&gt;
            prim = llGetLinkNumber();&lt;br /&gt;
    &lt;br /&gt;
        list details = OBJECT_POS + (list)OBJECT_ROT;&lt;br /&gt;
        rotation f = llList2Rot(details = (llGetObjectDetails(llGetLinkKey(prim), details) + llGetObjectDetails(av, details)), 1);&lt;br /&gt;
    &lt;br /&gt;
        return [(llRot2Up(f = (llList2Rot(details, 3) / f)) * tp.z * 0.02638) +&lt;br /&gt;
                ((llList2Vector(details, 2) - llList2Vector(details, 0)) / f) - &amp;lt;0.0, 0.0, 0.4&amp;gt;, f];&lt;br /&gt;
    }&lt;br /&gt;
    return [];&lt;br /&gt;
}//Written by Strife Onizuka&lt;br /&gt;
&amp;lt;/lsl&amp;gt;&lt;br /&gt;
Hi Strife! This version of your GetSitTarget, and the other version on the actual LlSitTarget page, both always return &amp;lt;0.000000, 0.000000, 0.707107, 0.707107&amp;gt; for the rotation. --[[User:MartinRJ Fayray|MartinRJ Fayray]] 07:52, 21 January 2013 (PST)&lt;br /&gt;
&lt;br /&gt;
:I haven&#039;t touched this in 5 years but I don&#039;t see a reason why it should be doing what you say. Are you sure you are using it properly? The prim parameter specifies what prim the location will be local to. The function was written to aid in determining sit targets when making furniture. You have the avatar sit on one object and then you get it&#039;s position local to the furniture so you can program in the sit target.&lt;br /&gt;
&lt;br /&gt;
:Just to clarify, you are saying that when you sit on an object with the following script in it, you don&#039;t get approximately the specified value? -- &#039;&#039;&#039;[[User:Strife_Onizuka|Strife]]&#039;&#039;&#039; &amp;lt;sup&amp;gt;&amp;lt;small&amp;gt;([[User talk:Strife_Onizuka|talk]]|[[Special:Contributions/Strife_Onizuka|contribs]])&amp;lt;/small&amp;gt;&amp;lt;/sup&amp;gt; 20:37, 22 January 2013 (PST)&lt;br /&gt;
&lt;br /&gt;
:It seems to work now. No idea what I was doing wrong. Thank you strife!--[[User:MartinRJ Fayray|MartinRJ Fayray]] 07:36, 3 February 2013 (PST)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;lsl&amp;gt;&lt;br /&gt;
vector vOffset = &amp;lt;0,0,1&amp;gt;;&lt;br /&gt;
rotation rOffset = &amp;lt;0,0,0,1&amp;gt;;&lt;br /&gt;
&lt;br /&gt;
list GetSitTarget(integer prim, key av)&lt;br /&gt;
{//WARNING: llGetObjectDetails can introduce an error that goes as far as the 5th decimal place!&lt;br /&gt;
 //This is highly unlikely to be ever noticed unless compounded over time.&lt;br /&gt;
 //Do not use while moving (like in a moving vehicle)!!!&lt;br /&gt;
    vector tp = llGetAgentSize(av);&lt;br /&gt;
    if(tp)&lt;br /&gt;
    {&lt;br /&gt;
        if(prim == LINK_THIS)//llGetLinkKey doesn&#039;t like LINK_THIS&lt;br /&gt;
            prim = llGetLinkNumber();&lt;br /&gt;
 &lt;br /&gt;
        list details = [OBJECT_POS, OBJECT_ROT];&lt;br /&gt;
        rotation f = llList2Rot(details = (llGetObjectDetails(llGetLinkKey(prim), details) + llGetObjectDetails(av, details)), 1);&lt;br /&gt;
        rotation r = llList2Rot(details, 3) / f;&lt;br /&gt;
 &lt;br /&gt;
        return [((llList2Vector(details, 2) - llList2Vector(details, 0)) / f) + (llRot2Up(r) * tp.z * 0.02638) - &amp;lt;0.0, 0.0, 0.4&amp;gt;, r];&lt;br /&gt;
    }&lt;br /&gt;
    return [];&lt;br /&gt;
}//Written by Strife Onizuka&lt;br /&gt;
&lt;br /&gt;
default{&lt;br /&gt;
    state_entry(){&lt;br /&gt;
        llSitTarget(vOffset, rOffset);&lt;br /&gt;
    }&lt;br /&gt;
    changed(integer change){&lt;br /&gt;
        key id = llAvatarOnSitTarget();&lt;br /&gt;
        if(id)&lt;br /&gt;
            llOwnerSay(&amp;quot;[&amp;quot;+llList2CSV([vOffset, rOffset]) +&amp;quot;] ~ [&amp;quot; + llList2CSV(GetSitTarget(LINK_THIS, id))+&amp;quot;]&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/lsl&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Note&#039;&#039;&#039;: the above two scripts in this paragraph are incorrect. Most notably, the position of an avatar (it&#039;s Avatar Center) is NOT dependent on the AgentSize of the seated avatar. I added another script that returns the sit target, below. [[User:Timmy Foxclaw|Timmy Foxclaw]] 10:31, 7 April 2014 (PDT)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;lsl&amp;gt;&lt;br /&gt;
// A script to develop and test sbGetLinkSitTarget&lt;br /&gt;
//&lt;br /&gt;
// Copyright(c) Timmy Songbird @DreamNation&lt;br /&gt;
//              Timmy Foxclaw  @SL,&lt;br /&gt;
//              2014&lt;br /&gt;
//&lt;br /&gt;
// This program is free software; you can redistribute it and/or modify&lt;br /&gt;
// it under the terms of the GNU General Public License as published by&lt;br /&gt;
// the Free Software Foundation; either version 2 of the License, or&lt;br /&gt;
// (at your option) any later version.&lt;br /&gt;
//&lt;br /&gt;
// This program is distributed in the hope that it will be useful,&lt;br /&gt;
// but WITHOUT ANY WARRANTY; without even the implied warranty of&lt;br /&gt;
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the&lt;br /&gt;
// GNU General Public License for more details.&lt;br /&gt;
//&lt;br /&gt;
// You should have received a copy of the GNU General Public License&lt;br /&gt;
// along with this program; if not, write to the Free Software&lt;br /&gt;
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307, USA.&#039;)&lt;br /&gt;
&lt;br /&gt;
//----------------------------------------------------------------------------&lt;br /&gt;
//#line &amp;quot;/opt/secondlife/scripts/scripts/tests/sbGetLinkSitTarget_Test.m4s:4&amp;quot;&lt;br /&gt;
// This script sets a &amp;quot;random&amp;quot;-ish sit target on every prim in an object.&lt;br /&gt;
// Recommended for your test is an object existing of two default cubes&lt;br /&gt;
// with arbitrary rotations and position. Put this script only in the&lt;br /&gt;
// root prim.&lt;br /&gt;
//&lt;br /&gt;
// The script sets the sit targets on compile or touch. Please touch&lt;br /&gt;
// the object after editting one of the prims.&lt;br /&gt;
//&lt;br /&gt;
// When an avatar (un)sits on one of the prims, the script prints for every&lt;br /&gt;
// sit target that has a seated avatar the return value of sbGetLinkSitTarget.&lt;br /&gt;
// This value should be (almost) equal to the values passed to llSitTarget.&lt;br /&gt;
&lt;br /&gt;
// Example output:&lt;br /&gt;
&lt;br /&gt;
// Object: [&amp;lt;0.200000, 0.300000, 0.500000&amp;gt;, &amp;lt;0.100000, 0.150000, 0.120000, 0.976268&amp;gt;] set with llSitTarget on 2 prims.&lt;br /&gt;
// Object: [&amp;lt;0.199999, 0.300001, 0.499999&amp;gt;, &amp;lt;0.100000, 0.150000, 0.120000, 0.976268&amp;gt;] returned by sbGetLinkSitTarget(1).&lt;br /&gt;
// Object: [&amp;lt;0.199998, 0.300002, 0.499998&amp;gt;, &amp;lt;0.100000, 0.150000, 0.120000, 0.976268&amp;gt;] returned by sbGetLinkSitTarget(2).&lt;br /&gt;
&lt;br /&gt;
// GitLocation: tests/sbGetLinkSitTarget_Test.m4s&lt;br /&gt;
&lt;br /&gt;
//----------------------------------------------------------------------------&lt;br /&gt;
//#line &amp;quot;/opt/secondlife/scripts/scripts/tests/sbGetLinkSitTarget_Test.m4s:26&amp;quot;&lt;br /&gt;
vector sitTarget_pos_link = &amp;lt;0.2, 0.3, 0.5&amp;gt;;&lt;br /&gt;
rotation sitTarget_rot_link = &amp;lt;0.1, 0.15, 0.12, 0.9762684&amp;gt;;&lt;br /&gt;
&lt;br /&gt;
//----------------------------------------------------------------------------&lt;br /&gt;
//#line &amp;quot;/opt/secondlife/scripts/scripts/tests/sbGetLinkSitTarget_Test.m4s:31&amp;quot;&lt;br /&gt;
// Returns the correct values to use for llSitTarget to make&lt;br /&gt;
// the currently seated avatar sit in the same way when re-seated.&lt;br /&gt;
// If no avatar is currently sitting then [ZERO_VECTOR, ZERO_ROTATION] is returned.&lt;br /&gt;
//&lt;br /&gt;
// [1] http://wiki.secondlife.com/wiki/User:Timmy_Foxclaw/About_Coordinate_Systems_and_Rotations#LSL_functions&lt;br /&gt;
// [2] http://wiki.secondlife.com/wiki/User:Timmy_Foxclaw/About_Coordinate_Systems_and_Rotations#Converting_between_coordinate_systems&lt;br /&gt;
list sbGetLinkSitTarget(integer link)&lt;br /&gt;
{&lt;br /&gt;
  // Calling llAvatarOnLinkSitTarget(0) always returns NULL_KEY because the link&lt;br /&gt;
  // number of an unlinked prim changes from 0 to 1 as soon as an avatar sits on&lt;br /&gt;
  // it. So if 0 was passed then they probably meant 1.&lt;br /&gt;
  if (link == 0)&lt;br /&gt;
  {&lt;br /&gt;
    link = 1;&lt;br /&gt;
  }&lt;br /&gt;
  key av = llAvatarOnLinkSitTarget(link);&lt;br /&gt;
  if (av != NULL_KEY)&lt;br /&gt;
  {&lt;br /&gt;
    // Get link_pos_oc and link_rot_oc. See table 2 in [1].&lt;br /&gt;
    vector link_pos_oc = ZERO_VECTOR;&lt;br /&gt;
    rotation link_rot_oc = ZERO_ROTATION;&lt;br /&gt;
    if (link &amp;gt; 1)&lt;br /&gt;
    {&lt;br /&gt;
      list params = llGetLinkPrimitiveParams(link, [PRIM_POS_LOCAL, PRIM_ROT_LOCAL]);&lt;br /&gt;
      link_pos_oc = llList2Vector(params, 0);&lt;br /&gt;
      link_rot_oc = llList2Rot(params, 1);&lt;br /&gt;
    }&lt;br /&gt;
    // Find the link number of the seated avatar.&lt;br /&gt;
    integer avNum = llGetNumberOfPrims();&lt;br /&gt;
    do&lt;br /&gt;
    {&lt;br /&gt;
        if (av == llGetLinkKey(avNum))&lt;br /&gt;
        {&lt;br /&gt;
            // Get ac_pos_oc and ac_rot_oc (ac stands for Avatar Center), exactly the same as above&lt;br /&gt;
            // except that we don&#039;t need to test if avNum &amp;gt; 1, because it always will be.&lt;br /&gt;
            list params = llGetLinkPrimitiveParams(avNum, [PRIM_POS_LOCAL, PRIM_ROT_LOCAL]);&lt;br /&gt;
            vector ac_pos_oc = llList2Vector(params, 0);&lt;br /&gt;
            rotation ac_rot_oc = llList2Rot(params, 1);&lt;br /&gt;
&lt;br /&gt;
            // Convert that to link coordinates. See formula (3) in [2].&lt;br /&gt;
            vector ac_pos_link = (ac_pos_oc - link_pos_oc) / link_rot_oc;&lt;br /&gt;
            rotation ac_rot_link = ac_rot_oc / link_rot_oc;&lt;br /&gt;
&lt;br /&gt;
            // Now we have this little vector in the Avatar Center coordinates.&lt;br /&gt;
            vector sit_pos_ac = &amp;lt;0.0, 0.0, 0.05&amp;gt;;&lt;br /&gt;
&lt;br /&gt;
            // Convert that to link coordinates. See formula (1) in [2].&lt;br /&gt;
            vector sit_pos_link = sit_pos_ac * ac_rot_link + ac_pos_link;&lt;br /&gt;
&lt;br /&gt;
            // Return the values, accounting for the sit target bug of 0.4m.&lt;br /&gt;
            return [sit_pos_link - &amp;lt;0.0, 0.0, 0.4&amp;gt;, ac_rot_link];&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    while (--avNum);&lt;br /&gt;
  }&lt;br /&gt;
  return [ZERO_VECTOR, ZERO_ROTATION];&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
setSitTargets()&lt;br /&gt;
{&lt;br /&gt;
  // Set the same sit target on every prim.&lt;br /&gt;
  integer n = llGetNumberOfPrims();&lt;br /&gt;
  llSay(0, &amp;quot;[&amp;quot; +  llList2CSV([sitTarget_pos_link, sitTarget_rot_link]) + &amp;quot;] set with llSitTarget on &amp;quot; + (string)n + &amp;quot; prims.&amp;quot;);&lt;br /&gt;
  do&lt;br /&gt;
  {&lt;br /&gt;
    llLinkSitTarget(n, sitTarget_pos_link, sitTarget_rot_link);&lt;br /&gt;
  }&lt;br /&gt;
  while(--n);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
//----------------------------------------------------------------------------&lt;br /&gt;
//#line &amp;quot;/opt/secondlife/scripts/scripts/tests/sbGetLinkSitTarget_Test.m4s:105&amp;quot;&lt;br /&gt;
default&lt;br /&gt;
{&lt;br /&gt;
  state_entry()&lt;br /&gt;
  {&lt;br /&gt;
    setSitTargets();&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  touch_start(integer n)&lt;br /&gt;
  {&lt;br /&gt;
    setSitTargets();&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  changed(integer change)&lt;br /&gt;
  {&lt;br /&gt;
    if ((change &amp;amp; CHANGED_LINK))&lt;br /&gt;
    {&lt;br /&gt;
      integer n = llGetNumberOfPrims();&lt;br /&gt;
      do&lt;br /&gt;
      {&lt;br /&gt;
        key av = llAvatarOnLinkSitTarget(n);&lt;br /&gt;
        if (av != NULL_KEY)&lt;br /&gt;
        {&lt;br /&gt;
          llSay(0, &amp;quot;[&amp;quot; + llList2CSV(sbGetLinkSitTarget(n)) + &amp;quot;] returned by sbGetLinkSitTarget(&amp;quot; + (string)n + &amp;quot;).&amp;quot;);&lt;br /&gt;
        }&lt;br /&gt;
      }&lt;br /&gt;
      while(--n);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/lsl&amp;gt;&lt;br /&gt;
:Yes the above two scripts are older versions. The 0.05 offset has been tried before. {{User|Talarus Luan}} [https://wiki.secondlife.com/w/index.php?title=LlSitTarget&amp;amp;diff=1179695&amp;amp;oldid=1179694 could not get it to work]. {{User|Talarus Luan}} went on to work out a quadratic equation that provided a more accurate result. See [[#UpdateSitTarget_changes.3F|#UpdateSitTarget changes?]] below. -- &#039;&#039;&#039;[[User:Strife_Onizuka|Strife]]&#039;&#039;&#039; &amp;lt;sup&amp;gt;&amp;lt;small&amp;gt;([[User talk:Strife_Onizuka|talk]]|[[Special:Contributions/Strife_Onizuka|contribs]])&amp;lt;/small&amp;gt;&amp;lt;/sup&amp;gt; 12:38, 7 April 2014 (PDT)&lt;br /&gt;
&lt;br /&gt;
::Hi Strife. There must be some miscommunication - we seem to be talking about different things. After extensive research (see [[ User:Timmy_Foxclaw/About_Coordinate_Systems_and_Rotations|this link]], especially the script at the end), I have found that the value is exactly 0.05 and not depend on the height of the avatar in SecondLife. The function sbGetLinkSitTarget as defined in the script above returns the exact values (within the normal floating point round off error of 0.000002 or so), no matter what position and rotation you passed to llSitTarget. Perhaps we can meet in some sandbox in SL? I&#039;d like to understand where your quadratic expression exactly comes in. Maybe you can show me the test object and the tests that you did to determine it. [[User:Timmy Foxclaw|Timmy Foxclaw]] 15:41, 7 April 2014 (PDT)&lt;br /&gt;
&lt;br /&gt;
==Using llSetLinkPrimitiveParams for skydiving: why limited to 5m in a linked set?==&lt;br /&gt;
llSetLinkPrimitiveParams can be used as a handy tool to adjust an avatar&#039;s position and rotation.&lt;br /&gt;
This works perfectly when the object consists of 1 prim, with a range for setting the avatar position away to 500m easily!&lt;br /&gt;
When there are more prims linked, this offset seems to be limited to 5m (measured with llVecDist). This is an awfull sideeffect!&lt;br /&gt;
&lt;br /&gt;
Put this next script inside a prim and sit on the prim, it will bring you to 1000.0 higher then the prim.&lt;br /&gt;
Next link this prim to another prim and try again. You will notice you are limited to 5m. My Question: why is this limited?&lt;br /&gt;
&amp;lt;lsl&amp;gt;&lt;br /&gt;
// by Randur Source&lt;br /&gt;
&lt;br /&gt;
integer heightcnt = 0;&lt;br /&gt;
list heights = [0.0, 1.0, 5.0, 6.0, 10.0, 100.0, 300.0, 500.0, 800.0, 1000.0];&lt;br /&gt;
&lt;br /&gt;
default&lt;br /&gt;
{&lt;br /&gt;
    state_entry()&lt;br /&gt;
    {&lt;br /&gt;
        llSitTarget(ZERO_VECTOR,ZERO_ROTATION); // Clear the current sittarget for a clear test&lt;br /&gt;
        llSetRot(ZERO_ROTATION); // set the prim to no rotation, for simple z axis movement&lt;br /&gt;
    }&lt;br /&gt;
    &lt;br /&gt;
    changed(integer change)&lt;br /&gt;
    {&lt;br /&gt;
        if (change &amp;amp; CHANGED_LINK) // detect linked prims and avatars&lt;br /&gt;
        {&lt;br /&gt;
            integer primnum = llGetNumberOfPrims(); // the avatar is the last linked prim&lt;br /&gt;
            if (primnum &amp;lt;= 1) // stop if there is only 1 prim&lt;br /&gt;
                return;&lt;br /&gt;
        &lt;br /&gt;
            key avatar = llGetLinkKey(primnum);&lt;br /&gt;
            if (llGetAgentSize(avatar) == ZERO_VECTOR) // stop if this is not an avatar&lt;br /&gt;
                return;&lt;br /&gt;
                &lt;br /&gt;
            // loop through the list of test heights:&lt;br /&gt;
            for (heightcnt = 0; heightcnt &amp;lt; llGetListLength(heights); heightcnt++)&lt;br /&gt;
            {&lt;br /&gt;
                float height = llList2Float(heights,heightcnt);&lt;br /&gt;
                llSetLinkPrimitiveParams(primnum,[PRIM_POSITION,&amp;lt;0.0,0.0,height&amp;gt;]); // set this to the wanted height using a vector z axis&lt;br /&gt;
                &lt;br /&gt;
                vector avatarpos = llList2Vector(llGetObjectDetails(avatar,[OBJECT_POS]),0); // detect the avatar position within the sim&lt;br /&gt;
                float distance = llVecDist(llGetPos(),avatarpos);&lt;br /&gt;
                llOwnerSay(&amp;quot;Attempt to move &amp;quot; + llKey2Name(llGetLinkKey(primnum)) +&lt;br /&gt;
                           &amp;quot; to &amp;quot; + (string)height + &amp;quot;m high resulting to &amp;quot; + (string)distance + &amp;quot;m&amp;quot;);&lt;br /&gt;
                &lt;br /&gt;
                llSleep(1.0);&lt;br /&gt;
            }&lt;br /&gt;
            llUnSit(avatar);&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/lsl&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Posted by Sylvio Runo : Answer &#039;&#039;&#039; :&lt;br /&gt;
The correct limit is 54 meters.&lt;br /&gt;
You can&#039;t move a linked object more than 54 meters away from the axis of the root prim.&lt;br /&gt;
On SecondLife (other grids like OsGrid, may works diferent) when an agent sit on prim, the agent is attached to it, so the agent is a linked prim of the link set.&lt;br /&gt;
&lt;br /&gt;
More information about link rules, you will find here : http://wiki.secondlife.com/wiki/Linkability_Rules [http://wiki.secondlife.com/wiki/Linkability_Rules]&lt;br /&gt;
&lt;br /&gt;
==UpdateSitTarget changes?==&lt;br /&gt;
I recently worked on a project where I used a version of this function, and it appears that it is a little off. A couple of things I noted: the Z-offset of the sit target is 0.35, not 0.4, and the avatar size doesn&#039;t seem to affect this position at all. When I used this function verbatim, I noticed discrepancies between the actual sit target and the set position call. When I changed the script as noted, I got a perfect match. Has the handling of the sit target been changed since this was written? [[User:Talarus Luan|Talarus Luan]] 22:57, 1 July 2009 (UTC)&lt;br /&gt;
:Seconded. I wish I&#039;d looked at this discussion before spending an hour on trying to figure out how the code actually behaved. -- [[User:Tonya Souther|Tonya Souther]] 15:11, 19 August 2009 (UTC)&lt;br /&gt;
&lt;br /&gt;
::This is news to me but I haven&#039;t been in world in ages :( -- &#039;&#039;&#039;[[User:Strife_Onizuka|Strife]]&#039;&#039;&#039; &amp;lt;sup&amp;gt;&amp;lt;small&amp;gt;([[User talk:Strife_Onizuka|talk]]|[[Special:Contributions/Strife_Onizuka|contribs]])&amp;lt;/small&amp;gt;&amp;lt;/sup&amp;gt; 22:56, 20 August 2009 (UTC)&lt;br /&gt;
&lt;br /&gt;
:::From some quick testing in 1.40, this seems to be how the &amp;quot;true&amp;quot; offset is computed:&lt;br /&gt;
:::1. Start with offset as provided by LSL.&lt;br /&gt;
:::2. Add &amp;lt; 0.0 , 0.0 , 0.4 &amp;gt;&lt;br /&gt;
:::3. Subtract llRot2Up( rot ) * 0.05&lt;br /&gt;
:::[[User:Gregory Maurer|--Gregory Maurer]] 20:00, 28 August 2010 (UTC)&lt;br /&gt;
&lt;br /&gt;
::::Confirmed. The following appears to work fine:&lt;br /&gt;
&amp;lt;lsl&amp;gt;llSetLinkPrimitiveParams(linkNum, [PRIM_POS_LOCAL, pos + &amp;lt;0.0, 0.0, 0.4&amp;gt; - (llRot2Up(rot) * 0.05), PRIM_ROT_LOCAL, rot]);&amp;lt;/lsl&amp;gt;&lt;br /&gt;
::::This of course using the new &amp;lt;code&amp;gt;PRIM_POS_LOCAL&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;PRIM_ROT_LOCAL&amp;lt;/code&amp;gt; values for simplicity. If one or two others can confirm that the above code works correctly, then I can splice it into the example.&amp;lt;br/&amp;gt;-- &#039;&#039;&#039;[[User:Haravikk_Mistral|Haravikk]]&#039;&#039;&#039; &amp;lt;sup&amp;gt;&amp;lt;small&amp;gt;([[User_talk:Haravikk_Mistral|talk]]|[[Special:Contributions/Haravikk_Mistral|contribs]])&amp;lt;/small&amp;gt;&amp;lt;/sup&amp;gt; 14:16, 26 December 2011 (PST)&lt;br /&gt;
&lt;br /&gt;
:::::Be sure to test it with avatars of different shapes, and shoe configurations. I recall that being an issue. {{User|Escort DeFarge}} would know about this best. -- &#039;&#039;&#039;[[User:Strife_Onizuka|Strife]]&#039;&#039;&#039; &amp;lt;sup&amp;gt;&amp;lt;small&amp;gt;([[User talk:Strife_Onizuka|talk]]|[[Special:Contributions/Strife_Onizuka|contribs]])&amp;lt;/small&amp;gt;&amp;lt;/sup&amp;gt; 22:05, 26 December 2011 (PST)&lt;br /&gt;
&lt;br /&gt;
::::::I tried with my two main avatar appearances, one average human height and one closer to 8 feet tall, and it didn&#039;t seem to make a difference. The test I used was a simple object with sit-target set, and a menu allowing it to be repositioned, causing the sit-target to move and if an avatar is seated on it, they will be repositioned using &amp;lt;code&amp;gt;llSetLinkPrimitiveParams()&amp;lt;/code&amp;gt; as done above. In my case the position of the avatar was consistent both when sitting on the object (using the sit-target) and being repositioned. Avatar height appears to have no effect, as the sit-target seems to define the avatar&#039;s hip-location, which is seemingly the avatar&#039;s &amp;quot;centre&amp;quot; when seated. I&#039;ll try to run some more tests when I get a chance, as it&#039;s possible this behaviour may not hold true if the object doesn&#039;t have a sit-target on it. The height of the avatar does however have a marked visual impact, depending exactly what you&#039;re trying to line up where, but that&#039;s a general issue with sitting on objects.&amp;lt;br/&amp;gt;-- &#039;&#039;&#039;[[User:Haravikk_Mistral|Haravikk]]&#039;&#039;&#039; &amp;lt;sup&amp;gt;&amp;lt;small&amp;gt;([[User_talk:Haravikk_Mistral|talk]]|[[Special:Contributions/Haravikk_Mistral|contribs]])&amp;lt;/small&amp;gt;&amp;lt;/sup&amp;gt; 05:38, 28 December 2011 (PST)&lt;br /&gt;
:::::::Sorry for my long delay in responding. Due to various RL issues and SL/LL burnout, I took a year off from SL to pursue other activities. That said, it seems to work fine to me, Haravikk; however, I have not done exhaustive testing with tons of different avs, shoes, etc. I would consider going ahead and changing it, because the version as it is right now is not correct for the majority of avatars, regardless. If Escort DeFarge or someone else wants to amend it later to include edge cases, that&#039;s great, but a better base accuracy is more important at this point. In fact, I think I will go ahead and edit it in, since it has been so long anyway.[[User:Talarus Luan|Talarus Luan]] 12:12, 5 July 2013 (PDT)&lt;br /&gt;
:::::::Holding up on the edit, further testing is revealing that if the script is in a prim other than the root, it is off by varying amounts depending on the rotation.[[User:Talarus Luan|Talarus Luan]] 12:39, 5 July 2013 (PDT)&lt;br /&gt;
:::::::OK, I think I found the error. Still need to keep the local position/rotation values for the child prim the script is in, like so:&lt;br /&gt;
&amp;lt;lsl&amp;gt;llSetLinkPrimitiveParams(linkNum, PRIM_POS_LOCAL, (pos + &amp;lt;0.0, 0.0, 0.4&amp;gt; - (llRot2Up(rot) * 0.05)) * localrot + localpos, PRIM_ROT_LOCAL, rot * localrot]);&amp;lt;/lsl&amp;gt;&lt;br /&gt;
:::::::I&#039;ll hold off on the edit until I can get another verify that this code is good.[[User:Talarus Luan|Talarus Luan]] 12:51, 5 July 2013 (PDT)&lt;br /&gt;
:::::::OK. I think I have analyzed this to death today and have come to the conclusion that Strife&#039;s original code is largely correct, but the error I am seeing comes from the &amp;quot;magic constants&amp;quot; 0.4 and 0.02638. Haravikk&#039;s code is simply a reduced form of Strife&#039;s code. The 0.4 magic constant is still there, but Haravikk is using just a close, but fixed, magic constant of 0.05 instead of Strife&#039;s (size.z * 0.02638), which comes out very close to 0.5 for most normal human avs. Thus, I am concluding that the inaccuracy is in the &amp;quot;magic constants&amp;quot; themselves, and I am going to hold off on the edit until I can get some more information on the source of these constants and see if there are better, more accurate values. It is annoying that, in all these years, we still haven&#039;t gotten LL to just tell us what the damn difference is between avatar sit targets and local position offsets in a linkset. It can&#039;t be that hard for someone who is familiar with the code to look at it and document it. -.- [[User:Talarus Luan|Talarus Luan]] 13:24, 5 July 2013 (PDT)&lt;br /&gt;
&lt;br /&gt;
::::::::Welcome back! I&#039;d like to take credit for that but that&#039;s the part that Escort contributed. As to where 0.02638 comes from, I vaguely recall it came from Escort&#039;s testing. I was driven more by &amp;quot;wouldn&#039;t it be cool to write a function that...&amp;quot; than anything else. I do agree the values have always been not quite right. -- &#039;&#039;&#039;[[User:Strife_Onizuka|Strife]]&#039;&#039;&#039; &amp;lt;sup&amp;gt;&amp;lt;small&amp;gt;([[User talk:Strife_Onizuka|talk]]|[[Special:Contributions/Strife_Onizuka|contribs]])&amp;lt;/small&amp;gt;&amp;lt;/sup&amp;gt; 23:10, 5 July 2013 (PDT)&lt;br /&gt;
:::::::::Thanks! OK, I did a bunch of empirical testing, sampling a bunch of avatars from 1.16m to 2.45m in height, as reported by llGetAgentSize. I picked the lowest and highest and one about standard height, and fitted a parabolic curve through them. I have reduced the inaccuracies to a great degree, but it still isn&#039;t 100% perfect for all sizes in that range, just the ones that I used to solve the curve equation. The rest show a *tiny* bit of movement, but they are very close. Obviously, the difference isn&#039;t parabolic, probably just some kind of discrete step function, but it works.[[User:Talarus Luan|Talarus Luan]] 11:16, 14 July 2013 (PDT)&lt;br /&gt;
&amp;lt;lsl&amp;gt;vector vCoefficients = &amp;lt;0.008906,-0.049831,0.088967&amp;gt;;&lt;br /&gt;
float fAdjust = vCoefficients.x * size.z * size.z + vCoefficients.y * size.z + vCoefficients.z;&lt;br /&gt;
llSetLinkPrimitiveParamsFast(linkNum,&lt;br /&gt;
    [PRIM_POS_LOCAL, (pos + &amp;lt;0.0, 0.0, 0.4&amp;gt; - (llRot2Up(rot) * size.z * fAdjust)) * localrot + localpos,&lt;br /&gt;
     PRIM_ROT_LOCAL, rot * localrot]);&amp;lt;/lsl&amp;gt;&lt;br /&gt;
&lt;br /&gt;
::::::::::I see you mind reading abilities haven&#039;t diminished (I contemplated suggesting the tests you have done, decided to go to bed instead). Any reason not to use parentheses? It looks like something that could get optimized to an a series of FMAs (by the VM). -- &#039;&#039;&#039;[[User:Strife_Onizuka|Strife]]&#039;&#039;&#039; &amp;lt;sup&amp;gt;&amp;lt;small&amp;gt;([[User talk:Strife_Onizuka|talk]]|[[Special:Contributions/Strife_Onizuka|contribs]])&amp;lt;/small&amp;gt;&amp;lt;/sup&amp;gt; 21:33, 14 July 2013 (PDT)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;lsl&amp;gt;vector vCoefficients = &amp;lt;0.008906,-0.049831,0.088967&amp;gt;;&lt;br /&gt;
float fAdjust = ((((vCoefficients.x * size.z) + vCoefficients.y) * size.z) + vCoefficients.z) * size.z;&lt;br /&gt;
llSetLinkPrimitiveParamsFast(linkNum,&lt;br /&gt;
    [PRIM_POS_LOCAL, (pos + &amp;lt;0.0, 0.0, 0.4&amp;gt; - (llRot2Up(rot) * fAdjust)) * localrot + localpos,&lt;br /&gt;
     PRIM_ROT_LOCAL, rot * localrot]);&amp;lt;/lsl&amp;gt;&lt;br /&gt;
:::::::::::Yeah, I thought about optimizing it a bit after I posted it, but decided to leave it unoptimized here so the path from the current function to this change was clear, for demonstrability purposes. Besides, I had to leave some room for it to be Strifed&amp;amp;trade;. :P [[User:Talarus Luan|Talarus Luan]] 15:17, 17 July 2013 (PDT)&lt;br /&gt;
&lt;br /&gt;
::::::::::::I appreciate the gesture :p and I&#039;m not as bad as I use to be. I&#039;m not going to optimize out fAdjust, it&#039;s more readable this way. This is more for myself later as my memory is crap, the reasoning behind using llRot2Up is that it solves the pesky problem of the quaternion not having a magnitude of one. While the following isn&#039;t optimal, it is cool. -- &#039;&#039;&#039;[[User:Strife_Onizuka|Strife]]&#039;&#039;&#039; &amp;lt;sup&amp;gt;&amp;lt;small&amp;gt;([[User talk:Strife_Onizuka|talk]]|[[Special:Contributions/Strife_Onizuka|contribs]])&amp;lt;/small&amp;gt;&amp;lt;/sup&amp;gt; 00:00, 18 July 2013 (PDT)&lt;br /&gt;
&amp;lt;lsl&amp;gt;&lt;br /&gt;
size.x = (size.z * (size.y = (size.z * size.z)));&lt;br /&gt;
float fAdjust = vCoefficients * size;&lt;br /&gt;
&amp;lt;/lsl&amp;gt;&lt;br /&gt;
:::::::::::::Yeah, that is a nice way to represent it, for those used to the LSL representation for vector dot product. I&#039;m a little less enthused about the size vector assignment chain, but that&#039;s just my general dislike for C value assignments and such. In my mind, I separate assignments from expressions, so seeing them mixed together causes a bit of a train wreck in my brain&#039;s lexical analyzer. :P[[User:Talarus Luan|Talarus Luan]] 10:00, 21 July 2013 (PDT)&lt;br /&gt;
&lt;br /&gt;
::::::::::::::I don&#039;t think anyone uses the LSL vector dot product. It took me three days to remember it existed and then I look up the syntax just to make sure I wasn&#039;t crazy (yes yes, I agree it&#039;s insane to think that looking up the syntax of an obscure feature is proof against insanity but I&#039;m sticking to it, my cat agrees). I think a train wreck was my goal. -- &#039;&#039;&#039;[[User:Strife_Onizuka|Strife]]&#039;&#039;&#039; &amp;lt;sup&amp;gt;&amp;lt;small&amp;gt;([[User talk:Strife_Onizuka|talk]]|[[Special:Contributions/Strife_Onizuka|contribs]])&amp;lt;/small&amp;gt;&amp;lt;/sup&amp;gt; 11:13, 21 July 2013 (PDT)&lt;br /&gt;
&lt;br /&gt;
== Avatars Floating After Sit ==&lt;br /&gt;
&lt;br /&gt;
The position of avatars will sometimes change, generally noticeable as a rise on the Z axis of perhaps half a meter - common triggers for this is typing or another AV sitting on the same object - though these are not exhaustive.  Does anyone have a clue why this happens, and how to prevent it from happening? [[User:TaraLi Jie|TaraLi Jie]] 21:14, 11 March 2012 (PDT)&lt;br /&gt;
&lt;br /&gt;
:Hmm, there are a few possible causes, but the main cause are the animations involved, so it&#039;s worth remembering that any animation overrider can potentially cause weirdness while on a sit-target, which is why most good ones can turn themselves off while seated. It&#039;s a bit difficult to describe specific problems with animations, but I think that sometimes it can be caused by animations that have a weird first frame, since it&#039;s used to calculate all the offsets etc. for the rest of the animation; normally this will be a neutral pose since you don&#039;t actually see it in the animation, but if it&#039;s something odd then it can mess with positioning. -- &amp;lt;br/&amp;gt;-- &#039;&#039;&#039;[[User:Haravikk_Mistral|Haravikk]]&#039;&#039;&#039; &amp;lt;sup&amp;gt;&amp;lt;small&amp;gt;([[User_talk:Haravikk_Mistral|talk]]|[[Special:Contributions/Haravikk_Mistral|contribs]])&amp;lt;/small&amp;gt;&amp;lt;/sup&amp;gt; 05:34, 12 March 2012 (PDT)&lt;br /&gt;
&lt;br /&gt;
::When I&#039;ve had problems with this, the root cause has usually been that I&#039;ve (or something has) inadvertently stopped an animation that&#039;s holding the avatar in place before starting another one.   Because animations are all made differently, neither the animator with whom I work most of the time nor I have ever managed to figure out exactly what to avoid, but certainly when it happens to me, I always start debugging by looking very carefully at where I&#039;m turning animations off and considering whether, in fact, I need to turn them off at all.   Quite often, I find that simply turning off the default sit animation when my first animation starts, and then keeping the first animation going throughout, starting and stopping other ones over it, as necessary, solves the problem.&lt;br /&gt;
&lt;br /&gt;
::One &amp;quot;gotcha&amp;quot; is that stopping an animation and then immediately restarting it doesn&#039;t work.  It confuses the viewer something horrible, and often leads to people floating in mid-air.  [[User:Innula Zenovka|Innula Zenovka]] 09:04, 12 March 2012 (PDT)&lt;br /&gt;
&lt;br /&gt;
== Sit Target 0.4m &#039;bug&#039; ==&lt;br /&gt;
The notes say &lt;br /&gt;
&amp;quot;rot affects the position of the sit-target in a buggy way way.&lt;br /&gt;
To correct for the rot bug, simply subtract &amp;lt;0,0,0.4&amp;gt; from the position when rot is zero. See example below.&amp;quot;&lt;br /&gt;
&lt;br /&gt;
But the example script adjusts z by 0.4m when rotation is NOT zero.&lt;br /&gt;
&amp;lt;lsl&amp;gt;&lt;br /&gt;
if (rot!=ZERO_ROTATION) pos -=&amp;lt;0,0,0.4&amp;gt;;  //here is the work around&lt;br /&gt;
&amp;lt;/lsl&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Which should it be?&lt;br /&gt;
&lt;br /&gt;
I&#039;ve just been doing some tests without any 0.4m adjustment, and I am unable to observe any difference in my z position whether rotation is zero or not. Has something changed? If so, wouldn&#039;t the change screw up some furniture?&lt;br /&gt;
[[User:Omei Qunhua|Omei Qunhua]] 14:09, 16 March 2014 (PDT)&lt;br /&gt;
&lt;br /&gt;
:You are right, there shouldn&#039;t be a test there. My understanding is that you always need to subtract 0.4 from z. Changing it would screw up furniture. -- &#039;&#039;&#039;[[User:Strife_Onizuka|Strife]]&#039;&#039;&#039; &amp;lt;sup&amp;gt;&amp;lt;small&amp;gt;([[User talk:Strife_Onizuka|talk]]|[[Special:Contributions/Strife_Onizuka|contribs]])&amp;lt;/small&amp;gt;&amp;lt;/sup&amp;gt; 21:02, 16 March 2014 (PDT)&lt;/div&gt;</summary>
		<author><name>Timmy Foxclaw</name></author>
	</entry>
	<entry>
		<id>https://wiki.secondlife.com/w/index.php?title=Talk:LlSitTarget&amp;diff=1189277</id>
		<title>Talk:LlSitTarget</title>
		<link rel="alternate" type="text/html" href="https://wiki.secondlife.com/w/index.php?title=Talk:LlSitTarget&amp;diff=1189277"/>
		<updated>2014-04-07T22:41:12Z</updated>

		<summary type="html">&lt;p&gt;Timmy Foxclaw: Reply to Strife&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Unsitting on wrong side or camera rotation ==&lt;br /&gt;
&lt;br /&gt;
Hi, i am getting frustrated with this. I create a board and set the sit target with&lt;br /&gt;
&amp;lt;code&amp;gt;llSitTarget(&amp;lt;0.4, 0.0, 0.0&amp;gt;, ZERO_ROTATION);&amp;lt;/code&amp;gt;&lt;br /&gt;
and an animation which for &amp;quot;standing&amp;quot;. So while the person technical sits, she stands in front of the board. &lt;br /&gt;
But I have a problem with that: If the board stand freely, the person unsits right through it towards the other side. I can put the board with the back  facing a large wall. In the case the unsitting is correctly in front of it. But on sit down the camera rotates, so that it is behind the avatar again; on the other side of the wall.&lt;br /&gt;
&lt;br /&gt;
If anyone has an idea how to fix, please tell me (even if it is just an idea where to look for more information). --[[User:Maike Short|Maike Short]] 12:41, 24 February 2008 (PST)&lt;br /&gt;
&lt;br /&gt;
:You could position the camera with the {{LSLGC|Camera}} functions.  -- [[User:Strife Onizuka|Strife Onizuka]] 04:46, 25 February 2008 (PST)&lt;br /&gt;
&lt;br /&gt;
==GetSitTarget==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;lsl&amp;gt;&lt;br /&gt;
list GetSitTarget(integer prim, key av)&lt;br /&gt;
{//WARNING: llGetObjectDetails can introduce an error that goes as far as the 5th decimal place.&lt;br /&gt;
    vector tp = llGetAgentSize(av);&lt;br /&gt;
    if(tp)&lt;br /&gt;
    {&lt;br /&gt;
        if(prim == LINK_THIS)//llGetLinkKey doesn&#039;t like LINK_THIS&lt;br /&gt;
            prim = llGetLinkNumber();&lt;br /&gt;
    &lt;br /&gt;
        list details = OBJECT_POS + (list)OBJECT_ROT;&lt;br /&gt;
        rotation f = llList2Rot(details = (llGetObjectDetails(llGetLinkKey(prim), details) + llGetObjectDetails(av, details)), 1);&lt;br /&gt;
    &lt;br /&gt;
        return [(llRot2Up(f = (llList2Rot(details, 3) / f)) * tp.z * 0.02638) +&lt;br /&gt;
                ((llList2Vector(details, 2) - llList2Vector(details, 0)) / f) - &amp;lt;0.0, 0.0, 0.4&amp;gt;, f];&lt;br /&gt;
    }&lt;br /&gt;
    return [];&lt;br /&gt;
}//Written by Strife Onizuka&lt;br /&gt;
&amp;lt;/lsl&amp;gt;&lt;br /&gt;
Hi Strife! This version of your GetSitTarget, and the other version on the actual LlSitTarget page, both always return &amp;lt;0.000000, 0.000000, 0.707107, 0.707107&amp;gt; for the rotation. --[[User:MartinRJ Fayray|MartinRJ Fayray]] 07:52, 21 January 2013 (PST)&lt;br /&gt;
&lt;br /&gt;
:I haven&#039;t touched this in 5 years but I don&#039;t see a reason why it should be doing what you say. Are you sure you are using it properly? The prim parameter specifies what prim the location will be local to. The function was written to aid in determining sit targets when making furniture. You have the avatar sit on one object and then you get it&#039;s position local to the furniture so you can program in the sit target.&lt;br /&gt;
&lt;br /&gt;
:Just to clarify, you are saying that when you sit on an object with the following script in it, you don&#039;t get approximately the specified value? -- &#039;&#039;&#039;[[User:Strife_Onizuka|Strife]]&#039;&#039;&#039; &amp;lt;sup&amp;gt;&amp;lt;small&amp;gt;([[User talk:Strife_Onizuka|talk]]|[[Special:Contributions/Strife_Onizuka|contribs]])&amp;lt;/small&amp;gt;&amp;lt;/sup&amp;gt; 20:37, 22 January 2013 (PST)&lt;br /&gt;
&lt;br /&gt;
:It seems to work now. No idea what I was doing wrong. Thank you strife!--[[User:MartinRJ Fayray|MartinRJ Fayray]] 07:36, 3 February 2013 (PST)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;lsl&amp;gt;&lt;br /&gt;
vector vOffset = &amp;lt;0,0,1&amp;gt;;&lt;br /&gt;
rotation rOffset = &amp;lt;0,0,0,1&amp;gt;;&lt;br /&gt;
&lt;br /&gt;
list GetSitTarget(integer prim, key av)&lt;br /&gt;
{//WARNING: llGetObjectDetails can introduce an error that goes as far as the 5th decimal place!&lt;br /&gt;
 //This is highly unlikely to be ever noticed unless compounded over time.&lt;br /&gt;
 //Do not use while moving (like in a moving vehicle)!!!&lt;br /&gt;
    vector tp = llGetAgentSize(av);&lt;br /&gt;
    if(tp)&lt;br /&gt;
    {&lt;br /&gt;
        if(prim == LINK_THIS)//llGetLinkKey doesn&#039;t like LINK_THIS&lt;br /&gt;
            prim = llGetLinkNumber();&lt;br /&gt;
 &lt;br /&gt;
        list details = [OBJECT_POS, OBJECT_ROT];&lt;br /&gt;
        rotation f = llList2Rot(details = (llGetObjectDetails(llGetLinkKey(prim), details) + llGetObjectDetails(av, details)), 1);&lt;br /&gt;
        rotation r = llList2Rot(details, 3) / f;&lt;br /&gt;
 &lt;br /&gt;
        return [((llList2Vector(details, 2) - llList2Vector(details, 0)) / f) + (llRot2Up(r) * tp.z * 0.02638) - &amp;lt;0.0, 0.0, 0.4&amp;gt;, r];&lt;br /&gt;
    }&lt;br /&gt;
    return [];&lt;br /&gt;
}//Written by Strife Onizuka&lt;br /&gt;
&lt;br /&gt;
default{&lt;br /&gt;
    state_entry(){&lt;br /&gt;
        llSitTarget(vOffset, rOffset);&lt;br /&gt;
    }&lt;br /&gt;
    changed(integer change){&lt;br /&gt;
        key id = llAvatarOnSitTarget();&lt;br /&gt;
        if(id)&lt;br /&gt;
            llOwnerSay(&amp;quot;[&amp;quot;+llList2CSV([vOffset, rOffset]) +&amp;quot;] ~ [&amp;quot; + llList2CSV(GetSitTarget(LINK_THIS, id))+&amp;quot;]&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/lsl&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Note&#039;&#039;&#039;: the above two scripts in this paragraph are incorrect. Most notably, the position of an avatar (it&#039;s Avatar Center) is NOT dependent on the AgentSize of the seated avatar. I added another script that returns the sit target, below. [[User:Timmy Foxclaw|Timmy Foxclaw]] 10:31, 7 April 2014 (PDT)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;lsl&amp;gt;&lt;br /&gt;
// A script to develop and test sbGetLinkSitTarget&lt;br /&gt;
//&lt;br /&gt;
// Copyright(c) Timmy Songbird @DreamNation&lt;br /&gt;
//              Timmy Foxclaw  @SL,&lt;br /&gt;
//              2014&lt;br /&gt;
//&lt;br /&gt;
// This program is free software; you can redistribute it and/or modify&lt;br /&gt;
// it under the terms of the GNU General Public License as published by&lt;br /&gt;
// the Free Software Foundation; either version 2 of the License, or&lt;br /&gt;
// (at your option) any later version.&lt;br /&gt;
//&lt;br /&gt;
// This program is distributed in the hope that it will be useful,&lt;br /&gt;
// but WITHOUT ANY WARRANTY; without even the implied warranty of&lt;br /&gt;
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the&lt;br /&gt;
// GNU General Public License for more details.&lt;br /&gt;
//&lt;br /&gt;
// You should have received a copy of the GNU General Public License&lt;br /&gt;
// along with this program; if not, write to the Free Software&lt;br /&gt;
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307, USA.&#039;)&lt;br /&gt;
&lt;br /&gt;
//----------------------------------------------------------------------------&lt;br /&gt;
//#line &amp;quot;/opt/secondlife/scripts/scripts/tests/sbGetLinkSitTarget_Test.m4s:4&amp;quot;&lt;br /&gt;
// This script sets a &amp;quot;random&amp;quot;-ish sit target on every prim in an object.&lt;br /&gt;
// Recommended for your test is an object existing of two default cubes&lt;br /&gt;
// with arbitrary rotations and position. Put this script only in the&lt;br /&gt;
// root prim.&lt;br /&gt;
//&lt;br /&gt;
// The script sets the sit targets on compile or touch. Please touch&lt;br /&gt;
// the object after editting one of the prims.&lt;br /&gt;
//&lt;br /&gt;
// When an avatar (un)sits on one of the prims, the script prints for every&lt;br /&gt;
// sit target that has a seated avatar the return value of sbGetLinkSitTarget.&lt;br /&gt;
// This value should be (almost) equal to the values passed to llSitTarget.&lt;br /&gt;
&lt;br /&gt;
// Example output:&lt;br /&gt;
&lt;br /&gt;
// Object: [&amp;lt;0.200000, 0.300000, 0.500000&amp;gt;, &amp;lt;0.100000, 0.150000, 0.120000, 0.976268&amp;gt;] set with llSitTarget on 2 prims.&lt;br /&gt;
// Object: [&amp;lt;0.199999, 0.300001, 0.499999&amp;gt;, &amp;lt;0.100000, 0.150000, 0.120000, 0.976268&amp;gt;] returned by sbGetLinkSitTarget(1).&lt;br /&gt;
// Object: [&amp;lt;0.199998, 0.300002, 0.499998&amp;gt;, &amp;lt;0.100000, 0.150000, 0.120000, 0.976268&amp;gt;] returned by sbGetLinkSitTarget(2).&lt;br /&gt;
&lt;br /&gt;
// GitLocation: tests/sbGetLinkSitTarget_Test.m4s&lt;br /&gt;
&lt;br /&gt;
//----------------------------------------------------------------------------&lt;br /&gt;
//#line &amp;quot;/opt/secondlife/scripts/scripts/tests/sbGetLinkSitTarget_Test.m4s:26&amp;quot;&lt;br /&gt;
vector sitTarget_pos_link = &amp;lt;0.2, 0.3, 0.5&amp;gt;;&lt;br /&gt;
rotation sitTarget_rot_link = &amp;lt;0.1, 0.15, 0.12, 0.9762684&amp;gt;;&lt;br /&gt;
&lt;br /&gt;
//----------------------------------------------------------------------------&lt;br /&gt;
//#line &amp;quot;/opt/secondlife/scripts/scripts/tests/sbGetLinkSitTarget_Test.m4s:31&amp;quot;&lt;br /&gt;
// Returns the correct values to use for llSitTarget to make&lt;br /&gt;
// the currently seated avatar sit in the same way when re-seated.&lt;br /&gt;
// If no avatar is currently sitting then [ZERO_VECTOR, ZERO_ROTATION] is returned.&lt;br /&gt;
//&lt;br /&gt;
// [1] http://wiki.secondlife.com/wiki/User:Timmy_Foxclaw/About_Coordinate_Systems_and_Rotations#LSL_functions&lt;br /&gt;
// [2] http://wiki.secondlife.com/wiki/User:Timmy_Foxclaw/About_Coordinate_Systems_and_Rotations#Converting_between_coordinate_systems&lt;br /&gt;
list sbGetLinkSitTarget(integer link)&lt;br /&gt;
{&lt;br /&gt;
  // Calling llAvatarOnLinkSitTarget(0) always returns NULL_KEY because the link&lt;br /&gt;
  // number of an unlinked prim changes from 0 to 1 as soon as an avatar sits on&lt;br /&gt;
  // it. So if 0 was passed then they probably meant 1.&lt;br /&gt;
  if (link == 0)&lt;br /&gt;
  {&lt;br /&gt;
    link = 1;&lt;br /&gt;
  }&lt;br /&gt;
  key av = llAvatarOnLinkSitTarget(link);&lt;br /&gt;
  if (av != NULL_KEY)&lt;br /&gt;
  {&lt;br /&gt;
    // Get link_pos_oc and link_rot_oc. See table 2 in [1].&lt;br /&gt;
    vector link_pos_oc = ZERO_VECTOR;&lt;br /&gt;
    rotation link_rot_oc = ZERO_ROTATION;&lt;br /&gt;
    if (link &amp;gt; 1)&lt;br /&gt;
    {&lt;br /&gt;
      list params = llGetLinkPrimitiveParams(link, [PRIM_POS_LOCAL, PRIM_ROT_LOCAL]);&lt;br /&gt;
      link_pos_oc = llList2Vector(params, 0);&lt;br /&gt;
      link_rot_oc = llList2Rot(params, 1);&lt;br /&gt;
    }&lt;br /&gt;
    // Find the link number of the seated avatar.&lt;br /&gt;
    integer avNum = llGetNumberOfPrims();&lt;br /&gt;
    do&lt;br /&gt;
    {&lt;br /&gt;
        if (av == llGetLinkKey(avNum))&lt;br /&gt;
        {&lt;br /&gt;
            // Get ac_pos_oc and ac_rot_oc (ac stands for Avatar Center), exactly the same as above&lt;br /&gt;
            // except that we don&#039;t need to test if avNum &amp;gt; 1, because it always will be.&lt;br /&gt;
            list params = llGetLinkPrimitiveParams(avNum, [PRIM_POS_LOCAL, PRIM_ROT_LOCAL]);&lt;br /&gt;
            vector ac_pos_oc = llList2Vector(params, 0);&lt;br /&gt;
            rotation ac_rot_oc = llList2Rot(params, 1);&lt;br /&gt;
&lt;br /&gt;
            // Convert that to link coordinates. See formula (3) in [2].&lt;br /&gt;
            vector ac_pos_link = (ac_pos_oc - link_pos_oc) / link_rot_oc;&lt;br /&gt;
            rotation ac_rot_link = ac_rot_oc / link_rot_oc;&lt;br /&gt;
&lt;br /&gt;
            // Now we have this little vector in the Avatar Center coordinates.&lt;br /&gt;
            vector sit_pos_ac = &amp;lt;0.0, 0.0, 0.05&amp;gt;;&lt;br /&gt;
&lt;br /&gt;
            // Convert that to link coordinates. See formula (1) in [2].&lt;br /&gt;
            vector sit_pos_link = sit_pos_ac * ac_rot_link + ac_pos_link;&lt;br /&gt;
&lt;br /&gt;
            // Return the values, accounting for the sit target bug of 0.4m.&lt;br /&gt;
            return [sit_pos_link - &amp;lt;0.0, 0.0, 0.4&amp;gt;, ac_rot_link];&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    while (--avNum);&lt;br /&gt;
  }&lt;br /&gt;
  return [ZERO_VECTOR, ZERO_ROTATION];&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
setSitTargets()&lt;br /&gt;
{&lt;br /&gt;
  // Set the same sit target on every prim.&lt;br /&gt;
  integer n = llGetNumberOfPrims();&lt;br /&gt;
  llSay(0, &amp;quot;[&amp;quot; +  llList2CSV([sitTarget_pos_link, sitTarget_rot_link]) + &amp;quot;] set with llSitTarget on &amp;quot; + (string)n + &amp;quot; prims.&amp;quot;);&lt;br /&gt;
  do&lt;br /&gt;
  {&lt;br /&gt;
    llLinkSitTarget(n, sitTarget_pos_link, sitTarget_rot_link);&lt;br /&gt;
  }&lt;br /&gt;
  while(--n);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
//----------------------------------------------------------------------------&lt;br /&gt;
//#line &amp;quot;/opt/secondlife/scripts/scripts/tests/sbGetLinkSitTarget_Test.m4s:105&amp;quot;&lt;br /&gt;
default&lt;br /&gt;
{&lt;br /&gt;
  state_entry()&lt;br /&gt;
  {&lt;br /&gt;
    setSitTargets();&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  touch_start(integer n)&lt;br /&gt;
  {&lt;br /&gt;
    setSitTargets();&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  changed(integer change)&lt;br /&gt;
  {&lt;br /&gt;
    if ((change &amp;amp; CHANGED_LINK))&lt;br /&gt;
    {&lt;br /&gt;
      integer n = llGetNumberOfPrims();&lt;br /&gt;
      do&lt;br /&gt;
      {&lt;br /&gt;
        key av = llAvatarOnLinkSitTarget(n);&lt;br /&gt;
        if (av != NULL_KEY)&lt;br /&gt;
        {&lt;br /&gt;
          llSay(0, &amp;quot;[&amp;quot; + llList2CSV(sbGetLinkSitTarget(n)) + &amp;quot;] returned by sbGetLinkSitTarget(&amp;quot; + (string)n + &amp;quot;).&amp;quot;);&lt;br /&gt;
        }&lt;br /&gt;
      }&lt;br /&gt;
      while(--n);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/lsl&amp;gt;&lt;br /&gt;
:Yes the above two scripts are older versions. The 0.05 offset has been tried before. {{User|Talarus Luan}} [https://wiki.secondlife.com/w/index.php?title=LlSitTarget&amp;amp;diff=1179695&amp;amp;oldid=1179694 could not get it to work]. {{User|Talarus Luan}} went on to work out a quadratic equation that provided a more accurate result. See [[#UpdateSitTarget_changes.3F|#UpdateSitTarget changes?]] below. -- &#039;&#039;&#039;[[User:Strife_Onizuka|Strife]]&#039;&#039;&#039; &amp;lt;sup&amp;gt;&amp;lt;small&amp;gt;([[User talk:Strife_Onizuka|talk]]|[[Special:Contributions/Strife_Onizuka|contribs]])&amp;lt;/small&amp;gt;&amp;lt;/sup&amp;gt; 12:38, 7 April 2014 (PDT)&lt;br /&gt;
&lt;br /&gt;
Hi Strife. There must be some miscommunication - we seem to be talking about different things. After extensive research (see [[ User:Timmy_Foxclaw/About_Coordinate_Systems_and_Rotations|this link]], especially the script at the end), I have found that the value is exactly 0.05 and not depend on the height of the avatar in SecondLife. The function sbGetLinkSitTarget as defined in the script above returns the exact values (within the normal floating point round off error of 0.000002 or so), no matter what position and rotation you passed to llSitTarget. Perhaps we can meet in some sandbox in SL? I&#039;d like to understand where your quadratic expression exactly comes in. Maybe you can show me the test object and the tests that you did to determine it. [[User:Timmy Foxclaw|Timmy Foxclaw]] 15:41, 7 April 2014 (PDT)&lt;br /&gt;
&lt;br /&gt;
==Using llSetLinkPrimitiveParams for skydiving: why limited to 5m in a linked set?==&lt;br /&gt;
llSetLinkPrimitiveParams can be used as a handy tool to adjust an avatar&#039;s position and rotation.&lt;br /&gt;
This works perfectly when the object consists of 1 prim, with a range for setting the avatar position away to 500m easily!&lt;br /&gt;
When there are more prims linked, this offset seems to be limited to 5m (measured with llVecDist). This is an awfull sideeffect!&lt;br /&gt;
&lt;br /&gt;
Put this next script inside a prim and sit on the prim, it will bring you to 1000.0 higher then the prim.&lt;br /&gt;
Next link this prim to another prim and try again. You will notice you are limited to 5m. My Question: why is this limited?&lt;br /&gt;
&amp;lt;lsl&amp;gt;&lt;br /&gt;
// by Randur Source&lt;br /&gt;
&lt;br /&gt;
integer heightcnt = 0;&lt;br /&gt;
list heights = [0.0, 1.0, 5.0, 6.0, 10.0, 100.0, 300.0, 500.0, 800.0, 1000.0];&lt;br /&gt;
&lt;br /&gt;
default&lt;br /&gt;
{&lt;br /&gt;
    state_entry()&lt;br /&gt;
    {&lt;br /&gt;
        llSitTarget(ZERO_VECTOR,ZERO_ROTATION); // Clear the current sittarget for a clear test&lt;br /&gt;
        llSetRot(ZERO_ROTATION); // set the prim to no rotation, for simple z axis movement&lt;br /&gt;
    }&lt;br /&gt;
    &lt;br /&gt;
    changed(integer change)&lt;br /&gt;
    {&lt;br /&gt;
        if (change &amp;amp; CHANGED_LINK) // detect linked prims and avatars&lt;br /&gt;
        {&lt;br /&gt;
            integer primnum = llGetNumberOfPrims(); // the avatar is the last linked prim&lt;br /&gt;
            if (primnum &amp;lt;= 1) // stop if there is only 1 prim&lt;br /&gt;
                return;&lt;br /&gt;
        &lt;br /&gt;
            key avatar = llGetLinkKey(primnum);&lt;br /&gt;
            if (llGetAgentSize(avatar) == ZERO_VECTOR) // stop if this is not an avatar&lt;br /&gt;
                return;&lt;br /&gt;
                &lt;br /&gt;
            // loop through the list of test heights:&lt;br /&gt;
            for (heightcnt = 0; heightcnt &amp;lt; llGetListLength(heights); heightcnt++)&lt;br /&gt;
            {&lt;br /&gt;
                float height = llList2Float(heights,heightcnt);&lt;br /&gt;
                llSetLinkPrimitiveParams(primnum,[PRIM_POSITION,&amp;lt;0.0,0.0,height&amp;gt;]); // set this to the wanted height using a vector z axis&lt;br /&gt;
                &lt;br /&gt;
                vector avatarpos = llList2Vector(llGetObjectDetails(avatar,[OBJECT_POS]),0); // detect the avatar position within the sim&lt;br /&gt;
                float distance = llVecDist(llGetPos(),avatarpos);&lt;br /&gt;
                llOwnerSay(&amp;quot;Attempt to move &amp;quot; + llKey2Name(llGetLinkKey(primnum)) +&lt;br /&gt;
                           &amp;quot; to &amp;quot; + (string)height + &amp;quot;m high resulting to &amp;quot; + (string)distance + &amp;quot;m&amp;quot;);&lt;br /&gt;
                &lt;br /&gt;
                llSleep(1.0);&lt;br /&gt;
            }&lt;br /&gt;
            llUnSit(avatar);&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/lsl&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Posted by Sylvio Runo : Answer &#039;&#039;&#039; :&lt;br /&gt;
The correct limit is 54 meters.&lt;br /&gt;
You can&#039;t move a linked object more than 54 meters away from the axis of the root prim.&lt;br /&gt;
On SecondLife (other grids like OsGrid, may works diferent) when an agent sit on prim, the agent is attached to it, so the agent is a linked prim of the link set.&lt;br /&gt;
&lt;br /&gt;
More information about link rules, you will find here : http://wiki.secondlife.com/wiki/Linkability_Rules [http://wiki.secondlife.com/wiki/Linkability_Rules]&lt;br /&gt;
&lt;br /&gt;
==UpdateSitTarget changes?==&lt;br /&gt;
I recently worked on a project where I used a version of this function, and it appears that it is a little off. A couple of things I noted: the Z-offset of the sit target is 0.35, not 0.4, and the avatar size doesn&#039;t seem to affect this position at all. When I used this function verbatim, I noticed discrepancies between the actual sit target and the set position call. When I changed the script as noted, I got a perfect match. Has the handling of the sit target been changed since this was written? [[User:Talarus Luan|Talarus Luan]] 22:57, 1 July 2009 (UTC)&lt;br /&gt;
:Seconded. I wish I&#039;d looked at this discussion before spending an hour on trying to figure out how the code actually behaved. -- [[User:Tonya Souther|Tonya Souther]] 15:11, 19 August 2009 (UTC)&lt;br /&gt;
&lt;br /&gt;
::This is news to me but I haven&#039;t been in world in ages :( -- &#039;&#039;&#039;[[User:Strife_Onizuka|Strife]]&#039;&#039;&#039; &amp;lt;sup&amp;gt;&amp;lt;small&amp;gt;([[User talk:Strife_Onizuka|talk]]|[[Special:Contributions/Strife_Onizuka|contribs]])&amp;lt;/small&amp;gt;&amp;lt;/sup&amp;gt; 22:56, 20 August 2009 (UTC)&lt;br /&gt;
&lt;br /&gt;
:::From some quick testing in 1.40, this seems to be how the &amp;quot;true&amp;quot; offset is computed:&lt;br /&gt;
:::1. Start with offset as provided by LSL.&lt;br /&gt;
:::2. Add &amp;lt; 0.0 , 0.0 , 0.4 &amp;gt;&lt;br /&gt;
:::3. Subtract llRot2Up( rot ) * 0.05&lt;br /&gt;
:::[[User:Gregory Maurer|--Gregory Maurer]] 20:00, 28 August 2010 (UTC)&lt;br /&gt;
&lt;br /&gt;
::::Confirmed. The following appears to work fine:&lt;br /&gt;
&amp;lt;lsl&amp;gt;llSetLinkPrimitiveParams(linkNum, [PRIM_POS_LOCAL, pos + &amp;lt;0.0, 0.0, 0.4&amp;gt; - (llRot2Up(rot) * 0.05), PRIM_ROT_LOCAL, rot]);&amp;lt;/lsl&amp;gt;&lt;br /&gt;
::::This of course using the new &amp;lt;code&amp;gt;PRIM_POS_LOCAL&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;PRIM_ROT_LOCAL&amp;lt;/code&amp;gt; values for simplicity. If one or two others can confirm that the above code works correctly, then I can splice it into the example.&amp;lt;br/&amp;gt;-- &#039;&#039;&#039;[[User:Haravikk_Mistral|Haravikk]]&#039;&#039;&#039; &amp;lt;sup&amp;gt;&amp;lt;small&amp;gt;([[User_talk:Haravikk_Mistral|talk]]|[[Special:Contributions/Haravikk_Mistral|contribs]])&amp;lt;/small&amp;gt;&amp;lt;/sup&amp;gt; 14:16, 26 December 2011 (PST)&lt;br /&gt;
&lt;br /&gt;
:::::Be sure to test it with avatars of different shapes, and shoe configurations. I recall that being an issue. {{User|Escort DeFarge}} would know about this best. -- &#039;&#039;&#039;[[User:Strife_Onizuka|Strife]]&#039;&#039;&#039; &amp;lt;sup&amp;gt;&amp;lt;small&amp;gt;([[User talk:Strife_Onizuka|talk]]|[[Special:Contributions/Strife_Onizuka|contribs]])&amp;lt;/small&amp;gt;&amp;lt;/sup&amp;gt; 22:05, 26 December 2011 (PST)&lt;br /&gt;
&lt;br /&gt;
::::::I tried with my two main avatar appearances, one average human height and one closer to 8 feet tall, and it didn&#039;t seem to make a difference. The test I used was a simple object with sit-target set, and a menu allowing it to be repositioned, causing the sit-target to move and if an avatar is seated on it, they will be repositioned using &amp;lt;code&amp;gt;llSetLinkPrimitiveParams()&amp;lt;/code&amp;gt; as done above. In my case the position of the avatar was consistent both when sitting on the object (using the sit-target) and being repositioned. Avatar height appears to have no effect, as the sit-target seems to define the avatar&#039;s hip-location, which is seemingly the avatar&#039;s &amp;quot;centre&amp;quot; when seated. I&#039;ll try to run some more tests when I get a chance, as it&#039;s possible this behaviour may not hold true if the object doesn&#039;t have a sit-target on it. The height of the avatar does however have a marked visual impact, depending exactly what you&#039;re trying to line up where, but that&#039;s a general issue with sitting on objects.&amp;lt;br/&amp;gt;-- &#039;&#039;&#039;[[User:Haravikk_Mistral|Haravikk]]&#039;&#039;&#039; &amp;lt;sup&amp;gt;&amp;lt;small&amp;gt;([[User_talk:Haravikk_Mistral|talk]]|[[Special:Contributions/Haravikk_Mistral|contribs]])&amp;lt;/small&amp;gt;&amp;lt;/sup&amp;gt; 05:38, 28 December 2011 (PST)&lt;br /&gt;
:::::::Sorry for my long delay in responding. Due to various RL issues and SL/LL burnout, I took a year off from SL to pursue other activities. That said, it seems to work fine to me, Haravikk; however, I have not done exhaustive testing with tons of different avs, shoes, etc. I would consider going ahead and changing it, because the version as it is right now is not correct for the majority of avatars, regardless. If Escort DeFarge or someone else wants to amend it later to include edge cases, that&#039;s great, but a better base accuracy is more important at this point. In fact, I think I will go ahead and edit it in, since it has been so long anyway.[[User:Talarus Luan|Talarus Luan]] 12:12, 5 July 2013 (PDT)&lt;br /&gt;
:::::::Holding up on the edit, further testing is revealing that if the script is in a prim other than the root, it is off by varying amounts depending on the rotation.[[User:Talarus Luan|Talarus Luan]] 12:39, 5 July 2013 (PDT)&lt;br /&gt;
:::::::OK, I think I found the error. Still need to keep the local position/rotation values for the child prim the script is in, like so:&lt;br /&gt;
&amp;lt;lsl&amp;gt;llSetLinkPrimitiveParams(linkNum, PRIM_POS_LOCAL, (pos + &amp;lt;0.0, 0.0, 0.4&amp;gt; - (llRot2Up(rot) * 0.05)) * localrot + localpos, PRIM_ROT_LOCAL, rot * localrot]);&amp;lt;/lsl&amp;gt;&lt;br /&gt;
:::::::I&#039;ll hold off on the edit until I can get another verify that this code is good.[[User:Talarus Luan|Talarus Luan]] 12:51, 5 July 2013 (PDT)&lt;br /&gt;
:::::::OK. I think I have analyzed this to death today and have come to the conclusion that Strife&#039;s original code is largely correct, but the error I am seeing comes from the &amp;quot;magic constants&amp;quot; 0.4 and 0.02638. Haravikk&#039;s code is simply a reduced form of Strife&#039;s code. The 0.4 magic constant is still there, but Haravikk is using just a close, but fixed, magic constant of 0.05 instead of Strife&#039;s (size.z * 0.02638), which comes out very close to 0.5 for most normal human avs. Thus, I am concluding that the inaccuracy is in the &amp;quot;magic constants&amp;quot; themselves, and I am going to hold off on the edit until I can get some more information on the source of these constants and see if there are better, more accurate values. It is annoying that, in all these years, we still haven&#039;t gotten LL to just tell us what the damn difference is between avatar sit targets and local position offsets in a linkset. It can&#039;t be that hard for someone who is familiar with the code to look at it and document it. -.- [[User:Talarus Luan|Talarus Luan]] 13:24, 5 July 2013 (PDT)&lt;br /&gt;
&lt;br /&gt;
::::::::Welcome back! I&#039;d like to take credit for that but that&#039;s the part that Escort contributed. As to where 0.02638 comes from, I vaguely recall it came from Escort&#039;s testing. I was driven more by &amp;quot;wouldn&#039;t it be cool to write a function that...&amp;quot; than anything else. I do agree the values have always been not quite right. -- &#039;&#039;&#039;[[User:Strife_Onizuka|Strife]]&#039;&#039;&#039; &amp;lt;sup&amp;gt;&amp;lt;small&amp;gt;([[User talk:Strife_Onizuka|talk]]|[[Special:Contributions/Strife_Onizuka|contribs]])&amp;lt;/small&amp;gt;&amp;lt;/sup&amp;gt; 23:10, 5 July 2013 (PDT)&lt;br /&gt;
:::::::::Thanks! OK, I did a bunch of empirical testing, sampling a bunch of avatars from 1.16m to 2.45m in height, as reported by llGetAgentSize. I picked the lowest and highest and one about standard height, and fitted a parabolic curve through them. I have reduced the inaccuracies to a great degree, but it still isn&#039;t 100% perfect for all sizes in that range, just the ones that I used to solve the curve equation. The rest show a *tiny* bit of movement, but they are very close. Obviously, the difference isn&#039;t parabolic, probably just some kind of discrete step function, but it works.[[User:Talarus Luan|Talarus Luan]] 11:16, 14 July 2013 (PDT)&lt;br /&gt;
&amp;lt;lsl&amp;gt;vector vCoefficients = &amp;lt;0.008906,-0.049831,0.088967&amp;gt;;&lt;br /&gt;
float fAdjust = vCoefficients.x * size.z * size.z + vCoefficients.y * size.z + vCoefficients.z;&lt;br /&gt;
llSetLinkPrimitiveParamsFast(linkNum,&lt;br /&gt;
    [PRIM_POS_LOCAL, (pos + &amp;lt;0.0, 0.0, 0.4&amp;gt; - (llRot2Up(rot) * size.z * fAdjust)) * localrot + localpos,&lt;br /&gt;
     PRIM_ROT_LOCAL, rot * localrot]);&amp;lt;/lsl&amp;gt;&lt;br /&gt;
&lt;br /&gt;
::::::::::I see you mind reading abilities haven&#039;t diminished (I contemplated suggesting the tests you have done, decided to go to bed instead). Any reason not to use parentheses? It looks like something that could get optimized to an a series of FMAs (by the VM). -- &#039;&#039;&#039;[[User:Strife_Onizuka|Strife]]&#039;&#039;&#039; &amp;lt;sup&amp;gt;&amp;lt;small&amp;gt;([[User talk:Strife_Onizuka|talk]]|[[Special:Contributions/Strife_Onizuka|contribs]])&amp;lt;/small&amp;gt;&amp;lt;/sup&amp;gt; 21:33, 14 July 2013 (PDT)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;lsl&amp;gt;vector vCoefficients = &amp;lt;0.008906,-0.049831,0.088967&amp;gt;;&lt;br /&gt;
float fAdjust = ((((vCoefficients.x * size.z) + vCoefficients.y) * size.z) + vCoefficients.z) * size.z;&lt;br /&gt;
llSetLinkPrimitiveParamsFast(linkNum,&lt;br /&gt;
    [PRIM_POS_LOCAL, (pos + &amp;lt;0.0, 0.0, 0.4&amp;gt; - (llRot2Up(rot) * fAdjust)) * localrot + localpos,&lt;br /&gt;
     PRIM_ROT_LOCAL, rot * localrot]);&amp;lt;/lsl&amp;gt;&lt;br /&gt;
:::::::::::Yeah, I thought about optimizing it a bit after I posted it, but decided to leave it unoptimized here so the path from the current function to this change was clear, for demonstrability purposes. Besides, I had to leave some room for it to be Strifed&amp;amp;trade;. :P [[User:Talarus Luan|Talarus Luan]] 15:17, 17 July 2013 (PDT)&lt;br /&gt;
&lt;br /&gt;
::::::::::::I appreciate the gesture :p and I&#039;m not as bad as I use to be. I&#039;m not going to optimize out fAdjust, it&#039;s more readable this way. This is more for myself later as my memory is crap, the reasoning behind using llRot2Up is that it solves the pesky problem of the quaternion not having a magnitude of one. While the following isn&#039;t optimal, it is cool. -- &#039;&#039;&#039;[[User:Strife_Onizuka|Strife]]&#039;&#039;&#039; &amp;lt;sup&amp;gt;&amp;lt;small&amp;gt;([[User talk:Strife_Onizuka|talk]]|[[Special:Contributions/Strife_Onizuka|contribs]])&amp;lt;/small&amp;gt;&amp;lt;/sup&amp;gt; 00:00, 18 July 2013 (PDT)&lt;br /&gt;
&amp;lt;lsl&amp;gt;&lt;br /&gt;
size.x = (size.z * (size.y = (size.z * size.z)));&lt;br /&gt;
float fAdjust = vCoefficients * size;&lt;br /&gt;
&amp;lt;/lsl&amp;gt;&lt;br /&gt;
:::::::::::::Yeah, that is a nice way to represent it, for those used to the LSL representation for vector dot product. I&#039;m a little less enthused about the size vector assignment chain, but that&#039;s just my general dislike for C value assignments and such. In my mind, I separate assignments from expressions, so seeing them mixed together causes a bit of a train wreck in my brain&#039;s lexical analyzer. :P[[User:Talarus Luan|Talarus Luan]] 10:00, 21 July 2013 (PDT)&lt;br /&gt;
&lt;br /&gt;
::::::::::::::I don&#039;t think anyone uses the LSL vector dot product. It took me three days to remember it existed and then I look up the syntax just to make sure I wasn&#039;t crazy (yes yes, I agree it&#039;s insane to think that looking up the syntax of an obscure feature is proof against insanity but I&#039;m sticking to it, my cat agrees). I think a train wreck was my goal. -- &#039;&#039;&#039;[[User:Strife_Onizuka|Strife]]&#039;&#039;&#039; &amp;lt;sup&amp;gt;&amp;lt;small&amp;gt;([[User talk:Strife_Onizuka|talk]]|[[Special:Contributions/Strife_Onizuka|contribs]])&amp;lt;/small&amp;gt;&amp;lt;/sup&amp;gt; 11:13, 21 July 2013 (PDT)&lt;br /&gt;
&lt;br /&gt;
== Avatars Floating After Sit ==&lt;br /&gt;
&lt;br /&gt;
The position of avatars will sometimes change, generally noticeable as a rise on the Z axis of perhaps half a meter - common triggers for this is typing or another AV sitting on the same object - though these are not exhaustive.  Does anyone have a clue why this happens, and how to prevent it from happening? [[User:TaraLi Jie|TaraLi Jie]] 21:14, 11 March 2012 (PDT)&lt;br /&gt;
&lt;br /&gt;
:Hmm, there are a few possible causes, but the main cause are the animations involved, so it&#039;s worth remembering that any animation overrider can potentially cause weirdness while on a sit-target, which is why most good ones can turn themselves off while seated. It&#039;s a bit difficult to describe specific problems with animations, but I think that sometimes it can be caused by animations that have a weird first frame, since it&#039;s used to calculate all the offsets etc. for the rest of the animation; normally this will be a neutral pose since you don&#039;t actually see it in the animation, but if it&#039;s something odd then it can mess with positioning. -- &amp;lt;br/&amp;gt;-- &#039;&#039;&#039;[[User:Haravikk_Mistral|Haravikk]]&#039;&#039;&#039; &amp;lt;sup&amp;gt;&amp;lt;small&amp;gt;([[User_talk:Haravikk_Mistral|talk]]|[[Special:Contributions/Haravikk_Mistral|contribs]])&amp;lt;/small&amp;gt;&amp;lt;/sup&amp;gt; 05:34, 12 March 2012 (PDT)&lt;br /&gt;
&lt;br /&gt;
::When I&#039;ve had problems with this, the root cause has usually been that I&#039;ve (or something has) inadvertently stopped an animation that&#039;s holding the avatar in place before starting another one.   Because animations are all made differently, neither the animator with whom I work most of the time nor I have ever managed to figure out exactly what to avoid, but certainly when it happens to me, I always start debugging by looking very carefully at where I&#039;m turning animations off and considering whether, in fact, I need to turn them off at all.   Quite often, I find that simply turning off the default sit animation when my first animation starts, and then keeping the first animation going throughout, starting and stopping other ones over it, as necessary, solves the problem.&lt;br /&gt;
&lt;br /&gt;
::One &amp;quot;gotcha&amp;quot; is that stopping an animation and then immediately restarting it doesn&#039;t work.  It confuses the viewer something horrible, and often leads to people floating in mid-air.  [[User:Innula Zenovka|Innula Zenovka]] 09:04, 12 March 2012 (PDT)&lt;br /&gt;
&lt;br /&gt;
== Sit Target 0.4m &#039;bug&#039; ==&lt;br /&gt;
The notes say &lt;br /&gt;
&amp;quot;rot affects the position of the sit-target in a buggy way way.&lt;br /&gt;
To correct for the rot bug, simply subtract &amp;lt;0,0,0.4&amp;gt; from the position when rot is zero. See example below.&amp;quot;&lt;br /&gt;
&lt;br /&gt;
But the example script adjusts z by 0.4m when rotation is NOT zero.&lt;br /&gt;
&amp;lt;lsl&amp;gt;&lt;br /&gt;
if (rot!=ZERO_ROTATION) pos -=&amp;lt;0,0,0.4&amp;gt;;  //here is the work around&lt;br /&gt;
&amp;lt;/lsl&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Which should it be?&lt;br /&gt;
&lt;br /&gt;
I&#039;ve just been doing some tests without any 0.4m adjustment, and I am unable to observe any difference in my z position whether rotation is zero or not. Has something changed? If so, wouldn&#039;t the change screw up some furniture?&lt;br /&gt;
[[User:Omei Qunhua|Omei Qunhua]] 14:09, 16 March 2014 (PDT)&lt;br /&gt;
&lt;br /&gt;
:You are right, there shouldn&#039;t be a test there. My understanding is that you always need to subtract 0.4 from z. Changing it would screw up furniture. -- &#039;&#039;&#039;[[User:Strife_Onizuka|Strife]]&#039;&#039;&#039; &amp;lt;sup&amp;gt;&amp;lt;small&amp;gt;([[User talk:Strife_Onizuka|talk]]|[[Special:Contributions/Strife_Onizuka|contribs]])&amp;lt;/small&amp;gt;&amp;lt;/sup&amp;gt; 21:02, 16 March 2014 (PDT)&lt;/div&gt;</summary>
		<author><name>Timmy Foxclaw</name></author>
	</entry>
	<entry>
		<id>https://wiki.secondlife.com/w/index.php?title=Talk:LlSitTarget&amp;diff=1189257</id>
		<title>Talk:LlSitTarget</title>
		<link rel="alternate" type="text/html" href="https://wiki.secondlife.com/w/index.php?title=Talk:LlSitTarget&amp;diff=1189257"/>
		<updated>2014-04-07T17:42:34Z</updated>

		<summary type="html">&lt;p&gt;Timmy Foxclaw: /* GetSitTarget */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Unsitting on wrong side or camera rotation ==&lt;br /&gt;
&lt;br /&gt;
Hi, i am getting frustrated with this. I create a board and set the sit target with&lt;br /&gt;
&amp;lt;code&amp;gt;llSitTarget(&amp;lt;0.4, 0.0, 0.0&amp;gt;, ZERO_ROTATION);&amp;lt;/code&amp;gt;&lt;br /&gt;
and an animation which for &amp;quot;standing&amp;quot;. So while the person technical sits, she stands in front of the board. &lt;br /&gt;
But I have a problem with that: If the board stand freely, the person unsits right through it towards the other side. I can put the board with the back  facing a large wall. In the case the unsitting is correctly in front of it. But on sit down the camera rotates, so that it is behind the avatar again; on the other side of the wall.&lt;br /&gt;
&lt;br /&gt;
If anyone has an idea how to fix, please tell me (even if it is just an idea where to look for more information). --[[User:Maike Short|Maike Short]] 12:41, 24 February 2008 (PST)&lt;br /&gt;
&lt;br /&gt;
:You could position the camera with the {{LSLGC|Camera}} functions.  -- [[User:Strife Onizuka|Strife Onizuka]] 04:46, 25 February 2008 (PST)&lt;br /&gt;
&lt;br /&gt;
==GetSitTarget==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;lsl&amp;gt;&lt;br /&gt;
list GetSitTarget(integer prim, key av)&lt;br /&gt;
{//WARNING: llGetObjectDetails can introduce an error that goes as far as the 5th decimal place.&lt;br /&gt;
    vector tp = llGetAgentSize(av);&lt;br /&gt;
    if(tp)&lt;br /&gt;
    {&lt;br /&gt;
        if(prim == LINK_THIS)//llGetLinkKey doesn&#039;t like LINK_THIS&lt;br /&gt;
            prim = llGetLinkNumber();&lt;br /&gt;
    &lt;br /&gt;
        list details = OBJECT_POS + (list)OBJECT_ROT;&lt;br /&gt;
        rotation f = llList2Rot(details = (llGetObjectDetails(llGetLinkKey(prim), details) + llGetObjectDetails(av, details)), 1);&lt;br /&gt;
    &lt;br /&gt;
        return [(llRot2Up(f = (llList2Rot(details, 3) / f)) * tp.z * 0.02638) +&lt;br /&gt;
                ((llList2Vector(details, 2) - llList2Vector(details, 0)) / f) - &amp;lt;0.0, 0.0, 0.4&amp;gt;, f];&lt;br /&gt;
    }&lt;br /&gt;
    return [];&lt;br /&gt;
}//Written by Strife Onizuka&lt;br /&gt;
&amp;lt;/lsl&amp;gt;&lt;br /&gt;
Hi Strife! This version of your GetSitTarget, and the other version on the actual LlSitTarget page, both always return &amp;lt;0.000000, 0.000000, 0.707107, 0.707107&amp;gt; for the rotation. --[[User:MartinRJ Fayray|MartinRJ Fayray]] 07:52, 21 January 2013 (PST)&lt;br /&gt;
&lt;br /&gt;
:I haven&#039;t touched this in 5 years but I don&#039;t see a reason why it should be doing what you say. Are you sure you are using it properly? The prim parameter specifies what prim the location will be local to. The function was written to aid in determining sit targets when making furniture. You have the avatar sit on one object and then you get it&#039;s position local to the furniture so you can program in the sit target.&lt;br /&gt;
&lt;br /&gt;
:Just to clarify, you are saying that when you sit on an object with the following script in it, you don&#039;t get approximately the specified value? -- &#039;&#039;&#039;[[User:Strife_Onizuka|Strife]]&#039;&#039;&#039; &amp;lt;sup&amp;gt;&amp;lt;small&amp;gt;([[User talk:Strife_Onizuka|talk]]|[[Special:Contributions/Strife_Onizuka|contribs]])&amp;lt;/small&amp;gt;&amp;lt;/sup&amp;gt; 20:37, 22 January 2013 (PST)&lt;br /&gt;
&lt;br /&gt;
:It seems to work now. No idea what I was doing wrong. Thank you strife!--[[User:MartinRJ Fayray|MartinRJ Fayray]] 07:36, 3 February 2013 (PST)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;lsl&amp;gt;&lt;br /&gt;
vector vOffset = &amp;lt;0,0,1&amp;gt;;&lt;br /&gt;
rotation rOffset = &amp;lt;0,0,0,1&amp;gt;;&lt;br /&gt;
&lt;br /&gt;
list GetSitTarget(integer prim, key av)&lt;br /&gt;
{//WARNING: llGetObjectDetails can introduce an error that goes as far as the 5th decimal place!&lt;br /&gt;
 //This is highly unlikely to be ever noticed unless compounded over time.&lt;br /&gt;
 //Do not use while moving (like in a moving vehicle)!!!&lt;br /&gt;
    vector tp = llGetAgentSize(av);&lt;br /&gt;
    if(tp)&lt;br /&gt;
    {&lt;br /&gt;
        if(prim == LINK_THIS)//llGetLinkKey doesn&#039;t like LINK_THIS&lt;br /&gt;
            prim = llGetLinkNumber();&lt;br /&gt;
 &lt;br /&gt;
        list details = [OBJECT_POS, OBJECT_ROT];&lt;br /&gt;
        rotation f = llList2Rot(details = (llGetObjectDetails(llGetLinkKey(prim), details) + llGetObjectDetails(av, details)), 1);&lt;br /&gt;
        rotation r = llList2Rot(details, 3) / f;&lt;br /&gt;
 &lt;br /&gt;
        return [((llList2Vector(details, 2) - llList2Vector(details, 0)) / f) + (llRot2Up(r) * tp.z * 0.02638) - &amp;lt;0.0, 0.0, 0.4&amp;gt;, r];&lt;br /&gt;
    }&lt;br /&gt;
    return [];&lt;br /&gt;
}//Written by Strife Onizuka&lt;br /&gt;
&lt;br /&gt;
default{&lt;br /&gt;
    state_entry(){&lt;br /&gt;
        llSitTarget(vOffset, rOffset);&lt;br /&gt;
    }&lt;br /&gt;
    changed(integer change){&lt;br /&gt;
        key id = llAvatarOnSitTarget();&lt;br /&gt;
        if(id)&lt;br /&gt;
            llOwnerSay(&amp;quot;[&amp;quot;+llList2CSV([vOffset, rOffset]) +&amp;quot;] ~ [&amp;quot; + llList2CSV(GetSitTarget(LINK_THIS, id))+&amp;quot;]&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/lsl&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Note&#039;&#039;&#039;: the above two scripts in this paragraph are incorrect. Most notably, the position of an avatar (it&#039;s Avatar Center) is NOT dependent on the AgentSize of the seated avatar. I added another script that returns the sit target, below. [[User:Timmy Foxclaw|Timmy Foxclaw]] 10:31, 7 April 2014 (PDT)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;lsl&amp;gt;&lt;br /&gt;
// A script to develop and test sbGetLinkSitTarget&lt;br /&gt;
//&lt;br /&gt;
// Copyright(c) Timmy Songbird @DreamNation&lt;br /&gt;
//              Timmy Foxclaw  @SL,&lt;br /&gt;
//              2014&lt;br /&gt;
//&lt;br /&gt;
// This program is free software; you can redistribute it and/or modify&lt;br /&gt;
// it under the terms of the GNU General Public License as published by&lt;br /&gt;
// the Free Software Foundation; either version 2 of the License, or&lt;br /&gt;
// (at your option) any later version.&lt;br /&gt;
//&lt;br /&gt;
// This program is distributed in the hope that it will be useful,&lt;br /&gt;
// but WITHOUT ANY WARRANTY; without even the implied warranty of&lt;br /&gt;
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the&lt;br /&gt;
// GNU General Public License for more details.&lt;br /&gt;
//&lt;br /&gt;
// You should have received a copy of the GNU General Public License&lt;br /&gt;
// along with this program; if not, write to the Free Software&lt;br /&gt;
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307, USA.&#039;)&lt;br /&gt;
&lt;br /&gt;
//----------------------------------------------------------------------------&lt;br /&gt;
//#line &amp;quot;/opt/secondlife/scripts/scripts/tests/sbGetLinkSitTarget_Test.m4s:4&amp;quot;&lt;br /&gt;
// This script sets a &amp;quot;random&amp;quot;-ish sit target on every prim in an object.&lt;br /&gt;
// Recommended for your test is an object existing of two default cubes&lt;br /&gt;
// with arbitrary rotations and position. Put this script only in the&lt;br /&gt;
// root prim.&lt;br /&gt;
//&lt;br /&gt;
// The script sets the sit targets on compile or touch. Please touch&lt;br /&gt;
// the object after editting one of the prims.&lt;br /&gt;
//&lt;br /&gt;
// When an avatar (un)sits on one of the prims, the script prints for every&lt;br /&gt;
// sit target that has a seated avatar the return value of sbGetLinkSitTarget.&lt;br /&gt;
// This value should be (almost) equal to the values passed to llSitTarget.&lt;br /&gt;
&lt;br /&gt;
// Example output:&lt;br /&gt;
&lt;br /&gt;
// Object: [&amp;lt;0.200000, 0.300000, 0.500000&amp;gt;, &amp;lt;0.100000, 0.150000, 0.120000, 0.976268&amp;gt;] set with llSitTarget on 2 prims.&lt;br /&gt;
// Object: [&amp;lt;0.199999, 0.300001, 0.499999&amp;gt;, &amp;lt;0.100000, 0.150000, 0.120000, 0.976268&amp;gt;] returned by sbGetLinkSitTarget(1).&lt;br /&gt;
// Object: [&amp;lt;0.199998, 0.300002, 0.499998&amp;gt;, &amp;lt;0.100000, 0.150000, 0.120000, 0.976268&amp;gt;] returned by sbGetLinkSitTarget(2).&lt;br /&gt;
&lt;br /&gt;
// GitLocation: tests/sbGetLinkSitTarget_Test.m4s&lt;br /&gt;
&lt;br /&gt;
//----------------------------------------------------------------------------&lt;br /&gt;
//#line &amp;quot;/opt/secondlife/scripts/scripts/tests/sbGetLinkSitTarget_Test.m4s:26&amp;quot;&lt;br /&gt;
vector sitTarget_pos_link = &amp;lt;0.2, 0.3, 0.5&amp;gt;;&lt;br /&gt;
rotation sitTarget_rot_link = &amp;lt;0.1, 0.15, 0.12, 0.9762684&amp;gt;;&lt;br /&gt;
&lt;br /&gt;
//----------------------------------------------------------------------------&lt;br /&gt;
//#line &amp;quot;/opt/secondlife/scripts/scripts/tests/sbGetLinkSitTarget_Test.m4s:31&amp;quot;&lt;br /&gt;
// Returns the correct values to use for llSitTarget to make&lt;br /&gt;
// the currently seated avatar sit in the same way when re-seated.&lt;br /&gt;
// If no avatar is currently sitting then [ZERO_VECTOR, ZERO_ROTATION] is returned.&lt;br /&gt;
//&lt;br /&gt;
// [1] http://wiki.secondlife.com/wiki/User:Timmy_Foxclaw/About_Coordinate_Systems_and_Rotations#LSL_functions&lt;br /&gt;
// [2] http://wiki.secondlife.com/wiki/User:Timmy_Foxclaw/About_Coordinate_Systems_and_Rotations#Converting_between_coordinate_systems&lt;br /&gt;
list sbGetLinkSitTarget(integer link)&lt;br /&gt;
{&lt;br /&gt;
  // Calling llAvatarOnLinkSitTarget(0) always returns NULL_KEY because the link&lt;br /&gt;
  // number of an unlinked prim changes from 0 to 1 as soon as an avatar sits on&lt;br /&gt;
  // it. So if 0 was passed then they probably meant 1.&lt;br /&gt;
  if (link == 0)&lt;br /&gt;
  {&lt;br /&gt;
    link = 1;&lt;br /&gt;
  }&lt;br /&gt;
  key av = llAvatarOnLinkSitTarget(link);&lt;br /&gt;
  if (av != NULL_KEY)&lt;br /&gt;
  {&lt;br /&gt;
    // Get link_pos_oc and link_rot_oc. See table 2 in [1].&lt;br /&gt;
    vector link_pos_oc = ZERO_VECTOR;&lt;br /&gt;
    rotation link_rot_oc = ZERO_ROTATION;&lt;br /&gt;
    if (link &amp;gt; 1)&lt;br /&gt;
    {&lt;br /&gt;
      list params = llGetLinkPrimitiveParams(link, [PRIM_POS_LOCAL, PRIM_ROT_LOCAL]);&lt;br /&gt;
      link_pos_oc = llList2Vector(params, 0);&lt;br /&gt;
      link_rot_oc = llList2Rot(params, 1);&lt;br /&gt;
    }&lt;br /&gt;
    // Find the link number of the seated avatar.&lt;br /&gt;
    integer avNum = llGetNumberOfPrims();&lt;br /&gt;
    do&lt;br /&gt;
    {&lt;br /&gt;
        if (av == llGetLinkKey(avNum))&lt;br /&gt;
        {&lt;br /&gt;
            // Get ac_pos_oc and ac_rot_oc (ac stands for Avatar Center), exactly the same as above&lt;br /&gt;
            // except that we don&#039;t need to test if avNum &amp;gt; 1, because it always will be.&lt;br /&gt;
            list params = llGetLinkPrimitiveParams(avNum, [PRIM_POS_LOCAL, PRIM_ROT_LOCAL]);&lt;br /&gt;
            vector ac_pos_oc = llList2Vector(params, 0);&lt;br /&gt;
            rotation ac_rot_oc = llList2Rot(params, 1);&lt;br /&gt;
&lt;br /&gt;
            // Convert that to link coordinates. See formula (3) in [2].&lt;br /&gt;
            vector ac_pos_link = (ac_pos_oc - link_pos_oc) / link_rot_oc;&lt;br /&gt;
            rotation ac_rot_link = ac_rot_oc / link_rot_oc;&lt;br /&gt;
&lt;br /&gt;
            // Now we have this little vector in the Avatar Center coordinates.&lt;br /&gt;
            vector sit_pos_ac = &amp;lt;0.0, 0.0, 0.05&amp;gt;;&lt;br /&gt;
&lt;br /&gt;
            // Convert that to link coordinates. See formula (1) in [2].&lt;br /&gt;
            vector sit_pos_link = sit_pos_ac * ac_rot_link + ac_pos_link;&lt;br /&gt;
&lt;br /&gt;
            // Return the values, accounting for the sit target bug of 0.4m.&lt;br /&gt;
            return [sit_pos_link - &amp;lt;0.0, 0.0, 0.4&amp;gt;, ac_rot_link];&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    while (--avNum);&lt;br /&gt;
  }&lt;br /&gt;
  return [ZERO_VECTOR, ZERO_ROTATION];&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
setSitTargets()&lt;br /&gt;
{&lt;br /&gt;
  // Set the same sit target on every prim.&lt;br /&gt;
  integer n = llGetNumberOfPrims();&lt;br /&gt;
  llSay(0, &amp;quot;[&amp;quot; +  llList2CSV([sitTarget_pos_link, sitTarget_rot_link]) + &amp;quot;] set with llSitTarget on &amp;quot; + (string)n + &amp;quot; prims.&amp;quot;);&lt;br /&gt;
  do&lt;br /&gt;
  {&lt;br /&gt;
    llLinkSitTarget(n, sitTarget_pos_link, sitTarget_rot_link);&lt;br /&gt;
  }&lt;br /&gt;
  while(--n);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
//----------------------------------------------------------------------------&lt;br /&gt;
//#line &amp;quot;/opt/secondlife/scripts/scripts/tests/sbGetLinkSitTarget_Test.m4s:105&amp;quot;&lt;br /&gt;
default&lt;br /&gt;
{&lt;br /&gt;
  state_entry()&lt;br /&gt;
  {&lt;br /&gt;
    setSitTargets();&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  touch_start(integer n)&lt;br /&gt;
  {&lt;br /&gt;
    setSitTargets();&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  changed(integer change)&lt;br /&gt;
  {&lt;br /&gt;
    if ((change &amp;amp; CHANGED_LINK))&lt;br /&gt;
    {&lt;br /&gt;
      integer n = llGetNumberOfPrims();&lt;br /&gt;
      do&lt;br /&gt;
      {&lt;br /&gt;
        key av = llAvatarOnLinkSitTarget(n);&lt;br /&gt;
        if (av != NULL_KEY)&lt;br /&gt;
        {&lt;br /&gt;
          llSay(0, &amp;quot;[&amp;quot; + llList2CSV(sbGetLinkSitTarget(n)) + &amp;quot;] returned by sbGetLinkSitTarget(&amp;quot; + (string)n + &amp;quot;).&amp;quot;);&lt;br /&gt;
        }&lt;br /&gt;
      }&lt;br /&gt;
      while(--n);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/lsl&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Using llSetLinkPrimitiveParams for skydiving: why limited to 5m in a linked set?==&lt;br /&gt;
llSetLinkPrimitiveParams can be used as a handy tool to adjust an avatar&#039;s position and rotation.&lt;br /&gt;
This works perfectly when the object consists of 1 prim, with a range for setting the avatar position away to 500m easily!&lt;br /&gt;
When there are more prims linked, this offset seems to be limited to 5m (measured with llVecDist). This is an awfull sideeffect!&lt;br /&gt;
&lt;br /&gt;
Put this next script inside a prim and sit on the prim, it will bring you to 1000.0 higher then the prim.&lt;br /&gt;
Next link this prim to another prim and try again. You will notice you are limited to 5m. My Question: why is this limited?&lt;br /&gt;
&amp;lt;lsl&amp;gt;&lt;br /&gt;
// by Randur Source&lt;br /&gt;
&lt;br /&gt;
integer heightcnt = 0;&lt;br /&gt;
list heights = [0.0, 1.0, 5.0, 6.0, 10.0, 100.0, 300.0, 500.0, 800.0, 1000.0];&lt;br /&gt;
&lt;br /&gt;
default&lt;br /&gt;
{&lt;br /&gt;
    state_entry()&lt;br /&gt;
    {&lt;br /&gt;
        llSitTarget(ZERO_VECTOR,ZERO_ROTATION); // Clear the current sittarget for a clear test&lt;br /&gt;
        llSetRot(ZERO_ROTATION); // set the prim to no rotation, for simple z axis movement&lt;br /&gt;
    }&lt;br /&gt;
    &lt;br /&gt;
    changed(integer change)&lt;br /&gt;
    {&lt;br /&gt;
        if (change &amp;amp; CHANGED_LINK) // detect linked prims and avatars&lt;br /&gt;
        {&lt;br /&gt;
            integer primnum = llGetNumberOfPrims(); // the avatar is the last linked prim&lt;br /&gt;
            if (primnum &amp;lt;= 1) // stop if there is only 1 prim&lt;br /&gt;
                return;&lt;br /&gt;
        &lt;br /&gt;
            key avatar = llGetLinkKey(primnum);&lt;br /&gt;
            if (llGetAgentSize(avatar) == ZERO_VECTOR) // stop if this is not an avatar&lt;br /&gt;
                return;&lt;br /&gt;
                &lt;br /&gt;
            // loop through the list of test heights:&lt;br /&gt;
            for (heightcnt = 0; heightcnt &amp;lt; llGetListLength(heights); heightcnt++)&lt;br /&gt;
            {&lt;br /&gt;
                float height = llList2Float(heights,heightcnt);&lt;br /&gt;
                llSetLinkPrimitiveParams(primnum,[PRIM_POSITION,&amp;lt;0.0,0.0,height&amp;gt;]); // set this to the wanted height using a vector z axis&lt;br /&gt;
                &lt;br /&gt;
                vector avatarpos = llList2Vector(llGetObjectDetails(avatar,[OBJECT_POS]),0); // detect the avatar position within the sim&lt;br /&gt;
                float distance = llVecDist(llGetPos(),avatarpos);&lt;br /&gt;
                llOwnerSay(&amp;quot;Attempt to move &amp;quot; + llKey2Name(llGetLinkKey(primnum)) +&lt;br /&gt;
                           &amp;quot; to &amp;quot; + (string)height + &amp;quot;m high resulting to &amp;quot; + (string)distance + &amp;quot;m&amp;quot;);&lt;br /&gt;
                &lt;br /&gt;
                llSleep(1.0);&lt;br /&gt;
            }&lt;br /&gt;
            llUnSit(avatar);&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/lsl&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Posted by Sylvio Runo : Answer &#039;&#039;&#039; :&lt;br /&gt;
The correct limit is 54 meters.&lt;br /&gt;
You can&#039;t move a linked object more than 54 meters away from the axis of the root prim.&lt;br /&gt;
On SecondLife (other grids like OsGrid, may works diferent) when an agent sit on prim, the agent is attached to it, so the agent is a linked prim of the link set.&lt;br /&gt;
&lt;br /&gt;
More information about link rules, you will find here : http://wiki.secondlife.com/wiki/Linkability_Rules [http://wiki.secondlife.com/wiki/Linkability_Rules]&lt;br /&gt;
&lt;br /&gt;
==UpdateSitTarget changes?==&lt;br /&gt;
I recently worked on a project where I used a version of this function, and it appears that it is a little off. A couple of things I noted: the Z-offset of the sit target is 0.35, not 0.4, and the avatar size doesn&#039;t seem to affect this position at all. When I used this function verbatim, I noticed discrepancies between the actual sit target and the set position call. When I changed the script as noted, I got a perfect match. Has the handling of the sit target been changed since this was written? [[User:Talarus Luan|Talarus Luan]] 22:57, 1 July 2009 (UTC)&lt;br /&gt;
:Seconded. I wish I&#039;d looked at this discussion before spending an hour on trying to figure out how the code actually behaved. -- [[User:Tonya Souther|Tonya Souther]] 15:11, 19 August 2009 (UTC)&lt;br /&gt;
&lt;br /&gt;
::This is news to me but I haven&#039;t been in world in ages :( -- &#039;&#039;&#039;[[User:Strife_Onizuka|Strife]]&#039;&#039;&#039; &amp;lt;sup&amp;gt;&amp;lt;small&amp;gt;([[User talk:Strife_Onizuka|talk]]|[[Special:Contributions/Strife_Onizuka|contribs]])&amp;lt;/small&amp;gt;&amp;lt;/sup&amp;gt; 22:56, 20 August 2009 (UTC)&lt;br /&gt;
&lt;br /&gt;
:::From some quick testing in 1.40, this seems to be how the &amp;quot;true&amp;quot; offset is computed:&lt;br /&gt;
:::1. Start with offset as provided by LSL.&lt;br /&gt;
:::2. Add &amp;lt; 0.0 , 0.0 , 0.4 &amp;gt;&lt;br /&gt;
:::3. Subtract llRot2Up( rot ) * 0.05&lt;br /&gt;
:::[[User:Gregory Maurer|--Gregory Maurer]] 20:00, 28 August 2010 (UTC)&lt;br /&gt;
&lt;br /&gt;
::::Confirmed. The following appears to work fine:&lt;br /&gt;
&amp;lt;lsl&amp;gt;llSetLinkPrimitiveParams(linkNum, [PRIM_POS_LOCAL, pos + &amp;lt;0.0, 0.0, 0.4&amp;gt; - (llRot2Up(rot) * 0.05), PRIM_ROT_LOCAL, rot]);&amp;lt;/lsl&amp;gt;&lt;br /&gt;
::::This of course using the new &amp;lt;code&amp;gt;PRIM_POS_LOCAL&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;PRIM_ROT_LOCAL&amp;lt;/code&amp;gt; values for simplicity. If one or two others can confirm that the above code works correctly, then I can splice it into the example.&amp;lt;br/&amp;gt;-- &#039;&#039;&#039;[[User:Haravikk_Mistral|Haravikk]]&#039;&#039;&#039; &amp;lt;sup&amp;gt;&amp;lt;small&amp;gt;([[User_talk:Haravikk_Mistral|talk]]|[[Special:Contributions/Haravikk_Mistral|contribs]])&amp;lt;/small&amp;gt;&amp;lt;/sup&amp;gt; 14:16, 26 December 2011 (PST)&lt;br /&gt;
&lt;br /&gt;
:::::Be sure to test it with avatars of different shapes, and shoe configurations. I recall that being an issue. {{User|Escort DeFarge}} would know about this best. -- &#039;&#039;&#039;[[User:Strife_Onizuka|Strife]]&#039;&#039;&#039; &amp;lt;sup&amp;gt;&amp;lt;small&amp;gt;([[User talk:Strife_Onizuka|talk]]|[[Special:Contributions/Strife_Onizuka|contribs]])&amp;lt;/small&amp;gt;&amp;lt;/sup&amp;gt; 22:05, 26 December 2011 (PST)&lt;br /&gt;
&lt;br /&gt;
::::::I tried with my two main avatar appearances, one average human height and one closer to 8 feet tall, and it didn&#039;t seem to make a difference. The test I used was a simple object with sit-target set, and a menu allowing it to be repositioned, causing the sit-target to move and if an avatar is seated on it, they will be repositioned using &amp;lt;code&amp;gt;llSetLinkPrimitiveParams()&amp;lt;/code&amp;gt; as done above. In my case the position of the avatar was consistent both when sitting on the object (using the sit-target) and being repositioned. Avatar height appears to have no effect, as the sit-target seems to define the avatar&#039;s hip-location, which is seemingly the avatar&#039;s &amp;quot;centre&amp;quot; when seated. I&#039;ll try to run some more tests when I get a chance, as it&#039;s possible this behaviour may not hold true if the object doesn&#039;t have a sit-target on it. The height of the avatar does however have a marked visual impact, depending exactly what you&#039;re trying to line up where, but that&#039;s a general issue with sitting on objects.&amp;lt;br/&amp;gt;-- &#039;&#039;&#039;[[User:Haravikk_Mistral|Haravikk]]&#039;&#039;&#039; &amp;lt;sup&amp;gt;&amp;lt;small&amp;gt;([[User_talk:Haravikk_Mistral|talk]]|[[Special:Contributions/Haravikk_Mistral|contribs]])&amp;lt;/small&amp;gt;&amp;lt;/sup&amp;gt; 05:38, 28 December 2011 (PST)&lt;br /&gt;
:::::::Sorry for my long delay in responding. Due to various RL issues and SL/LL burnout, I took a year off from SL to pursue other activities. That said, it seems to work fine to me, Haravikk; however, I have not done exhaustive testing with tons of different avs, shoes, etc. I would consider going ahead and changing it, because the version as it is right now is not correct for the majority of avatars, regardless. If Escort DeFarge or someone else wants to amend it later to include edge cases, that&#039;s great, but a better base accuracy is more important at this point. In fact, I think I will go ahead and edit it in, since it has been so long anyway.[[User:Talarus Luan|Talarus Luan]] 12:12, 5 July 2013 (PDT)&lt;br /&gt;
:::::::Holding up on the edit, further testing is revealing that if the script is in a prim other than the root, it is off by varying amounts depending on the rotation.[[User:Talarus Luan|Talarus Luan]] 12:39, 5 July 2013 (PDT)&lt;br /&gt;
:::::::OK, I think I found the error. Still need to keep the local position/rotation values for the child prim the script is in, like so:&lt;br /&gt;
&amp;lt;lsl&amp;gt;llSetLinkPrimitiveParams(linkNum, PRIM_POS_LOCAL, (pos + &amp;lt;0.0, 0.0, 0.4&amp;gt; - (llRot2Up(rot) * 0.05)) * localrot + localpos, PRIM_ROT_LOCAL, rot * localrot]);&amp;lt;/lsl&amp;gt;&lt;br /&gt;
:::::::I&#039;ll hold off on the edit until I can get another verify that this code is good.[[User:Talarus Luan|Talarus Luan]] 12:51, 5 July 2013 (PDT)&lt;br /&gt;
:::::::OK. I think I have analyzed this to death today and have come to the conclusion that Strife&#039;s original code is largely correct, but the error I am seeing comes from the &amp;quot;magic constants&amp;quot; 0.4 and 0.02638. Haravikk&#039;s code is simply a reduced form of Strife&#039;s code. The 0.4 magic constant is still there, but Haravikk is using just a close, but fixed, magic constant of 0.05 instead of Strife&#039;s (size.z * 0.02638), which comes out very close to 0.5 for most normal human avs. Thus, I am concluding that the inaccuracy is in the &amp;quot;magic constants&amp;quot; themselves, and I am going to hold off on the edit until I can get some more information on the source of these constants and see if there are better, more accurate values. It is annoying that, in all these years, we still haven&#039;t gotten LL to just tell us what the damn difference is between avatar sit targets and local position offsets in a linkset. It can&#039;t be that hard for someone who is familiar with the code to look at it and document it. -.- [[User:Talarus Luan|Talarus Luan]] 13:24, 5 July 2013 (PDT)&lt;br /&gt;
&lt;br /&gt;
::::::::Welcome back! I&#039;d like to take credit for that but that&#039;s the part that Escort contributed. As to where 0.02638 comes from, I vaguely recall it came from Escort&#039;s testing. I was driven more by &amp;quot;wouldn&#039;t it be cool to write a function that...&amp;quot; than anything else. I do agree the values have always been not quite right. -- &#039;&#039;&#039;[[User:Strife_Onizuka|Strife]]&#039;&#039;&#039; &amp;lt;sup&amp;gt;&amp;lt;small&amp;gt;([[User talk:Strife_Onizuka|talk]]|[[Special:Contributions/Strife_Onizuka|contribs]])&amp;lt;/small&amp;gt;&amp;lt;/sup&amp;gt; 23:10, 5 July 2013 (PDT)&lt;br /&gt;
:::::::::Thanks! OK, I did a bunch of empirical testing, sampling a bunch of avatars from 1.16m to 2.45m in height, as reported by llGetAgentSize. I picked the lowest and highest and one about standard height, and fitted a parabolic curve through them. I have reduced the inaccuracies to a great degree, but it still isn&#039;t 100% perfect for all sizes in that range, just the ones that I used to solve the curve equation. The rest show a *tiny* bit of movement, but they are very close. Obviously, the difference isn&#039;t parabolic, probably just some kind of discrete step function, but it works.[[User:Talarus Luan|Talarus Luan]] 11:16, 14 July 2013 (PDT)&lt;br /&gt;
&amp;lt;lsl&amp;gt;vector vCoefficients = &amp;lt;0.008906,-0.049831,0.088967&amp;gt;;&lt;br /&gt;
float fAdjust = vCoefficients.x * size.z * size.z + vCoefficients.y * size.z + vCoefficients.z;&lt;br /&gt;
llSetLinkPrimitiveParamsFast(linkNum,&lt;br /&gt;
    [PRIM_POS_LOCAL, (pos + &amp;lt;0.0, 0.0, 0.4&amp;gt; - (llRot2Up(rot) * size.z * fAdjust)) * localrot + localpos,&lt;br /&gt;
     PRIM_ROT_LOCAL, rot * localrot]);&amp;lt;/lsl&amp;gt;&lt;br /&gt;
&lt;br /&gt;
::::::::::I see you mind reading abilities haven&#039;t diminished (I contemplated suggesting the tests you have done, decided to go to bed instead). Any reason not to use parentheses? It looks like something that could get optimized to an a series of FMAs (by the VM). -- &#039;&#039;&#039;[[User:Strife_Onizuka|Strife]]&#039;&#039;&#039; &amp;lt;sup&amp;gt;&amp;lt;small&amp;gt;([[User talk:Strife_Onizuka|talk]]|[[Special:Contributions/Strife_Onizuka|contribs]])&amp;lt;/small&amp;gt;&amp;lt;/sup&amp;gt; 21:33, 14 July 2013 (PDT)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;lsl&amp;gt;vector vCoefficients = &amp;lt;0.008906,-0.049831,0.088967&amp;gt;;&lt;br /&gt;
float fAdjust = ((((vCoefficients.x * size.z) + vCoefficients.y) * size.z) + vCoefficients.z) * size.z;&lt;br /&gt;
llSetLinkPrimitiveParamsFast(linkNum,&lt;br /&gt;
    [PRIM_POS_LOCAL, (pos + &amp;lt;0.0, 0.0, 0.4&amp;gt; - (llRot2Up(rot) * fAdjust)) * localrot + localpos,&lt;br /&gt;
     PRIM_ROT_LOCAL, rot * localrot]);&amp;lt;/lsl&amp;gt;&lt;br /&gt;
:::::::::::Yeah, I thought about optimizing it a bit after I posted it, but decided to leave it unoptimized here so the path from the current function to this change was clear, for demonstrability purposes. Besides, I had to leave some room for it to be Strifed&amp;amp;trade;. :P [[User:Talarus Luan|Talarus Luan]] 15:17, 17 July 2013 (PDT)&lt;br /&gt;
&lt;br /&gt;
::::::::::::I appreciate the gesture :p and I&#039;m not as bad as I use to be. I&#039;m not going to optimize out fAdjust, it&#039;s more readable this way. This is more for myself later as my memory is crap, the reasoning behind using llRot2Up is that it solves the pesky problem of the quaternion not having a magnitude of one. While the following isn&#039;t optimal, it is cool. -- &#039;&#039;&#039;[[User:Strife_Onizuka|Strife]]&#039;&#039;&#039; &amp;lt;sup&amp;gt;&amp;lt;small&amp;gt;([[User talk:Strife_Onizuka|talk]]|[[Special:Contributions/Strife_Onizuka|contribs]])&amp;lt;/small&amp;gt;&amp;lt;/sup&amp;gt; 00:00, 18 July 2013 (PDT)&lt;br /&gt;
&amp;lt;lsl&amp;gt;&lt;br /&gt;
size.x = (size.z * (size.y = (size.z * size.z)));&lt;br /&gt;
float fAdjust = vCoefficients * size;&lt;br /&gt;
&amp;lt;/lsl&amp;gt;&lt;br /&gt;
:::::::::::::Yeah, that is a nice way to represent it, for those used to the LSL representation for vector dot product. I&#039;m a little less enthused about the size vector assignment chain, but that&#039;s just my general dislike for C value assignments and such. In my mind, I separate assignments from expressions, so seeing them mixed together causes a bit of a train wreck in my brain&#039;s lexical analyzer. :P[[User:Talarus Luan|Talarus Luan]] 10:00, 21 July 2013 (PDT)&lt;br /&gt;
&lt;br /&gt;
::::::::::::::I don&#039;t think anyone uses the LSL vector dot product. It took me three days to remember it existed and then I look up the syntax just to make sure I wasn&#039;t crazy (yes yes, I agree it&#039;s insane to think that looking up the syntax of an obscure feature is proof against insanity but I&#039;m sticking to it, my cat agrees). I think a train wreck was my goal. -- &#039;&#039;&#039;[[User:Strife_Onizuka|Strife]]&#039;&#039;&#039; &amp;lt;sup&amp;gt;&amp;lt;small&amp;gt;([[User talk:Strife_Onizuka|talk]]|[[Special:Contributions/Strife_Onizuka|contribs]])&amp;lt;/small&amp;gt;&amp;lt;/sup&amp;gt; 11:13, 21 July 2013 (PDT)&lt;br /&gt;
&lt;br /&gt;
== Avatars Floating After Sit ==&lt;br /&gt;
&lt;br /&gt;
The position of avatars will sometimes change, generally noticeable as a rise on the Z axis of perhaps half a meter - common triggers for this is typing or another AV sitting on the same object - though these are not exhaustive.  Does anyone have a clue why this happens, and how to prevent it from happening? [[User:TaraLi Jie|TaraLi Jie]] 21:14, 11 March 2012 (PDT)&lt;br /&gt;
&lt;br /&gt;
:Hmm, there are a few possible causes, but the main cause are the animations involved, so it&#039;s worth remembering that any animation overrider can potentially cause weirdness while on a sit-target, which is why most good ones can turn themselves off while seated. It&#039;s a bit difficult to describe specific problems with animations, but I think that sometimes it can be caused by animations that have a weird first frame, since it&#039;s used to calculate all the offsets etc. for the rest of the animation; normally this will be a neutral pose since you don&#039;t actually see it in the animation, but if it&#039;s something odd then it can mess with positioning. -- &amp;lt;br/&amp;gt;-- &#039;&#039;&#039;[[User:Haravikk_Mistral|Haravikk]]&#039;&#039;&#039; &amp;lt;sup&amp;gt;&amp;lt;small&amp;gt;([[User_talk:Haravikk_Mistral|talk]]|[[Special:Contributions/Haravikk_Mistral|contribs]])&amp;lt;/small&amp;gt;&amp;lt;/sup&amp;gt; 05:34, 12 March 2012 (PDT)&lt;br /&gt;
&lt;br /&gt;
::When I&#039;ve had problems with this, the root cause has usually been that I&#039;ve (or something has) inadvertently stopped an animation that&#039;s holding the avatar in place before starting another one.   Because animations are all made differently, neither the animator with whom I work most of the time nor I have ever managed to figure out exactly what to avoid, but certainly when it happens to me, I always start debugging by looking very carefully at where I&#039;m turning animations off and considering whether, in fact, I need to turn them off at all.   Quite often, I find that simply turning off the default sit animation when my first animation starts, and then keeping the first animation going throughout, starting and stopping other ones over it, as necessary, solves the problem.&lt;br /&gt;
&lt;br /&gt;
::One &amp;quot;gotcha&amp;quot; is that stopping an animation and then immediately restarting it doesn&#039;t work.  It confuses the viewer something horrible, and often leads to people floating in mid-air.  [[User:Innula Zenovka|Innula Zenovka]] 09:04, 12 March 2012 (PDT)&lt;br /&gt;
&lt;br /&gt;
== Sit Target 0.4m &#039;bug&#039; ==&lt;br /&gt;
The notes say &lt;br /&gt;
&amp;quot;rot affects the position of the sit-target in a buggy way way.&lt;br /&gt;
To correct for the rot bug, simply subtract &amp;lt;0,0,0.4&amp;gt; from the position when rot is zero. See example below.&amp;quot;&lt;br /&gt;
&lt;br /&gt;
But the example script adjusts z by 0.4m when rotation is NOT zero.&lt;br /&gt;
&amp;lt;lsl&amp;gt;&lt;br /&gt;
if (rot!=ZERO_ROTATION) pos -=&amp;lt;0,0,0.4&amp;gt;;  //here is the work around&lt;br /&gt;
&amp;lt;/lsl&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Which should it be?&lt;br /&gt;
&lt;br /&gt;
I&#039;ve just been doing some tests without any 0.4m adjustment, and I am unable to observe any difference in my z position whether rotation is zero or not. Has something changed? If so, wouldn&#039;t the change screw up some furniture?&lt;br /&gt;
[[User:Omei Qunhua|Omei Qunhua]] 14:09, 16 March 2014 (PDT)&lt;br /&gt;
&lt;br /&gt;
:You are right, there shouldn&#039;t be a test there. My understanding is that you always need to subtract 0.4 from z. Changing it would screw up furniture. -- &#039;&#039;&#039;[[User:Strife_Onizuka|Strife]]&#039;&#039;&#039; &amp;lt;sup&amp;gt;&amp;lt;small&amp;gt;([[User talk:Strife_Onizuka|talk]]|[[Special:Contributions/Strife_Onizuka|contribs]])&amp;lt;/small&amp;gt;&amp;lt;/sup&amp;gt; 21:02, 16 March 2014 (PDT)&lt;/div&gt;</summary>
		<author><name>Timmy Foxclaw</name></author>
	</entry>
	<entry>
		<id>https://wiki.secondlife.com/w/index.php?title=Talk:LlSitTarget&amp;diff=1189256</id>
		<title>Talk:LlSitTarget</title>
		<link rel="alternate" type="text/html" href="https://wiki.secondlife.com/w/index.php?title=Talk:LlSitTarget&amp;diff=1189256"/>
		<updated>2014-04-07T17:41:56Z</updated>

		<summary type="html">&lt;p&gt;Timmy Foxclaw: /* GetSitTarget */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Unsitting on wrong side or camera rotation ==&lt;br /&gt;
&lt;br /&gt;
Hi, i am getting frustrated with this. I create a board and set the sit target with&lt;br /&gt;
&amp;lt;code&amp;gt;llSitTarget(&amp;lt;0.4, 0.0, 0.0&amp;gt;, ZERO_ROTATION);&amp;lt;/code&amp;gt;&lt;br /&gt;
and an animation which for &amp;quot;standing&amp;quot;. So while the person technical sits, she stands in front of the board. &lt;br /&gt;
But I have a problem with that: If the board stand freely, the person unsits right through it towards the other side. I can put the board with the back  facing a large wall. In the case the unsitting is correctly in front of it. But on sit down the camera rotates, so that it is behind the avatar again; on the other side of the wall.&lt;br /&gt;
&lt;br /&gt;
If anyone has an idea how to fix, please tell me (even if it is just an idea where to look for more information). --[[User:Maike Short|Maike Short]] 12:41, 24 February 2008 (PST)&lt;br /&gt;
&lt;br /&gt;
:You could position the camera with the {{LSLGC|Camera}} functions.  -- [[User:Strife Onizuka|Strife Onizuka]] 04:46, 25 February 2008 (PST)&lt;br /&gt;
&lt;br /&gt;
==GetSitTarget==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;lsl&amp;gt;&lt;br /&gt;
list GetSitTarget(integer prim, key av)&lt;br /&gt;
{//WARNING: llGetObjectDetails can introduce an error that goes as far as the 5th decimal place.&lt;br /&gt;
    vector tp = llGetAgentSize(av);&lt;br /&gt;
    if(tp)&lt;br /&gt;
    {&lt;br /&gt;
        if(prim == LINK_THIS)//llGetLinkKey doesn&#039;t like LINK_THIS&lt;br /&gt;
            prim = llGetLinkNumber();&lt;br /&gt;
    &lt;br /&gt;
        list details = OBJECT_POS + (list)OBJECT_ROT;&lt;br /&gt;
        rotation f = llList2Rot(details = (llGetObjectDetails(llGetLinkKey(prim), details) + llGetObjectDetails(av, details)), 1);&lt;br /&gt;
    &lt;br /&gt;
        return [(llRot2Up(f = (llList2Rot(details, 3) / f)) * tp.z * 0.02638) +&lt;br /&gt;
                ((llList2Vector(details, 2) - llList2Vector(details, 0)) / f) - &amp;lt;0.0, 0.0, 0.4&amp;gt;, f];&lt;br /&gt;
    }&lt;br /&gt;
    return [];&lt;br /&gt;
}//Written by Strife Onizuka&lt;br /&gt;
&amp;lt;/lsl&amp;gt;&lt;br /&gt;
Hi Strife! This version of your GetSitTarget, and the other version on the actual LlSitTarget page, both always return &amp;lt;0.000000, 0.000000, 0.707107, 0.707107&amp;gt; for the rotation. --[[User:MartinRJ Fayray|MartinRJ Fayray]] 07:52, 21 January 2013 (PST)&lt;br /&gt;
&lt;br /&gt;
:I haven&#039;t touched this in 5 years but I don&#039;t see a reason why it should be doing what you say. Are you sure you are using it properly? The prim parameter specifies what prim the location will be local to. The function was written to aid in determining sit targets when making furniture. You have the avatar sit on one object and then you get it&#039;s position local to the furniture so you can program in the sit target.&lt;br /&gt;
&lt;br /&gt;
:Just to clarify, you are saying that when you sit on an object with the following script in it, you don&#039;t get approximately the specified value? -- &#039;&#039;&#039;[[User:Strife_Onizuka|Strife]]&#039;&#039;&#039; &amp;lt;sup&amp;gt;&amp;lt;small&amp;gt;([[User talk:Strife_Onizuka|talk]]|[[Special:Contributions/Strife_Onizuka|contribs]])&amp;lt;/small&amp;gt;&amp;lt;/sup&amp;gt; 20:37, 22 January 2013 (PST)&lt;br /&gt;
&lt;br /&gt;
:It seems to work now. No idea what I was doing wrong. Thank you strife!--[[User:MartinRJ Fayray|MartinRJ Fayray]] 07:36, 3 February 2013 (PST)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;lsl&amp;gt;&lt;br /&gt;
vector vOffset = &amp;lt;0,0,1&amp;gt;;&lt;br /&gt;
rotation rOffset = &amp;lt;0,0,0,1&amp;gt;;&lt;br /&gt;
&lt;br /&gt;
list GetSitTarget(integer prim, key av)&lt;br /&gt;
{//WARNING: llGetObjectDetails can introduce an error that goes as far as the 5th decimal place!&lt;br /&gt;
 //This is highly unlikely to be ever noticed unless compounded over time.&lt;br /&gt;
 //Do not use while moving (like in a moving vehicle)!!!&lt;br /&gt;
    vector tp = llGetAgentSize(av);&lt;br /&gt;
    if(tp)&lt;br /&gt;
    {&lt;br /&gt;
        if(prim == LINK_THIS)//llGetLinkKey doesn&#039;t like LINK_THIS&lt;br /&gt;
            prim = llGetLinkNumber();&lt;br /&gt;
 &lt;br /&gt;
        list details = [OBJECT_POS, OBJECT_ROT];&lt;br /&gt;
        rotation f = llList2Rot(details = (llGetObjectDetails(llGetLinkKey(prim), details) + llGetObjectDetails(av, details)), 1);&lt;br /&gt;
        rotation r = llList2Rot(details, 3) / f;&lt;br /&gt;
 &lt;br /&gt;
        return [((llList2Vector(details, 2) - llList2Vector(details, 0)) / f) + (llRot2Up(r) * tp.z * 0.02638) - &amp;lt;0.0, 0.0, 0.4&amp;gt;, r];&lt;br /&gt;
    }&lt;br /&gt;
    return [];&lt;br /&gt;
}//Written by Strife Onizuka&lt;br /&gt;
&lt;br /&gt;
default{&lt;br /&gt;
    state_entry(){&lt;br /&gt;
        llSitTarget(vOffset, rOffset);&lt;br /&gt;
    }&lt;br /&gt;
    changed(integer change){&lt;br /&gt;
        key id = llAvatarOnSitTarget();&lt;br /&gt;
        if(id)&lt;br /&gt;
            llOwnerSay(&amp;quot;[&amp;quot;+llList2CSV([vOffset, rOffset]) +&amp;quot;] ~ [&amp;quot; + llList2CSV(GetSitTarget(LINK_THIS, id))+&amp;quot;]&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/lsl&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Note&#039;&#039;&#039;: the above two scripts in this paragraph are incorrect. Most notably, the position of an avatar (it&#039;s Avatar Center) is NOT dependent on the AgentSize of the seated avatar. I added another script that returns the sit target below. [[User:Timmy Foxclaw|Timmy Foxclaw]] 10:31, 7 April 2014 (PDT)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;lsl&amp;gt;&lt;br /&gt;
// A script to develop and test sbGetLinkSitTarget&lt;br /&gt;
//&lt;br /&gt;
// Copyright(c) Timmy Songbird @DreamNation&lt;br /&gt;
//              Timmy Foxclaw  @SL,&lt;br /&gt;
//              2014&lt;br /&gt;
//&lt;br /&gt;
// This program is free software; you can redistribute it and/or modify&lt;br /&gt;
// it under the terms of the GNU General Public License as published by&lt;br /&gt;
// the Free Software Foundation; either version 2 of the License, or&lt;br /&gt;
// (at your option) any later version.&lt;br /&gt;
//&lt;br /&gt;
// This program is distributed in the hope that it will be useful,&lt;br /&gt;
// but WITHOUT ANY WARRANTY; without even the implied warranty of&lt;br /&gt;
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the&lt;br /&gt;
// GNU General Public License for more details.&lt;br /&gt;
//&lt;br /&gt;
// You should have received a copy of the GNU General Public License&lt;br /&gt;
// along with this program; if not, write to the Free Software&lt;br /&gt;
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307, USA.&#039;)&lt;br /&gt;
&lt;br /&gt;
//----------------------------------------------------------------------------&lt;br /&gt;
//#line &amp;quot;/opt/secondlife/scripts/scripts/tests/sbGetLinkSitTarget_Test.m4s:4&amp;quot;&lt;br /&gt;
// This script sets a &amp;quot;random&amp;quot;-ish sit target on every prim in an object.&lt;br /&gt;
// Recommended for your test is an object existing of two default cubes&lt;br /&gt;
// with arbitrary rotations and position. Put this script only in the&lt;br /&gt;
// root prim.&lt;br /&gt;
//&lt;br /&gt;
// The script sets the sit targets on compile or touch. Please touch&lt;br /&gt;
// the object after editting one of the prims.&lt;br /&gt;
//&lt;br /&gt;
// When an avatar (un)sits on one of the prims, the script prints for every&lt;br /&gt;
// sit target that has a seated avatar the return value of sbGetLinkSitTarget.&lt;br /&gt;
// This value should be (almost) equal to the values passed to llSitTarget.&lt;br /&gt;
&lt;br /&gt;
// Example output:&lt;br /&gt;
&lt;br /&gt;
// Object: [&amp;lt;0.200000, 0.300000, 0.500000&amp;gt;, &amp;lt;0.100000, 0.150000, 0.120000, 0.976268&amp;gt;] set with llSitTarget on 2 prims.&lt;br /&gt;
// Object: [&amp;lt;0.199999, 0.300001, 0.499999&amp;gt;, &amp;lt;0.100000, 0.150000, 0.120000, 0.976268&amp;gt;] returned by sbGetLinkSitTarget(1).&lt;br /&gt;
// Object: [&amp;lt;0.199998, 0.300002, 0.499998&amp;gt;, &amp;lt;0.100000, 0.150000, 0.120000, 0.976268&amp;gt;] returned by sbGetLinkSitTarget(2).&lt;br /&gt;
&lt;br /&gt;
// GitLocation: tests/sbGetLinkSitTarget_Test.m4s&lt;br /&gt;
&lt;br /&gt;
//----------------------------------------------------------------------------&lt;br /&gt;
//#line &amp;quot;/opt/secondlife/scripts/scripts/tests/sbGetLinkSitTarget_Test.m4s:26&amp;quot;&lt;br /&gt;
vector sitTarget_pos_link = &amp;lt;0.2, 0.3, 0.5&amp;gt;;&lt;br /&gt;
rotation sitTarget_rot_link = &amp;lt;0.1, 0.15, 0.12, 0.9762684&amp;gt;;&lt;br /&gt;
&lt;br /&gt;
//----------------------------------------------------------------------------&lt;br /&gt;
//#line &amp;quot;/opt/secondlife/scripts/scripts/tests/sbGetLinkSitTarget_Test.m4s:31&amp;quot;&lt;br /&gt;
// Returns the correct values to use for llSitTarget to make&lt;br /&gt;
// the currently seated avatar sit in the same way when re-seated.&lt;br /&gt;
// If no avatar is currently sitting then [ZERO_VECTOR, ZERO_ROTATION] is returned.&lt;br /&gt;
//&lt;br /&gt;
// [1] http://wiki.secondlife.com/wiki/User:Timmy_Foxclaw/About_Coordinate_Systems_and_Rotations#LSL_functions&lt;br /&gt;
// [2] http://wiki.secondlife.com/wiki/User:Timmy_Foxclaw/About_Coordinate_Systems_and_Rotations#Converting_between_coordinate_systems&lt;br /&gt;
list sbGetLinkSitTarget(integer link)&lt;br /&gt;
{&lt;br /&gt;
  // Calling llAvatarOnLinkSitTarget(0) always returns NULL_KEY because the link&lt;br /&gt;
  // number of an unlinked prim changes from 0 to 1 as soon as an avatar sits on&lt;br /&gt;
  // it. So if 0 was passed then they probably meant 1.&lt;br /&gt;
  if (link == 0)&lt;br /&gt;
  {&lt;br /&gt;
    link = 1;&lt;br /&gt;
  }&lt;br /&gt;
  key av = llAvatarOnLinkSitTarget(link);&lt;br /&gt;
  if (av != NULL_KEY)&lt;br /&gt;
  {&lt;br /&gt;
    // Get link_pos_oc and link_rot_oc. See table 2 in [1].&lt;br /&gt;
    vector link_pos_oc = ZERO_VECTOR;&lt;br /&gt;
    rotation link_rot_oc = ZERO_ROTATION;&lt;br /&gt;
    if (link &amp;gt; 1)&lt;br /&gt;
    {&lt;br /&gt;
      list params = llGetLinkPrimitiveParams(link, [PRIM_POS_LOCAL, PRIM_ROT_LOCAL]);&lt;br /&gt;
      link_pos_oc = llList2Vector(params, 0);&lt;br /&gt;
      link_rot_oc = llList2Rot(params, 1);&lt;br /&gt;
    }&lt;br /&gt;
    // Find the link number of the seated avatar.&lt;br /&gt;
    integer avNum = llGetNumberOfPrims();&lt;br /&gt;
    do&lt;br /&gt;
    {&lt;br /&gt;
        if (av == llGetLinkKey(avNum))&lt;br /&gt;
        {&lt;br /&gt;
            // Get ac_pos_oc and ac_rot_oc (ac stands for Avatar Center), exactly the same as above&lt;br /&gt;
            // except that we don&#039;t need to test if avNum &amp;gt; 1, because it always will be.&lt;br /&gt;
            list params = llGetLinkPrimitiveParams(avNum, [PRIM_POS_LOCAL, PRIM_ROT_LOCAL]);&lt;br /&gt;
            vector ac_pos_oc = llList2Vector(params, 0);&lt;br /&gt;
            rotation ac_rot_oc = llList2Rot(params, 1);&lt;br /&gt;
&lt;br /&gt;
            // Convert that to link coordinates. See formula (3) in [2].&lt;br /&gt;
            vector ac_pos_link = (ac_pos_oc - link_pos_oc) / link_rot_oc;&lt;br /&gt;
            rotation ac_rot_link = ac_rot_oc / link_rot_oc;&lt;br /&gt;
&lt;br /&gt;
            // Now we have this little vector in the Avatar Center coordinates.&lt;br /&gt;
            vector sit_pos_ac = &amp;lt;0.0, 0.0, 0.05&amp;gt;;&lt;br /&gt;
&lt;br /&gt;
            // Convert that to link coordinates. See formula (1) in [2].&lt;br /&gt;
            vector sit_pos_link = sit_pos_ac * ac_rot_link + ac_pos_link;&lt;br /&gt;
&lt;br /&gt;
            // Return the values, accounting for the sit target bug of 0.4m.&lt;br /&gt;
            return [sit_pos_link - &amp;lt;0.0, 0.0, 0.4&amp;gt;, ac_rot_link];&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    while (--avNum);&lt;br /&gt;
  }&lt;br /&gt;
  return [ZERO_VECTOR, ZERO_ROTATION];&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
setSitTargets()&lt;br /&gt;
{&lt;br /&gt;
  // Set the same sit target on every prim.&lt;br /&gt;
  integer n = llGetNumberOfPrims();&lt;br /&gt;
  llSay(0, &amp;quot;[&amp;quot; +  llList2CSV([sitTarget_pos_link, sitTarget_rot_link]) + &amp;quot;] set with llSitTarget on &amp;quot; + (string)n + &amp;quot; prims.&amp;quot;);&lt;br /&gt;
  do&lt;br /&gt;
  {&lt;br /&gt;
    llLinkSitTarget(n, sitTarget_pos_link, sitTarget_rot_link);&lt;br /&gt;
  }&lt;br /&gt;
  while(--n);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
//----------------------------------------------------------------------------&lt;br /&gt;
//#line &amp;quot;/opt/secondlife/scripts/scripts/tests/sbGetLinkSitTarget_Test.m4s:105&amp;quot;&lt;br /&gt;
default&lt;br /&gt;
{&lt;br /&gt;
  state_entry()&lt;br /&gt;
  {&lt;br /&gt;
    setSitTargets();&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  touch_start(integer n)&lt;br /&gt;
  {&lt;br /&gt;
    setSitTargets();&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  changed(integer change)&lt;br /&gt;
  {&lt;br /&gt;
    if ((change &amp;amp; CHANGED_LINK))&lt;br /&gt;
    {&lt;br /&gt;
      integer n = llGetNumberOfPrims();&lt;br /&gt;
      do&lt;br /&gt;
      {&lt;br /&gt;
        key av = llAvatarOnLinkSitTarget(n);&lt;br /&gt;
        if (av != NULL_KEY)&lt;br /&gt;
        {&lt;br /&gt;
          llSay(0, &amp;quot;[&amp;quot; + llList2CSV(sbGetLinkSitTarget(n)) + &amp;quot;] returned by sbGetLinkSitTarget(&amp;quot; + (string)n + &amp;quot;).&amp;quot;);&lt;br /&gt;
        }&lt;br /&gt;
      }&lt;br /&gt;
      while(--n);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/lsl&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Using llSetLinkPrimitiveParams for skydiving: why limited to 5m in a linked set?==&lt;br /&gt;
llSetLinkPrimitiveParams can be used as a handy tool to adjust an avatar&#039;s position and rotation.&lt;br /&gt;
This works perfectly when the object consists of 1 prim, with a range for setting the avatar position away to 500m easily!&lt;br /&gt;
When there are more prims linked, this offset seems to be limited to 5m (measured with llVecDist). This is an awfull sideeffect!&lt;br /&gt;
&lt;br /&gt;
Put this next script inside a prim and sit on the prim, it will bring you to 1000.0 higher then the prim.&lt;br /&gt;
Next link this prim to another prim and try again. You will notice you are limited to 5m. My Question: why is this limited?&lt;br /&gt;
&amp;lt;lsl&amp;gt;&lt;br /&gt;
// by Randur Source&lt;br /&gt;
&lt;br /&gt;
integer heightcnt = 0;&lt;br /&gt;
list heights = [0.0, 1.0, 5.0, 6.0, 10.0, 100.0, 300.0, 500.0, 800.0, 1000.0];&lt;br /&gt;
&lt;br /&gt;
default&lt;br /&gt;
{&lt;br /&gt;
    state_entry()&lt;br /&gt;
    {&lt;br /&gt;
        llSitTarget(ZERO_VECTOR,ZERO_ROTATION); // Clear the current sittarget for a clear test&lt;br /&gt;
        llSetRot(ZERO_ROTATION); // set the prim to no rotation, for simple z axis movement&lt;br /&gt;
    }&lt;br /&gt;
    &lt;br /&gt;
    changed(integer change)&lt;br /&gt;
    {&lt;br /&gt;
        if (change &amp;amp; CHANGED_LINK) // detect linked prims and avatars&lt;br /&gt;
        {&lt;br /&gt;
            integer primnum = llGetNumberOfPrims(); // the avatar is the last linked prim&lt;br /&gt;
            if (primnum &amp;lt;= 1) // stop if there is only 1 prim&lt;br /&gt;
                return;&lt;br /&gt;
        &lt;br /&gt;
            key avatar = llGetLinkKey(primnum);&lt;br /&gt;
            if (llGetAgentSize(avatar) == ZERO_VECTOR) // stop if this is not an avatar&lt;br /&gt;
                return;&lt;br /&gt;
                &lt;br /&gt;
            // loop through the list of test heights:&lt;br /&gt;
            for (heightcnt = 0; heightcnt &amp;lt; llGetListLength(heights); heightcnt++)&lt;br /&gt;
            {&lt;br /&gt;
                float height = llList2Float(heights,heightcnt);&lt;br /&gt;
                llSetLinkPrimitiveParams(primnum,[PRIM_POSITION,&amp;lt;0.0,0.0,height&amp;gt;]); // set this to the wanted height using a vector z axis&lt;br /&gt;
                &lt;br /&gt;
                vector avatarpos = llList2Vector(llGetObjectDetails(avatar,[OBJECT_POS]),0); // detect the avatar position within the sim&lt;br /&gt;
                float distance = llVecDist(llGetPos(),avatarpos);&lt;br /&gt;
                llOwnerSay(&amp;quot;Attempt to move &amp;quot; + llKey2Name(llGetLinkKey(primnum)) +&lt;br /&gt;
                           &amp;quot; to &amp;quot; + (string)height + &amp;quot;m high resulting to &amp;quot; + (string)distance + &amp;quot;m&amp;quot;);&lt;br /&gt;
                &lt;br /&gt;
                llSleep(1.0);&lt;br /&gt;
            }&lt;br /&gt;
            llUnSit(avatar);&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/lsl&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Posted by Sylvio Runo : Answer &#039;&#039;&#039; :&lt;br /&gt;
The correct limit is 54 meters.&lt;br /&gt;
You can&#039;t move a linked object more than 54 meters away from the axis of the root prim.&lt;br /&gt;
On SecondLife (other grids like OsGrid, may works diferent) when an agent sit on prim, the agent is attached to it, so the agent is a linked prim of the link set.&lt;br /&gt;
&lt;br /&gt;
More information about link rules, you will find here : http://wiki.secondlife.com/wiki/Linkability_Rules [http://wiki.secondlife.com/wiki/Linkability_Rules]&lt;br /&gt;
&lt;br /&gt;
==UpdateSitTarget changes?==&lt;br /&gt;
I recently worked on a project where I used a version of this function, and it appears that it is a little off. A couple of things I noted: the Z-offset of the sit target is 0.35, not 0.4, and the avatar size doesn&#039;t seem to affect this position at all. When I used this function verbatim, I noticed discrepancies between the actual sit target and the set position call. When I changed the script as noted, I got a perfect match. Has the handling of the sit target been changed since this was written? [[User:Talarus Luan|Talarus Luan]] 22:57, 1 July 2009 (UTC)&lt;br /&gt;
:Seconded. I wish I&#039;d looked at this discussion before spending an hour on trying to figure out how the code actually behaved. -- [[User:Tonya Souther|Tonya Souther]] 15:11, 19 August 2009 (UTC)&lt;br /&gt;
&lt;br /&gt;
::This is news to me but I haven&#039;t been in world in ages :( -- &#039;&#039;&#039;[[User:Strife_Onizuka|Strife]]&#039;&#039;&#039; &amp;lt;sup&amp;gt;&amp;lt;small&amp;gt;([[User talk:Strife_Onizuka|talk]]|[[Special:Contributions/Strife_Onizuka|contribs]])&amp;lt;/small&amp;gt;&amp;lt;/sup&amp;gt; 22:56, 20 August 2009 (UTC)&lt;br /&gt;
&lt;br /&gt;
:::From some quick testing in 1.40, this seems to be how the &amp;quot;true&amp;quot; offset is computed:&lt;br /&gt;
:::1. Start with offset as provided by LSL.&lt;br /&gt;
:::2. Add &amp;lt; 0.0 , 0.0 , 0.4 &amp;gt;&lt;br /&gt;
:::3. Subtract llRot2Up( rot ) * 0.05&lt;br /&gt;
:::[[User:Gregory Maurer|--Gregory Maurer]] 20:00, 28 August 2010 (UTC)&lt;br /&gt;
&lt;br /&gt;
::::Confirmed. The following appears to work fine:&lt;br /&gt;
&amp;lt;lsl&amp;gt;llSetLinkPrimitiveParams(linkNum, [PRIM_POS_LOCAL, pos + &amp;lt;0.0, 0.0, 0.4&amp;gt; - (llRot2Up(rot) * 0.05), PRIM_ROT_LOCAL, rot]);&amp;lt;/lsl&amp;gt;&lt;br /&gt;
::::This of course using the new &amp;lt;code&amp;gt;PRIM_POS_LOCAL&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;PRIM_ROT_LOCAL&amp;lt;/code&amp;gt; values for simplicity. If one or two others can confirm that the above code works correctly, then I can splice it into the example.&amp;lt;br/&amp;gt;-- &#039;&#039;&#039;[[User:Haravikk_Mistral|Haravikk]]&#039;&#039;&#039; &amp;lt;sup&amp;gt;&amp;lt;small&amp;gt;([[User_talk:Haravikk_Mistral|talk]]|[[Special:Contributions/Haravikk_Mistral|contribs]])&amp;lt;/small&amp;gt;&amp;lt;/sup&amp;gt; 14:16, 26 December 2011 (PST)&lt;br /&gt;
&lt;br /&gt;
:::::Be sure to test it with avatars of different shapes, and shoe configurations. I recall that being an issue. {{User|Escort DeFarge}} would know about this best. -- &#039;&#039;&#039;[[User:Strife_Onizuka|Strife]]&#039;&#039;&#039; &amp;lt;sup&amp;gt;&amp;lt;small&amp;gt;([[User talk:Strife_Onizuka|talk]]|[[Special:Contributions/Strife_Onizuka|contribs]])&amp;lt;/small&amp;gt;&amp;lt;/sup&amp;gt; 22:05, 26 December 2011 (PST)&lt;br /&gt;
&lt;br /&gt;
::::::I tried with my two main avatar appearances, one average human height and one closer to 8 feet tall, and it didn&#039;t seem to make a difference. The test I used was a simple object with sit-target set, and a menu allowing it to be repositioned, causing the sit-target to move and if an avatar is seated on it, they will be repositioned using &amp;lt;code&amp;gt;llSetLinkPrimitiveParams()&amp;lt;/code&amp;gt; as done above. In my case the position of the avatar was consistent both when sitting on the object (using the sit-target) and being repositioned. Avatar height appears to have no effect, as the sit-target seems to define the avatar&#039;s hip-location, which is seemingly the avatar&#039;s &amp;quot;centre&amp;quot; when seated. I&#039;ll try to run some more tests when I get a chance, as it&#039;s possible this behaviour may not hold true if the object doesn&#039;t have a sit-target on it. The height of the avatar does however have a marked visual impact, depending exactly what you&#039;re trying to line up where, but that&#039;s a general issue with sitting on objects.&amp;lt;br/&amp;gt;-- &#039;&#039;&#039;[[User:Haravikk_Mistral|Haravikk]]&#039;&#039;&#039; &amp;lt;sup&amp;gt;&amp;lt;small&amp;gt;([[User_talk:Haravikk_Mistral|talk]]|[[Special:Contributions/Haravikk_Mistral|contribs]])&amp;lt;/small&amp;gt;&amp;lt;/sup&amp;gt; 05:38, 28 December 2011 (PST)&lt;br /&gt;
:::::::Sorry for my long delay in responding. Due to various RL issues and SL/LL burnout, I took a year off from SL to pursue other activities. That said, it seems to work fine to me, Haravikk; however, I have not done exhaustive testing with tons of different avs, shoes, etc. I would consider going ahead and changing it, because the version as it is right now is not correct for the majority of avatars, regardless. If Escort DeFarge or someone else wants to amend it later to include edge cases, that&#039;s great, but a better base accuracy is more important at this point. In fact, I think I will go ahead and edit it in, since it has been so long anyway.[[User:Talarus Luan|Talarus Luan]] 12:12, 5 July 2013 (PDT)&lt;br /&gt;
:::::::Holding up on the edit, further testing is revealing that if the script is in a prim other than the root, it is off by varying amounts depending on the rotation.[[User:Talarus Luan|Talarus Luan]] 12:39, 5 July 2013 (PDT)&lt;br /&gt;
:::::::OK, I think I found the error. Still need to keep the local position/rotation values for the child prim the script is in, like so:&lt;br /&gt;
&amp;lt;lsl&amp;gt;llSetLinkPrimitiveParams(linkNum, PRIM_POS_LOCAL, (pos + &amp;lt;0.0, 0.0, 0.4&amp;gt; - (llRot2Up(rot) * 0.05)) * localrot + localpos, PRIM_ROT_LOCAL, rot * localrot]);&amp;lt;/lsl&amp;gt;&lt;br /&gt;
:::::::I&#039;ll hold off on the edit until I can get another verify that this code is good.[[User:Talarus Luan|Talarus Luan]] 12:51, 5 July 2013 (PDT)&lt;br /&gt;
:::::::OK. I think I have analyzed this to death today and have come to the conclusion that Strife&#039;s original code is largely correct, but the error I am seeing comes from the &amp;quot;magic constants&amp;quot; 0.4 and 0.02638. Haravikk&#039;s code is simply a reduced form of Strife&#039;s code. The 0.4 magic constant is still there, but Haravikk is using just a close, but fixed, magic constant of 0.05 instead of Strife&#039;s (size.z * 0.02638), which comes out very close to 0.5 for most normal human avs. Thus, I am concluding that the inaccuracy is in the &amp;quot;magic constants&amp;quot; themselves, and I am going to hold off on the edit until I can get some more information on the source of these constants and see if there are better, more accurate values. It is annoying that, in all these years, we still haven&#039;t gotten LL to just tell us what the damn difference is between avatar sit targets and local position offsets in a linkset. It can&#039;t be that hard for someone who is familiar with the code to look at it and document it. -.- [[User:Talarus Luan|Talarus Luan]] 13:24, 5 July 2013 (PDT)&lt;br /&gt;
&lt;br /&gt;
::::::::Welcome back! I&#039;d like to take credit for that but that&#039;s the part that Escort contributed. As to where 0.02638 comes from, I vaguely recall it came from Escort&#039;s testing. I was driven more by &amp;quot;wouldn&#039;t it be cool to write a function that...&amp;quot; than anything else. I do agree the values have always been not quite right. -- &#039;&#039;&#039;[[User:Strife_Onizuka|Strife]]&#039;&#039;&#039; &amp;lt;sup&amp;gt;&amp;lt;small&amp;gt;([[User talk:Strife_Onizuka|talk]]|[[Special:Contributions/Strife_Onizuka|contribs]])&amp;lt;/small&amp;gt;&amp;lt;/sup&amp;gt; 23:10, 5 July 2013 (PDT)&lt;br /&gt;
:::::::::Thanks! OK, I did a bunch of empirical testing, sampling a bunch of avatars from 1.16m to 2.45m in height, as reported by llGetAgentSize. I picked the lowest and highest and one about standard height, and fitted a parabolic curve through them. I have reduced the inaccuracies to a great degree, but it still isn&#039;t 100% perfect for all sizes in that range, just the ones that I used to solve the curve equation. The rest show a *tiny* bit of movement, but they are very close. Obviously, the difference isn&#039;t parabolic, probably just some kind of discrete step function, but it works.[[User:Talarus Luan|Talarus Luan]] 11:16, 14 July 2013 (PDT)&lt;br /&gt;
&amp;lt;lsl&amp;gt;vector vCoefficients = &amp;lt;0.008906,-0.049831,0.088967&amp;gt;;&lt;br /&gt;
float fAdjust = vCoefficients.x * size.z * size.z + vCoefficients.y * size.z + vCoefficients.z;&lt;br /&gt;
llSetLinkPrimitiveParamsFast(linkNum,&lt;br /&gt;
    [PRIM_POS_LOCAL, (pos + &amp;lt;0.0, 0.0, 0.4&amp;gt; - (llRot2Up(rot) * size.z * fAdjust)) * localrot + localpos,&lt;br /&gt;
     PRIM_ROT_LOCAL, rot * localrot]);&amp;lt;/lsl&amp;gt;&lt;br /&gt;
&lt;br /&gt;
::::::::::I see you mind reading abilities haven&#039;t diminished (I contemplated suggesting the tests you have done, decided to go to bed instead). Any reason not to use parentheses? It looks like something that could get optimized to an a series of FMAs (by the VM). -- &#039;&#039;&#039;[[User:Strife_Onizuka|Strife]]&#039;&#039;&#039; &amp;lt;sup&amp;gt;&amp;lt;small&amp;gt;([[User talk:Strife_Onizuka|talk]]|[[Special:Contributions/Strife_Onizuka|contribs]])&amp;lt;/small&amp;gt;&amp;lt;/sup&amp;gt; 21:33, 14 July 2013 (PDT)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;lsl&amp;gt;vector vCoefficients = &amp;lt;0.008906,-0.049831,0.088967&amp;gt;;&lt;br /&gt;
float fAdjust = ((((vCoefficients.x * size.z) + vCoefficients.y) * size.z) + vCoefficients.z) * size.z;&lt;br /&gt;
llSetLinkPrimitiveParamsFast(linkNum,&lt;br /&gt;
    [PRIM_POS_LOCAL, (pos + &amp;lt;0.0, 0.0, 0.4&amp;gt; - (llRot2Up(rot) * fAdjust)) * localrot + localpos,&lt;br /&gt;
     PRIM_ROT_LOCAL, rot * localrot]);&amp;lt;/lsl&amp;gt;&lt;br /&gt;
:::::::::::Yeah, I thought about optimizing it a bit after I posted it, but decided to leave it unoptimized here so the path from the current function to this change was clear, for demonstrability purposes. Besides, I had to leave some room for it to be Strifed&amp;amp;trade;. :P [[User:Talarus Luan|Talarus Luan]] 15:17, 17 July 2013 (PDT)&lt;br /&gt;
&lt;br /&gt;
::::::::::::I appreciate the gesture :p and I&#039;m not as bad as I use to be. I&#039;m not going to optimize out fAdjust, it&#039;s more readable this way. This is more for myself later as my memory is crap, the reasoning behind using llRot2Up is that it solves the pesky problem of the quaternion not having a magnitude of one. While the following isn&#039;t optimal, it is cool. -- &#039;&#039;&#039;[[User:Strife_Onizuka|Strife]]&#039;&#039;&#039; &amp;lt;sup&amp;gt;&amp;lt;small&amp;gt;([[User talk:Strife_Onizuka|talk]]|[[Special:Contributions/Strife_Onizuka|contribs]])&amp;lt;/small&amp;gt;&amp;lt;/sup&amp;gt; 00:00, 18 July 2013 (PDT)&lt;br /&gt;
&amp;lt;lsl&amp;gt;&lt;br /&gt;
size.x = (size.z * (size.y = (size.z * size.z)));&lt;br /&gt;
float fAdjust = vCoefficients * size;&lt;br /&gt;
&amp;lt;/lsl&amp;gt;&lt;br /&gt;
:::::::::::::Yeah, that is a nice way to represent it, for those used to the LSL representation for vector dot product. I&#039;m a little less enthused about the size vector assignment chain, but that&#039;s just my general dislike for C value assignments and such. In my mind, I separate assignments from expressions, so seeing them mixed together causes a bit of a train wreck in my brain&#039;s lexical analyzer. :P[[User:Talarus Luan|Talarus Luan]] 10:00, 21 July 2013 (PDT)&lt;br /&gt;
&lt;br /&gt;
::::::::::::::I don&#039;t think anyone uses the LSL vector dot product. It took me three days to remember it existed and then I look up the syntax just to make sure I wasn&#039;t crazy (yes yes, I agree it&#039;s insane to think that looking up the syntax of an obscure feature is proof against insanity but I&#039;m sticking to it, my cat agrees). I think a train wreck was my goal. -- &#039;&#039;&#039;[[User:Strife_Onizuka|Strife]]&#039;&#039;&#039; &amp;lt;sup&amp;gt;&amp;lt;small&amp;gt;([[User talk:Strife_Onizuka|talk]]|[[Special:Contributions/Strife_Onizuka|contribs]])&amp;lt;/small&amp;gt;&amp;lt;/sup&amp;gt; 11:13, 21 July 2013 (PDT)&lt;br /&gt;
&lt;br /&gt;
== Avatars Floating After Sit ==&lt;br /&gt;
&lt;br /&gt;
The position of avatars will sometimes change, generally noticeable as a rise on the Z axis of perhaps half a meter - common triggers for this is typing or another AV sitting on the same object - though these are not exhaustive.  Does anyone have a clue why this happens, and how to prevent it from happening? [[User:TaraLi Jie|TaraLi Jie]] 21:14, 11 March 2012 (PDT)&lt;br /&gt;
&lt;br /&gt;
:Hmm, there are a few possible causes, but the main cause are the animations involved, so it&#039;s worth remembering that any animation overrider can potentially cause weirdness while on a sit-target, which is why most good ones can turn themselves off while seated. It&#039;s a bit difficult to describe specific problems with animations, but I think that sometimes it can be caused by animations that have a weird first frame, since it&#039;s used to calculate all the offsets etc. for the rest of the animation; normally this will be a neutral pose since you don&#039;t actually see it in the animation, but if it&#039;s something odd then it can mess with positioning. -- &amp;lt;br/&amp;gt;-- &#039;&#039;&#039;[[User:Haravikk_Mistral|Haravikk]]&#039;&#039;&#039; &amp;lt;sup&amp;gt;&amp;lt;small&amp;gt;([[User_talk:Haravikk_Mistral|talk]]|[[Special:Contributions/Haravikk_Mistral|contribs]])&amp;lt;/small&amp;gt;&amp;lt;/sup&amp;gt; 05:34, 12 March 2012 (PDT)&lt;br /&gt;
&lt;br /&gt;
::When I&#039;ve had problems with this, the root cause has usually been that I&#039;ve (or something has) inadvertently stopped an animation that&#039;s holding the avatar in place before starting another one.   Because animations are all made differently, neither the animator with whom I work most of the time nor I have ever managed to figure out exactly what to avoid, but certainly when it happens to me, I always start debugging by looking very carefully at where I&#039;m turning animations off and considering whether, in fact, I need to turn them off at all.   Quite often, I find that simply turning off the default sit animation when my first animation starts, and then keeping the first animation going throughout, starting and stopping other ones over it, as necessary, solves the problem.&lt;br /&gt;
&lt;br /&gt;
::One &amp;quot;gotcha&amp;quot; is that stopping an animation and then immediately restarting it doesn&#039;t work.  It confuses the viewer something horrible, and often leads to people floating in mid-air.  [[User:Innula Zenovka|Innula Zenovka]] 09:04, 12 March 2012 (PDT)&lt;br /&gt;
&lt;br /&gt;
== Sit Target 0.4m &#039;bug&#039; ==&lt;br /&gt;
The notes say &lt;br /&gt;
&amp;quot;rot affects the position of the sit-target in a buggy way way.&lt;br /&gt;
To correct for the rot bug, simply subtract &amp;lt;0,0,0.4&amp;gt; from the position when rot is zero. See example below.&amp;quot;&lt;br /&gt;
&lt;br /&gt;
But the example script adjusts z by 0.4m when rotation is NOT zero.&lt;br /&gt;
&amp;lt;lsl&amp;gt;&lt;br /&gt;
if (rot!=ZERO_ROTATION) pos -=&amp;lt;0,0,0.4&amp;gt;;  //here is the work around&lt;br /&gt;
&amp;lt;/lsl&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Which should it be?&lt;br /&gt;
&lt;br /&gt;
I&#039;ve just been doing some tests without any 0.4m adjustment, and I am unable to observe any difference in my z position whether rotation is zero or not. Has something changed? If so, wouldn&#039;t the change screw up some furniture?&lt;br /&gt;
[[User:Omei Qunhua|Omei Qunhua]] 14:09, 16 March 2014 (PDT)&lt;br /&gt;
&lt;br /&gt;
:You are right, there shouldn&#039;t be a test there. My understanding is that you always need to subtract 0.4 from z. Changing it would screw up furniture. -- &#039;&#039;&#039;[[User:Strife_Onizuka|Strife]]&#039;&#039;&#039; &amp;lt;sup&amp;gt;&amp;lt;small&amp;gt;([[User talk:Strife_Onizuka|talk]]|[[Special:Contributions/Strife_Onizuka|contribs]])&amp;lt;/small&amp;gt;&amp;lt;/sup&amp;gt; 21:02, 16 March 2014 (PDT)&lt;/div&gt;</summary>
		<author><name>Timmy Foxclaw</name></author>
	</entry>
	<entry>
		<id>https://wiki.secondlife.com/w/index.php?title=Talk:LlSitTarget&amp;diff=1189255</id>
		<title>Talk:LlSitTarget</title>
		<link rel="alternate" type="text/html" href="https://wiki.secondlife.com/w/index.php?title=Talk:LlSitTarget&amp;diff=1189255"/>
		<updated>2014-04-07T17:40:07Z</updated>

		<summary type="html">&lt;p&gt;Timmy Foxclaw: Removed PRIM_SIZE, since it&amp;#039;s not used anyway.&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Unsitting on wrong side or camera rotation ==&lt;br /&gt;
&lt;br /&gt;
Hi, i am getting frustrated with this. I create a board and set the sit target with&lt;br /&gt;
&amp;lt;code&amp;gt;llSitTarget(&amp;lt;0.4, 0.0, 0.0&amp;gt;, ZERO_ROTATION);&amp;lt;/code&amp;gt;&lt;br /&gt;
and an animation which for &amp;quot;standing&amp;quot;. So while the person technical sits, she stands in front of the board. &lt;br /&gt;
But I have a problem with that: If the board stand freely, the person unsits right through it towards the other side. I can put the board with the back  facing a large wall. In the case the unsitting is correctly in front of it. But on sit down the camera rotates, so that it is behind the avatar again; on the other side of the wall.&lt;br /&gt;
&lt;br /&gt;
If anyone has an idea how to fix, please tell me (even if it is just an idea where to look for more information). --[[User:Maike Short|Maike Short]] 12:41, 24 February 2008 (PST)&lt;br /&gt;
&lt;br /&gt;
:You could position the camera with the {{LSLGC|Camera}} functions.  -- [[User:Strife Onizuka|Strife Onizuka]] 04:46, 25 February 2008 (PST)&lt;br /&gt;
&lt;br /&gt;
==GetSitTarget==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;lsl&amp;gt;&lt;br /&gt;
list GetSitTarget(integer prim, key av)&lt;br /&gt;
{//WARNING: llGetObjectDetails can introduce an error that goes as far as the 5th decimal place.&lt;br /&gt;
    vector tp = llGetAgentSize(av);&lt;br /&gt;
    if(tp)&lt;br /&gt;
    {&lt;br /&gt;
        if(prim == LINK_THIS)//llGetLinkKey doesn&#039;t like LINK_THIS&lt;br /&gt;
            prim = llGetLinkNumber();&lt;br /&gt;
    &lt;br /&gt;
        list details = OBJECT_POS + (list)OBJECT_ROT;&lt;br /&gt;
        rotation f = llList2Rot(details = (llGetObjectDetails(llGetLinkKey(prim), details) + llGetObjectDetails(av, details)), 1);&lt;br /&gt;
    &lt;br /&gt;
        return [(llRot2Up(f = (llList2Rot(details, 3) / f)) * tp.z * 0.02638) +&lt;br /&gt;
                ((llList2Vector(details, 2) - llList2Vector(details, 0)) / f) - &amp;lt;0.0, 0.0, 0.4&amp;gt;, f];&lt;br /&gt;
    }&lt;br /&gt;
    return [];&lt;br /&gt;
}//Written by Strife Onizuka&lt;br /&gt;
&amp;lt;/lsl&amp;gt;&lt;br /&gt;
Hi Strife! This version of your GetSitTarget, and the other version on the actual LlSitTarget page, both always return &amp;lt;0.000000, 0.000000, 0.707107, 0.707107&amp;gt; for the rotation. --[[User:MartinRJ Fayray|MartinRJ Fayray]] 07:52, 21 January 2013 (PST)&lt;br /&gt;
&lt;br /&gt;
:I haven&#039;t touched this in 5 years but I don&#039;t see a reason why it should be doing what you say. Are you sure you are using it properly? The prim parameter specifies what prim the location will be local to. The function was written to aid in determining sit targets when making furniture. You have the avatar sit on one object and then you get it&#039;s position local to the furniture so you can program in the sit target.&lt;br /&gt;
&lt;br /&gt;
:Just to clarify, you are saying that when you sit on an object with the following script in it, you don&#039;t get approximately the specified value? -- &#039;&#039;&#039;[[User:Strife_Onizuka|Strife]]&#039;&#039;&#039; &amp;lt;sup&amp;gt;&amp;lt;small&amp;gt;([[User talk:Strife_Onizuka|talk]]|[[Special:Contributions/Strife_Onizuka|contribs]])&amp;lt;/small&amp;gt;&amp;lt;/sup&amp;gt; 20:37, 22 January 2013 (PST)&lt;br /&gt;
&lt;br /&gt;
:It seems to work now. No idea what I was doing wrong. Thank you strife!--[[User:MartinRJ Fayray|MartinRJ Fayray]] 07:36, 3 February 2013 (PST)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;lsl&amp;gt;&lt;br /&gt;
vector vOffset = &amp;lt;0,0,1&amp;gt;;&lt;br /&gt;
rotation rOffset = &amp;lt;0,0,0,1&amp;gt;;&lt;br /&gt;
&lt;br /&gt;
list GetSitTarget(integer prim, key av)&lt;br /&gt;
{//WARNING: llGetObjectDetails can introduce an error that goes as far as the 5th decimal place!&lt;br /&gt;
 //This is highly unlikely to be ever noticed unless compounded over time.&lt;br /&gt;
 //Do not use while moving (like in a moving vehicle)!!!&lt;br /&gt;
    vector tp = llGetAgentSize(av);&lt;br /&gt;
    if(tp)&lt;br /&gt;
    {&lt;br /&gt;
        if(prim == LINK_THIS)//llGetLinkKey doesn&#039;t like LINK_THIS&lt;br /&gt;
            prim = llGetLinkNumber();&lt;br /&gt;
 &lt;br /&gt;
        list details = [OBJECT_POS, OBJECT_ROT];&lt;br /&gt;
        rotation f = llList2Rot(details = (llGetObjectDetails(llGetLinkKey(prim), details) + llGetObjectDetails(av, details)), 1);&lt;br /&gt;
        rotation r = llList2Rot(details, 3) / f;&lt;br /&gt;
 &lt;br /&gt;
        return [((llList2Vector(details, 2) - llList2Vector(details, 0)) / f) + (llRot2Up(r) * tp.z * 0.02638) - &amp;lt;0.0, 0.0, 0.4&amp;gt;, r];&lt;br /&gt;
    }&lt;br /&gt;
    return [];&lt;br /&gt;
}//Written by Strife Onizuka&lt;br /&gt;
&lt;br /&gt;
default{&lt;br /&gt;
    state_entry(){&lt;br /&gt;
        llSitTarget(vOffset, rOffset);&lt;br /&gt;
    }&lt;br /&gt;
    changed(integer change){&lt;br /&gt;
        key id = llAvatarOnSitTarget();&lt;br /&gt;
        if(id)&lt;br /&gt;
            llOwnerSay(&amp;quot;[&amp;quot;+llList2CSV([vOffset, rOffset]) +&amp;quot;] ~ [&amp;quot; + llList2CSV(GetSitTarget(LINK_THIS, id))+&amp;quot;]&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/lsl&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Note&#039;&#039;&#039;: the two scripts in this paragraph are incorrect. Most notably, the position of an avatar (it&#039;s Avatar Center) is NOT dependent on the AgentSize of the seated avatar. I added another script that returns the sit target below. [[User:Timmy Foxclaw|Timmy Foxclaw]] 10:31, 7 April 2014 (PDT)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;lsl&amp;gt;&lt;br /&gt;
// A script to develop and test sbGetLinkSitTarget&lt;br /&gt;
//&lt;br /&gt;
// Copyright(c) Timmy Songbird @DreamNation&lt;br /&gt;
//              Timmy Foxclaw  @SL,&lt;br /&gt;
//              2014&lt;br /&gt;
//&lt;br /&gt;
// This program is free software; you can redistribute it and/or modify&lt;br /&gt;
// it under the terms of the GNU General Public License as published by&lt;br /&gt;
// the Free Software Foundation; either version 2 of the License, or&lt;br /&gt;
// (at your option) any later version.&lt;br /&gt;
//&lt;br /&gt;
// This program is distributed in the hope that it will be useful,&lt;br /&gt;
// but WITHOUT ANY WARRANTY; without even the implied warranty of&lt;br /&gt;
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the&lt;br /&gt;
// GNU General Public License for more details.&lt;br /&gt;
//&lt;br /&gt;
// You should have received a copy of the GNU General Public License&lt;br /&gt;
// along with this program; if not, write to the Free Software&lt;br /&gt;
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307, USA.&#039;)&lt;br /&gt;
&lt;br /&gt;
//----------------------------------------------------------------------------&lt;br /&gt;
//#line &amp;quot;/opt/secondlife/scripts/scripts/tests/sbGetLinkSitTarget_Test.m4s:4&amp;quot;&lt;br /&gt;
// This script sets a &amp;quot;random&amp;quot;-ish sit target on every prim in an object.&lt;br /&gt;
// Recommended for your test is an object existing of two default cubes&lt;br /&gt;
// with arbitrary rotations and position. Put this script only in the&lt;br /&gt;
// root prim.&lt;br /&gt;
//&lt;br /&gt;
// The script sets the sit targets on compile or touch. Please touch&lt;br /&gt;
// the object after editting one of the prims.&lt;br /&gt;
//&lt;br /&gt;
// When an avatar (un)sits on one of the prims, the script prints for every&lt;br /&gt;
// sit target that has a seated avatar the return value of sbGetLinkSitTarget.&lt;br /&gt;
// This value should be (almost) equal to the values passed to llSitTarget.&lt;br /&gt;
&lt;br /&gt;
// Example output:&lt;br /&gt;
&lt;br /&gt;
// Object: [&amp;lt;0.200000, 0.300000, 0.500000&amp;gt;, &amp;lt;0.100000, 0.150000, 0.120000, 0.976268&amp;gt;] set with llSitTarget on 2 prims.&lt;br /&gt;
// Object: [&amp;lt;0.199999, 0.300001, 0.499999&amp;gt;, &amp;lt;0.100000, 0.150000, 0.120000, 0.976268&amp;gt;] returned by sbGetLinkSitTarget(1).&lt;br /&gt;
// Object: [&amp;lt;0.199998, 0.300002, 0.499998&amp;gt;, &amp;lt;0.100000, 0.150000, 0.120000, 0.976268&amp;gt;] returned by sbGetLinkSitTarget(2).&lt;br /&gt;
&lt;br /&gt;
// GitLocation: tests/sbGetLinkSitTarget_Test.m4s&lt;br /&gt;
&lt;br /&gt;
//----------------------------------------------------------------------------&lt;br /&gt;
//#line &amp;quot;/opt/secondlife/scripts/scripts/tests/sbGetLinkSitTarget_Test.m4s:26&amp;quot;&lt;br /&gt;
vector sitTarget_pos_link = &amp;lt;0.2, 0.3, 0.5&amp;gt;;&lt;br /&gt;
rotation sitTarget_rot_link = &amp;lt;0.1, 0.15, 0.12, 0.9762684&amp;gt;;&lt;br /&gt;
&lt;br /&gt;
//----------------------------------------------------------------------------&lt;br /&gt;
//#line &amp;quot;/opt/secondlife/scripts/scripts/tests/sbGetLinkSitTarget_Test.m4s:31&amp;quot;&lt;br /&gt;
// Returns the correct values to use for llSitTarget to make&lt;br /&gt;
// the currently seated avatar sit in the same way when re-seated.&lt;br /&gt;
// If no avatar is currently sitting then [ZERO_VECTOR, ZERO_ROTATION] is returned.&lt;br /&gt;
//&lt;br /&gt;
// [1] http://wiki.secondlife.com/wiki/User:Timmy_Foxclaw/About_Coordinate_Systems_and_Rotations#LSL_functions&lt;br /&gt;
// [2] http://wiki.secondlife.com/wiki/User:Timmy_Foxclaw/About_Coordinate_Systems_and_Rotations#Converting_between_coordinate_systems&lt;br /&gt;
list sbGetLinkSitTarget(integer link)&lt;br /&gt;
{&lt;br /&gt;
  // Calling llAvatarOnLinkSitTarget(0) always returns NULL_KEY because the link&lt;br /&gt;
  // number of an unlinked prim changes from 0 to 1 as soon as an avatar sits on&lt;br /&gt;
  // it. So if 0 was passed then they probably meant 1.&lt;br /&gt;
  if (link == 0)&lt;br /&gt;
  {&lt;br /&gt;
    link = 1;&lt;br /&gt;
  }&lt;br /&gt;
  key av = llAvatarOnLinkSitTarget(link);&lt;br /&gt;
  if (av != NULL_KEY)&lt;br /&gt;
  {&lt;br /&gt;
    // Get link_pos_oc and link_rot_oc. See table 2 in [1].&lt;br /&gt;
    vector link_pos_oc = ZERO_VECTOR;&lt;br /&gt;
    rotation link_rot_oc = ZERO_ROTATION;&lt;br /&gt;
    if (link &amp;gt; 1)&lt;br /&gt;
    {&lt;br /&gt;
      list params = llGetLinkPrimitiveParams(link, [PRIM_POS_LOCAL, PRIM_ROT_LOCAL]);&lt;br /&gt;
      link_pos_oc = llList2Vector(params, 0);&lt;br /&gt;
      link_rot_oc = llList2Rot(params, 1);&lt;br /&gt;
    }&lt;br /&gt;
    // Find the link number of the seated avatar.&lt;br /&gt;
    integer avNum = llGetNumberOfPrims();&lt;br /&gt;
    do&lt;br /&gt;
    {&lt;br /&gt;
        if (av == llGetLinkKey(avNum))&lt;br /&gt;
        {&lt;br /&gt;
            // Get ac_pos_oc and ac_rot_oc (ac stands for Avatar Center), exactly the same as above&lt;br /&gt;
            // except that we don&#039;t need to test if avNum &amp;gt; 1, because it always will be.&lt;br /&gt;
            list params = llGetLinkPrimitiveParams(avNum, [PRIM_POS_LOCAL, PRIM_ROT_LOCAL]);&lt;br /&gt;
            vector ac_pos_oc = llList2Vector(params, 0);&lt;br /&gt;
            rotation ac_rot_oc = llList2Rot(params, 1);&lt;br /&gt;
&lt;br /&gt;
            // Convert that to link coordinates. See formula (3) in [2].&lt;br /&gt;
            vector ac_pos_link = (ac_pos_oc - link_pos_oc) / link_rot_oc;&lt;br /&gt;
            rotation ac_rot_link = ac_rot_oc / link_rot_oc;&lt;br /&gt;
&lt;br /&gt;
            // Now we have this little vector in the Avatar Center coordinates.&lt;br /&gt;
            vector sit_pos_ac = &amp;lt;0.0, 0.0, 0.05&amp;gt;;&lt;br /&gt;
&lt;br /&gt;
            // Convert that to link coordinates. See formula (1) in [2].&lt;br /&gt;
            vector sit_pos_link = sit_pos_ac * ac_rot_link + ac_pos_link;&lt;br /&gt;
&lt;br /&gt;
            // Return the values, accounting for the sit target bug of 0.4m.&lt;br /&gt;
            return [sit_pos_link - &amp;lt;0.0, 0.0, 0.4&amp;gt;, ac_rot_link];&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    while (--avNum);&lt;br /&gt;
  }&lt;br /&gt;
  return [ZERO_VECTOR, ZERO_ROTATION];&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
setSitTargets()&lt;br /&gt;
{&lt;br /&gt;
  // Set the same sit target on every prim.&lt;br /&gt;
  integer n = llGetNumberOfPrims();&lt;br /&gt;
  llSay(0, &amp;quot;[&amp;quot; +  llList2CSV([sitTarget_pos_link, sitTarget_rot_link]) + &amp;quot;] set with llSitTarget on &amp;quot; + (string)n + &amp;quot; prims.&amp;quot;);&lt;br /&gt;
  do&lt;br /&gt;
  {&lt;br /&gt;
    llLinkSitTarget(n, sitTarget_pos_link, sitTarget_rot_link);&lt;br /&gt;
  }&lt;br /&gt;
  while(--n);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
//----------------------------------------------------------------------------&lt;br /&gt;
//#line &amp;quot;/opt/secondlife/scripts/scripts/tests/sbGetLinkSitTarget_Test.m4s:105&amp;quot;&lt;br /&gt;
default&lt;br /&gt;
{&lt;br /&gt;
  state_entry()&lt;br /&gt;
  {&lt;br /&gt;
    setSitTargets();&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  touch_start(integer n)&lt;br /&gt;
  {&lt;br /&gt;
    setSitTargets();&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  changed(integer change)&lt;br /&gt;
  {&lt;br /&gt;
    if ((change &amp;amp; CHANGED_LINK))&lt;br /&gt;
    {&lt;br /&gt;
      integer n = llGetNumberOfPrims();&lt;br /&gt;
      do&lt;br /&gt;
      {&lt;br /&gt;
        key av = llAvatarOnLinkSitTarget(n);&lt;br /&gt;
        if (av != NULL_KEY)&lt;br /&gt;
        {&lt;br /&gt;
          llSay(0, &amp;quot;[&amp;quot; + llList2CSV(sbGetLinkSitTarget(n)) + &amp;quot;] returned by sbGetLinkSitTarget(&amp;quot; + (string)n + &amp;quot;).&amp;quot;);&lt;br /&gt;
        }&lt;br /&gt;
      }&lt;br /&gt;
      while(--n);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/lsl&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Using llSetLinkPrimitiveParams for skydiving: why limited to 5m in a linked set?==&lt;br /&gt;
llSetLinkPrimitiveParams can be used as a handy tool to adjust an avatar&#039;s position and rotation.&lt;br /&gt;
This works perfectly when the object consists of 1 prim, with a range for setting the avatar position away to 500m easily!&lt;br /&gt;
When there are more prims linked, this offset seems to be limited to 5m (measured with llVecDist). This is an awfull sideeffect!&lt;br /&gt;
&lt;br /&gt;
Put this next script inside a prim and sit on the prim, it will bring you to 1000.0 higher then the prim.&lt;br /&gt;
Next link this prim to another prim and try again. You will notice you are limited to 5m. My Question: why is this limited?&lt;br /&gt;
&amp;lt;lsl&amp;gt;&lt;br /&gt;
// by Randur Source&lt;br /&gt;
&lt;br /&gt;
integer heightcnt = 0;&lt;br /&gt;
list heights = [0.0, 1.0, 5.0, 6.0, 10.0, 100.0, 300.0, 500.0, 800.0, 1000.0];&lt;br /&gt;
&lt;br /&gt;
default&lt;br /&gt;
{&lt;br /&gt;
    state_entry()&lt;br /&gt;
    {&lt;br /&gt;
        llSitTarget(ZERO_VECTOR,ZERO_ROTATION); // Clear the current sittarget for a clear test&lt;br /&gt;
        llSetRot(ZERO_ROTATION); // set the prim to no rotation, for simple z axis movement&lt;br /&gt;
    }&lt;br /&gt;
    &lt;br /&gt;
    changed(integer change)&lt;br /&gt;
    {&lt;br /&gt;
        if (change &amp;amp; CHANGED_LINK) // detect linked prims and avatars&lt;br /&gt;
        {&lt;br /&gt;
            integer primnum = llGetNumberOfPrims(); // the avatar is the last linked prim&lt;br /&gt;
            if (primnum &amp;lt;= 1) // stop if there is only 1 prim&lt;br /&gt;
                return;&lt;br /&gt;
        &lt;br /&gt;
            key avatar = llGetLinkKey(primnum);&lt;br /&gt;
            if (llGetAgentSize(avatar) == ZERO_VECTOR) // stop if this is not an avatar&lt;br /&gt;
                return;&lt;br /&gt;
                &lt;br /&gt;
            // loop through the list of test heights:&lt;br /&gt;
            for (heightcnt = 0; heightcnt &amp;lt; llGetListLength(heights); heightcnt++)&lt;br /&gt;
            {&lt;br /&gt;
                float height = llList2Float(heights,heightcnt);&lt;br /&gt;
                llSetLinkPrimitiveParams(primnum,[PRIM_POSITION,&amp;lt;0.0,0.0,height&amp;gt;]); // set this to the wanted height using a vector z axis&lt;br /&gt;
                &lt;br /&gt;
                vector avatarpos = llList2Vector(llGetObjectDetails(avatar,[OBJECT_POS]),0); // detect the avatar position within the sim&lt;br /&gt;
                float distance = llVecDist(llGetPos(),avatarpos);&lt;br /&gt;
                llOwnerSay(&amp;quot;Attempt to move &amp;quot; + llKey2Name(llGetLinkKey(primnum)) +&lt;br /&gt;
                           &amp;quot; to &amp;quot; + (string)height + &amp;quot;m high resulting to &amp;quot; + (string)distance + &amp;quot;m&amp;quot;);&lt;br /&gt;
                &lt;br /&gt;
                llSleep(1.0);&lt;br /&gt;
            }&lt;br /&gt;
            llUnSit(avatar);&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/lsl&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Posted by Sylvio Runo : Answer &#039;&#039;&#039; :&lt;br /&gt;
The correct limit is 54 meters.&lt;br /&gt;
You can&#039;t move a linked object more than 54 meters away from the axis of the root prim.&lt;br /&gt;
On SecondLife (other grids like OsGrid, may works diferent) when an agent sit on prim, the agent is attached to it, so the agent is a linked prim of the link set.&lt;br /&gt;
&lt;br /&gt;
More information about link rules, you will find here : http://wiki.secondlife.com/wiki/Linkability_Rules [http://wiki.secondlife.com/wiki/Linkability_Rules]&lt;br /&gt;
&lt;br /&gt;
==UpdateSitTarget changes?==&lt;br /&gt;
I recently worked on a project where I used a version of this function, and it appears that it is a little off. A couple of things I noted: the Z-offset of the sit target is 0.35, not 0.4, and the avatar size doesn&#039;t seem to affect this position at all. When I used this function verbatim, I noticed discrepancies between the actual sit target and the set position call. When I changed the script as noted, I got a perfect match. Has the handling of the sit target been changed since this was written? [[User:Talarus Luan|Talarus Luan]] 22:57, 1 July 2009 (UTC)&lt;br /&gt;
:Seconded. I wish I&#039;d looked at this discussion before spending an hour on trying to figure out how the code actually behaved. -- [[User:Tonya Souther|Tonya Souther]] 15:11, 19 August 2009 (UTC)&lt;br /&gt;
&lt;br /&gt;
::This is news to me but I haven&#039;t been in world in ages :( -- &#039;&#039;&#039;[[User:Strife_Onizuka|Strife]]&#039;&#039;&#039; &amp;lt;sup&amp;gt;&amp;lt;small&amp;gt;([[User talk:Strife_Onizuka|talk]]|[[Special:Contributions/Strife_Onizuka|contribs]])&amp;lt;/small&amp;gt;&amp;lt;/sup&amp;gt; 22:56, 20 August 2009 (UTC)&lt;br /&gt;
&lt;br /&gt;
:::From some quick testing in 1.40, this seems to be how the &amp;quot;true&amp;quot; offset is computed:&lt;br /&gt;
:::1. Start with offset as provided by LSL.&lt;br /&gt;
:::2. Add &amp;lt; 0.0 , 0.0 , 0.4 &amp;gt;&lt;br /&gt;
:::3. Subtract llRot2Up( rot ) * 0.05&lt;br /&gt;
:::[[User:Gregory Maurer|--Gregory Maurer]] 20:00, 28 August 2010 (UTC)&lt;br /&gt;
&lt;br /&gt;
::::Confirmed. The following appears to work fine:&lt;br /&gt;
&amp;lt;lsl&amp;gt;llSetLinkPrimitiveParams(linkNum, [PRIM_POS_LOCAL, pos + &amp;lt;0.0, 0.0, 0.4&amp;gt; - (llRot2Up(rot) * 0.05), PRIM_ROT_LOCAL, rot]);&amp;lt;/lsl&amp;gt;&lt;br /&gt;
::::This of course using the new &amp;lt;code&amp;gt;PRIM_POS_LOCAL&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;PRIM_ROT_LOCAL&amp;lt;/code&amp;gt; values for simplicity. If one or two others can confirm that the above code works correctly, then I can splice it into the example.&amp;lt;br/&amp;gt;-- &#039;&#039;&#039;[[User:Haravikk_Mistral|Haravikk]]&#039;&#039;&#039; &amp;lt;sup&amp;gt;&amp;lt;small&amp;gt;([[User_talk:Haravikk_Mistral|talk]]|[[Special:Contributions/Haravikk_Mistral|contribs]])&amp;lt;/small&amp;gt;&amp;lt;/sup&amp;gt; 14:16, 26 December 2011 (PST)&lt;br /&gt;
&lt;br /&gt;
:::::Be sure to test it with avatars of different shapes, and shoe configurations. I recall that being an issue. {{User|Escort DeFarge}} would know about this best. -- &#039;&#039;&#039;[[User:Strife_Onizuka|Strife]]&#039;&#039;&#039; &amp;lt;sup&amp;gt;&amp;lt;small&amp;gt;([[User talk:Strife_Onizuka|talk]]|[[Special:Contributions/Strife_Onizuka|contribs]])&amp;lt;/small&amp;gt;&amp;lt;/sup&amp;gt; 22:05, 26 December 2011 (PST)&lt;br /&gt;
&lt;br /&gt;
::::::I tried with my two main avatar appearances, one average human height and one closer to 8 feet tall, and it didn&#039;t seem to make a difference. The test I used was a simple object with sit-target set, and a menu allowing it to be repositioned, causing the sit-target to move and if an avatar is seated on it, they will be repositioned using &amp;lt;code&amp;gt;llSetLinkPrimitiveParams()&amp;lt;/code&amp;gt; as done above. In my case the position of the avatar was consistent both when sitting on the object (using the sit-target) and being repositioned. Avatar height appears to have no effect, as the sit-target seems to define the avatar&#039;s hip-location, which is seemingly the avatar&#039;s &amp;quot;centre&amp;quot; when seated. I&#039;ll try to run some more tests when I get a chance, as it&#039;s possible this behaviour may not hold true if the object doesn&#039;t have a sit-target on it. The height of the avatar does however have a marked visual impact, depending exactly what you&#039;re trying to line up where, but that&#039;s a general issue with sitting on objects.&amp;lt;br/&amp;gt;-- &#039;&#039;&#039;[[User:Haravikk_Mistral|Haravikk]]&#039;&#039;&#039; &amp;lt;sup&amp;gt;&amp;lt;small&amp;gt;([[User_talk:Haravikk_Mistral|talk]]|[[Special:Contributions/Haravikk_Mistral|contribs]])&amp;lt;/small&amp;gt;&amp;lt;/sup&amp;gt; 05:38, 28 December 2011 (PST)&lt;br /&gt;
:::::::Sorry for my long delay in responding. Due to various RL issues and SL/LL burnout, I took a year off from SL to pursue other activities. That said, it seems to work fine to me, Haravikk; however, I have not done exhaustive testing with tons of different avs, shoes, etc. I would consider going ahead and changing it, because the version as it is right now is not correct for the majority of avatars, regardless. If Escort DeFarge or someone else wants to amend it later to include edge cases, that&#039;s great, but a better base accuracy is more important at this point. In fact, I think I will go ahead and edit it in, since it has been so long anyway.[[User:Talarus Luan|Talarus Luan]] 12:12, 5 July 2013 (PDT)&lt;br /&gt;
:::::::Holding up on the edit, further testing is revealing that if the script is in a prim other than the root, it is off by varying amounts depending on the rotation.[[User:Talarus Luan|Talarus Luan]] 12:39, 5 July 2013 (PDT)&lt;br /&gt;
:::::::OK, I think I found the error. Still need to keep the local position/rotation values for the child prim the script is in, like so:&lt;br /&gt;
&amp;lt;lsl&amp;gt;llSetLinkPrimitiveParams(linkNum, PRIM_POS_LOCAL, (pos + &amp;lt;0.0, 0.0, 0.4&amp;gt; - (llRot2Up(rot) * 0.05)) * localrot + localpos, PRIM_ROT_LOCAL, rot * localrot]);&amp;lt;/lsl&amp;gt;&lt;br /&gt;
:::::::I&#039;ll hold off on the edit until I can get another verify that this code is good.[[User:Talarus Luan|Talarus Luan]] 12:51, 5 July 2013 (PDT)&lt;br /&gt;
:::::::OK. I think I have analyzed this to death today and have come to the conclusion that Strife&#039;s original code is largely correct, but the error I am seeing comes from the &amp;quot;magic constants&amp;quot; 0.4 and 0.02638. Haravikk&#039;s code is simply a reduced form of Strife&#039;s code. The 0.4 magic constant is still there, but Haravikk is using just a close, but fixed, magic constant of 0.05 instead of Strife&#039;s (size.z * 0.02638), which comes out very close to 0.5 for most normal human avs. Thus, I am concluding that the inaccuracy is in the &amp;quot;magic constants&amp;quot; themselves, and I am going to hold off on the edit until I can get some more information on the source of these constants and see if there are better, more accurate values. It is annoying that, in all these years, we still haven&#039;t gotten LL to just tell us what the damn difference is between avatar sit targets and local position offsets in a linkset. It can&#039;t be that hard for someone who is familiar with the code to look at it and document it. -.- [[User:Talarus Luan|Talarus Luan]] 13:24, 5 July 2013 (PDT)&lt;br /&gt;
&lt;br /&gt;
::::::::Welcome back! I&#039;d like to take credit for that but that&#039;s the part that Escort contributed. As to where 0.02638 comes from, I vaguely recall it came from Escort&#039;s testing. I was driven more by &amp;quot;wouldn&#039;t it be cool to write a function that...&amp;quot; than anything else. I do agree the values have always been not quite right. -- &#039;&#039;&#039;[[User:Strife_Onizuka|Strife]]&#039;&#039;&#039; &amp;lt;sup&amp;gt;&amp;lt;small&amp;gt;([[User talk:Strife_Onizuka|talk]]|[[Special:Contributions/Strife_Onizuka|contribs]])&amp;lt;/small&amp;gt;&amp;lt;/sup&amp;gt; 23:10, 5 July 2013 (PDT)&lt;br /&gt;
:::::::::Thanks! OK, I did a bunch of empirical testing, sampling a bunch of avatars from 1.16m to 2.45m in height, as reported by llGetAgentSize. I picked the lowest and highest and one about standard height, and fitted a parabolic curve through them. I have reduced the inaccuracies to a great degree, but it still isn&#039;t 100% perfect for all sizes in that range, just the ones that I used to solve the curve equation. The rest show a *tiny* bit of movement, but they are very close. Obviously, the difference isn&#039;t parabolic, probably just some kind of discrete step function, but it works.[[User:Talarus Luan|Talarus Luan]] 11:16, 14 July 2013 (PDT)&lt;br /&gt;
&amp;lt;lsl&amp;gt;vector vCoefficients = &amp;lt;0.008906,-0.049831,0.088967&amp;gt;;&lt;br /&gt;
float fAdjust = vCoefficients.x * size.z * size.z + vCoefficients.y * size.z + vCoefficients.z;&lt;br /&gt;
llSetLinkPrimitiveParamsFast(linkNum,&lt;br /&gt;
    [PRIM_POS_LOCAL, (pos + &amp;lt;0.0, 0.0, 0.4&amp;gt; - (llRot2Up(rot) * size.z * fAdjust)) * localrot + localpos,&lt;br /&gt;
     PRIM_ROT_LOCAL, rot * localrot]);&amp;lt;/lsl&amp;gt;&lt;br /&gt;
&lt;br /&gt;
::::::::::I see you mind reading abilities haven&#039;t diminished (I contemplated suggesting the tests you have done, decided to go to bed instead). Any reason not to use parentheses? It looks like something that could get optimized to an a series of FMAs (by the VM). -- &#039;&#039;&#039;[[User:Strife_Onizuka|Strife]]&#039;&#039;&#039; &amp;lt;sup&amp;gt;&amp;lt;small&amp;gt;([[User talk:Strife_Onizuka|talk]]|[[Special:Contributions/Strife_Onizuka|contribs]])&amp;lt;/small&amp;gt;&amp;lt;/sup&amp;gt; 21:33, 14 July 2013 (PDT)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;lsl&amp;gt;vector vCoefficients = &amp;lt;0.008906,-0.049831,0.088967&amp;gt;;&lt;br /&gt;
float fAdjust = ((((vCoefficients.x * size.z) + vCoefficients.y) * size.z) + vCoefficients.z) * size.z;&lt;br /&gt;
llSetLinkPrimitiveParamsFast(linkNum,&lt;br /&gt;
    [PRIM_POS_LOCAL, (pos + &amp;lt;0.0, 0.0, 0.4&amp;gt; - (llRot2Up(rot) * fAdjust)) * localrot + localpos,&lt;br /&gt;
     PRIM_ROT_LOCAL, rot * localrot]);&amp;lt;/lsl&amp;gt;&lt;br /&gt;
:::::::::::Yeah, I thought about optimizing it a bit after I posted it, but decided to leave it unoptimized here so the path from the current function to this change was clear, for demonstrability purposes. Besides, I had to leave some room for it to be Strifed&amp;amp;trade;. :P [[User:Talarus Luan|Talarus Luan]] 15:17, 17 July 2013 (PDT)&lt;br /&gt;
&lt;br /&gt;
::::::::::::I appreciate the gesture :p and I&#039;m not as bad as I use to be. I&#039;m not going to optimize out fAdjust, it&#039;s more readable this way. This is more for myself later as my memory is crap, the reasoning behind using llRot2Up is that it solves the pesky problem of the quaternion not having a magnitude of one. While the following isn&#039;t optimal, it is cool. -- &#039;&#039;&#039;[[User:Strife_Onizuka|Strife]]&#039;&#039;&#039; &amp;lt;sup&amp;gt;&amp;lt;small&amp;gt;([[User talk:Strife_Onizuka|talk]]|[[Special:Contributions/Strife_Onizuka|contribs]])&amp;lt;/small&amp;gt;&amp;lt;/sup&amp;gt; 00:00, 18 July 2013 (PDT)&lt;br /&gt;
&amp;lt;lsl&amp;gt;&lt;br /&gt;
size.x = (size.z * (size.y = (size.z * size.z)));&lt;br /&gt;
float fAdjust = vCoefficients * size;&lt;br /&gt;
&amp;lt;/lsl&amp;gt;&lt;br /&gt;
:::::::::::::Yeah, that is a nice way to represent it, for those used to the LSL representation for vector dot product. I&#039;m a little less enthused about the size vector assignment chain, but that&#039;s just my general dislike for C value assignments and such. In my mind, I separate assignments from expressions, so seeing them mixed together causes a bit of a train wreck in my brain&#039;s lexical analyzer. :P[[User:Talarus Luan|Talarus Luan]] 10:00, 21 July 2013 (PDT)&lt;br /&gt;
&lt;br /&gt;
::::::::::::::I don&#039;t think anyone uses the LSL vector dot product. It took me three days to remember it existed and then I look up the syntax just to make sure I wasn&#039;t crazy (yes yes, I agree it&#039;s insane to think that looking up the syntax of an obscure feature is proof against insanity but I&#039;m sticking to it, my cat agrees). I think a train wreck was my goal. -- &#039;&#039;&#039;[[User:Strife_Onizuka|Strife]]&#039;&#039;&#039; &amp;lt;sup&amp;gt;&amp;lt;small&amp;gt;([[User talk:Strife_Onizuka|talk]]|[[Special:Contributions/Strife_Onizuka|contribs]])&amp;lt;/small&amp;gt;&amp;lt;/sup&amp;gt; 11:13, 21 July 2013 (PDT)&lt;br /&gt;
&lt;br /&gt;
== Avatars Floating After Sit ==&lt;br /&gt;
&lt;br /&gt;
The position of avatars will sometimes change, generally noticeable as a rise on the Z axis of perhaps half a meter - common triggers for this is typing or another AV sitting on the same object - though these are not exhaustive.  Does anyone have a clue why this happens, and how to prevent it from happening? [[User:TaraLi Jie|TaraLi Jie]] 21:14, 11 March 2012 (PDT)&lt;br /&gt;
&lt;br /&gt;
:Hmm, there are a few possible causes, but the main cause are the animations involved, so it&#039;s worth remembering that any animation overrider can potentially cause weirdness while on a sit-target, which is why most good ones can turn themselves off while seated. It&#039;s a bit difficult to describe specific problems with animations, but I think that sometimes it can be caused by animations that have a weird first frame, since it&#039;s used to calculate all the offsets etc. for the rest of the animation; normally this will be a neutral pose since you don&#039;t actually see it in the animation, but if it&#039;s something odd then it can mess with positioning. -- &amp;lt;br/&amp;gt;-- &#039;&#039;&#039;[[User:Haravikk_Mistral|Haravikk]]&#039;&#039;&#039; &amp;lt;sup&amp;gt;&amp;lt;small&amp;gt;([[User_talk:Haravikk_Mistral|talk]]|[[Special:Contributions/Haravikk_Mistral|contribs]])&amp;lt;/small&amp;gt;&amp;lt;/sup&amp;gt; 05:34, 12 March 2012 (PDT)&lt;br /&gt;
&lt;br /&gt;
::When I&#039;ve had problems with this, the root cause has usually been that I&#039;ve (or something has) inadvertently stopped an animation that&#039;s holding the avatar in place before starting another one.   Because animations are all made differently, neither the animator with whom I work most of the time nor I have ever managed to figure out exactly what to avoid, but certainly when it happens to me, I always start debugging by looking very carefully at where I&#039;m turning animations off and considering whether, in fact, I need to turn them off at all.   Quite often, I find that simply turning off the default sit animation when my first animation starts, and then keeping the first animation going throughout, starting and stopping other ones over it, as necessary, solves the problem.&lt;br /&gt;
&lt;br /&gt;
::One &amp;quot;gotcha&amp;quot; is that stopping an animation and then immediately restarting it doesn&#039;t work.  It confuses the viewer something horrible, and often leads to people floating in mid-air.  [[User:Innula Zenovka|Innula Zenovka]] 09:04, 12 March 2012 (PDT)&lt;br /&gt;
&lt;br /&gt;
== Sit Target 0.4m &#039;bug&#039; ==&lt;br /&gt;
The notes say &lt;br /&gt;
&amp;quot;rot affects the position of the sit-target in a buggy way way.&lt;br /&gt;
To correct for the rot bug, simply subtract &amp;lt;0,0,0.4&amp;gt; from the position when rot is zero. See example below.&amp;quot;&lt;br /&gt;
&lt;br /&gt;
But the example script adjusts z by 0.4m when rotation is NOT zero.&lt;br /&gt;
&amp;lt;lsl&amp;gt;&lt;br /&gt;
if (rot!=ZERO_ROTATION) pos -=&amp;lt;0,0,0.4&amp;gt;;  //here is the work around&lt;br /&gt;
&amp;lt;/lsl&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Which should it be?&lt;br /&gt;
&lt;br /&gt;
I&#039;ve just been doing some tests without any 0.4m adjustment, and I am unable to observe any difference in my z position whether rotation is zero or not. Has something changed? If so, wouldn&#039;t the change screw up some furniture?&lt;br /&gt;
[[User:Omei Qunhua|Omei Qunhua]] 14:09, 16 March 2014 (PDT)&lt;br /&gt;
&lt;br /&gt;
:You are right, there shouldn&#039;t be a test there. My understanding is that you always need to subtract 0.4 from z. Changing it would screw up furniture. -- &#039;&#039;&#039;[[User:Strife_Onizuka|Strife]]&#039;&#039;&#039; &amp;lt;sup&amp;gt;&amp;lt;small&amp;gt;([[User talk:Strife_Onizuka|talk]]|[[Special:Contributions/Strife_Onizuka|contribs]])&amp;lt;/small&amp;gt;&amp;lt;/sup&amp;gt; 21:02, 16 March 2014 (PDT)&lt;/div&gt;</summary>
		<author><name>Timmy Foxclaw</name></author>
	</entry>
	<entry>
		<id>https://wiki.secondlife.com/w/index.php?title=Talk:LlSitTarget&amp;diff=1189254</id>
		<title>Talk:LlSitTarget</title>
		<link rel="alternate" type="text/html" href="https://wiki.secondlife.com/w/index.php?title=Talk:LlSitTarget&amp;diff=1189254"/>
		<updated>2014-04-07T17:35:51Z</updated>

		<summary type="html">&lt;p&gt;Timmy Foxclaw: Added script to same paragraph... Changed the name of the paragraph to GetSitTarget.&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Unsitting on wrong side or camera rotation ==&lt;br /&gt;
&lt;br /&gt;
Hi, i am getting frustrated with this. I create a board and set the sit target with&lt;br /&gt;
&amp;lt;code&amp;gt;llSitTarget(&amp;lt;0.4, 0.0, 0.0&amp;gt;, ZERO_ROTATION);&amp;lt;/code&amp;gt;&lt;br /&gt;
and an animation which for &amp;quot;standing&amp;quot;. So while the person technical sits, she stands in front of the board. &lt;br /&gt;
But I have a problem with that: If the board stand freely, the person unsits right through it towards the other side. I can put the board with the back  facing a large wall. In the case the unsitting is correctly in front of it. But on sit down the camera rotates, so that it is behind the avatar again; on the other side of the wall.&lt;br /&gt;
&lt;br /&gt;
If anyone has an idea how to fix, please tell me (even if it is just an idea where to look for more information). --[[User:Maike Short|Maike Short]] 12:41, 24 February 2008 (PST)&lt;br /&gt;
&lt;br /&gt;
:You could position the camera with the {{LSLGC|Camera}} functions.  -- [[User:Strife Onizuka|Strife Onizuka]] 04:46, 25 February 2008 (PST)&lt;br /&gt;
&lt;br /&gt;
==GetSitTarget==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;lsl&amp;gt;&lt;br /&gt;
list GetSitTarget(integer prim, key av)&lt;br /&gt;
{//WARNING: llGetObjectDetails can introduce an error that goes as far as the 5th decimal place.&lt;br /&gt;
    vector tp = llGetAgentSize(av);&lt;br /&gt;
    if(tp)&lt;br /&gt;
    {&lt;br /&gt;
        if(prim == LINK_THIS)//llGetLinkKey doesn&#039;t like LINK_THIS&lt;br /&gt;
            prim = llGetLinkNumber();&lt;br /&gt;
    &lt;br /&gt;
        list details = OBJECT_POS + (list)OBJECT_ROT;&lt;br /&gt;
        rotation f = llList2Rot(details = (llGetObjectDetails(llGetLinkKey(prim), details) + llGetObjectDetails(av, details)), 1);&lt;br /&gt;
    &lt;br /&gt;
        return [(llRot2Up(f = (llList2Rot(details, 3) / f)) * tp.z * 0.02638) +&lt;br /&gt;
                ((llList2Vector(details, 2) - llList2Vector(details, 0)) / f) - &amp;lt;0.0, 0.0, 0.4&amp;gt;, f];&lt;br /&gt;
    }&lt;br /&gt;
    return [];&lt;br /&gt;
}//Written by Strife Onizuka&lt;br /&gt;
&amp;lt;/lsl&amp;gt;&lt;br /&gt;
Hi Strife! This version of your GetSitTarget, and the other version on the actual LlSitTarget page, both always return &amp;lt;0.000000, 0.000000, 0.707107, 0.707107&amp;gt; for the rotation. --[[User:MartinRJ Fayray|MartinRJ Fayray]] 07:52, 21 January 2013 (PST)&lt;br /&gt;
&lt;br /&gt;
:I haven&#039;t touched this in 5 years but I don&#039;t see a reason why it should be doing what you say. Are you sure you are using it properly? The prim parameter specifies what prim the location will be local to. The function was written to aid in determining sit targets when making furniture. You have the avatar sit on one object and then you get it&#039;s position local to the furniture so you can program in the sit target.&lt;br /&gt;
&lt;br /&gt;
:Just to clarify, you are saying that when you sit on an object with the following script in it, you don&#039;t get approximately the specified value? -- &#039;&#039;&#039;[[User:Strife_Onizuka|Strife]]&#039;&#039;&#039; &amp;lt;sup&amp;gt;&amp;lt;small&amp;gt;([[User talk:Strife_Onizuka|talk]]|[[Special:Contributions/Strife_Onizuka|contribs]])&amp;lt;/small&amp;gt;&amp;lt;/sup&amp;gt; 20:37, 22 January 2013 (PST)&lt;br /&gt;
&lt;br /&gt;
:It seems to work now. No idea what I was doing wrong. Thank you strife!--[[User:MartinRJ Fayray|MartinRJ Fayray]] 07:36, 3 February 2013 (PST)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;lsl&amp;gt;&lt;br /&gt;
vector vOffset = &amp;lt;0,0,1&amp;gt;;&lt;br /&gt;
rotation rOffset = &amp;lt;0,0,0,1&amp;gt;;&lt;br /&gt;
&lt;br /&gt;
list GetSitTarget(integer prim, key av)&lt;br /&gt;
{//WARNING: llGetObjectDetails can introduce an error that goes as far as the 5th decimal place!&lt;br /&gt;
 //This is highly unlikely to be ever noticed unless compounded over time.&lt;br /&gt;
 //Do not use while moving (like in a moving vehicle)!!!&lt;br /&gt;
    vector tp = llGetAgentSize(av);&lt;br /&gt;
    if(tp)&lt;br /&gt;
    {&lt;br /&gt;
        if(prim == LINK_THIS)//llGetLinkKey doesn&#039;t like LINK_THIS&lt;br /&gt;
            prim = llGetLinkNumber();&lt;br /&gt;
 &lt;br /&gt;
        list details = [OBJECT_POS, OBJECT_ROT];&lt;br /&gt;
        rotation f = llList2Rot(details = (llGetObjectDetails(llGetLinkKey(prim), details) + llGetObjectDetails(av, details)), 1);&lt;br /&gt;
        rotation r = llList2Rot(details, 3) / f;&lt;br /&gt;
 &lt;br /&gt;
        return [((llList2Vector(details, 2) - llList2Vector(details, 0)) / f) + (llRot2Up(r) * tp.z * 0.02638) - &amp;lt;0.0, 0.0, 0.4&amp;gt;, r];&lt;br /&gt;
    }&lt;br /&gt;
    return [];&lt;br /&gt;
}//Written by Strife Onizuka&lt;br /&gt;
&lt;br /&gt;
default{&lt;br /&gt;
    state_entry(){&lt;br /&gt;
        llSitTarget(vOffset, rOffset);&lt;br /&gt;
    }&lt;br /&gt;
    changed(integer change){&lt;br /&gt;
        key id = llAvatarOnSitTarget();&lt;br /&gt;
        if(id)&lt;br /&gt;
            llOwnerSay(&amp;quot;[&amp;quot;+llList2CSV([vOffset, rOffset]) +&amp;quot;] ~ [&amp;quot; + llList2CSV(GetSitTarget(LINK_THIS, id))+&amp;quot;]&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/lsl&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Note&#039;&#039;&#039;: the two scripts in this paragraph are incorrect. Most notably, the position of an avatar (it&#039;s Avatar Center) is NOT dependent on the AgentSize of the seated avatar. I added another script that returns the sit target below. [[User:Timmy Foxclaw|Timmy Foxclaw]] 10:31, 7 April 2014 (PDT)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;lsl&amp;gt;&lt;br /&gt;
// A script to develop and test sbGetLinkSitTarget&lt;br /&gt;
//&lt;br /&gt;
// Copyright(c) Timmy Songbird @DreamNation&lt;br /&gt;
//              Timmy Foxclaw  @SL,&lt;br /&gt;
//              2014&lt;br /&gt;
//&lt;br /&gt;
// This program is free software; you can redistribute it and/or modify&lt;br /&gt;
// it under the terms of the GNU General Public License as published by&lt;br /&gt;
// the Free Software Foundation; either version 2 of the License, or&lt;br /&gt;
// (at your option) any later version.&lt;br /&gt;
//&lt;br /&gt;
// This program is distributed in the hope that it will be useful,&lt;br /&gt;
// but WITHOUT ANY WARRANTY; without even the implied warranty of&lt;br /&gt;
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the&lt;br /&gt;
// GNU General Public License for more details.&lt;br /&gt;
//&lt;br /&gt;
// You should have received a copy of the GNU General Public License&lt;br /&gt;
// along with this program; if not, write to the Free Software&lt;br /&gt;
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307, USA.&#039;)&lt;br /&gt;
&lt;br /&gt;
//----------------------------------------------------------------------------&lt;br /&gt;
//#line &amp;quot;/opt/secondlife/scripts/scripts/tests/sbGetLinkSitTarget_Test.m4s:4&amp;quot;&lt;br /&gt;
// This script sets a &amp;quot;random&amp;quot;-ish sit target on every prim in an object.&lt;br /&gt;
// Recommended for your test is an object existing of two default cubes&lt;br /&gt;
// with arbitrary rotations and position. Put this script only in the&lt;br /&gt;
// root prim.&lt;br /&gt;
//&lt;br /&gt;
// The script sets the sit targets on compile or touch. Please touch&lt;br /&gt;
// the object after editting one of the prims.&lt;br /&gt;
//&lt;br /&gt;
// When an avatar (un)sits on one of the prims, the script prints for every&lt;br /&gt;
// sit target that has a seated avatar the return value of sbGetLinkSitTarget.&lt;br /&gt;
// This value should be (almost) equal to the values passed to llSitTarget.&lt;br /&gt;
&lt;br /&gt;
// Example output:&lt;br /&gt;
&lt;br /&gt;
// Object: [&amp;lt;0.200000, 0.300000, 0.500000&amp;gt;, &amp;lt;0.100000, 0.150000, 0.120000, 0.976268&amp;gt;] set with llSitTarget on 2 prims.&lt;br /&gt;
// Object: [&amp;lt;0.199999, 0.300001, 0.499999&amp;gt;, &amp;lt;0.100000, 0.150000, 0.120000, 0.976268&amp;gt;] returned by sbGetLinkSitTarget(1).&lt;br /&gt;
// Object: [&amp;lt;0.199998, 0.300002, 0.499998&amp;gt;, &amp;lt;0.100000, 0.150000, 0.120000, 0.976268&amp;gt;] returned by sbGetLinkSitTarget(2).&lt;br /&gt;
&lt;br /&gt;
// GitLocation: tests/sbGetLinkSitTarget_Test.m4s&lt;br /&gt;
&lt;br /&gt;
//----------------------------------------------------------------------------&lt;br /&gt;
//#line &amp;quot;/opt/secondlife/scripts/scripts/tests/sbGetLinkSitTarget_Test.m4s:26&amp;quot;&lt;br /&gt;
vector sitTarget_pos_link = &amp;lt;0.2, 0.3, 0.5&amp;gt;;&lt;br /&gt;
rotation sitTarget_rot_link = &amp;lt;0.1, 0.15, 0.12, 0.9762684&amp;gt;;&lt;br /&gt;
&lt;br /&gt;
//----------------------------------------------------------------------------&lt;br /&gt;
//#line &amp;quot;/opt/secondlife/scripts/scripts/tests/sbGetLinkSitTarget_Test.m4s:31&amp;quot;&lt;br /&gt;
// Returns the correct values to use for llSitTarget to make&lt;br /&gt;
// the currently seated avatar sit in the same way when re-seated.&lt;br /&gt;
// If no avatar is currently sitting then [ZERO_VECTOR, ZERO_ROTATION] is returned.&lt;br /&gt;
//&lt;br /&gt;
// [1] http://wiki.secondlife.com/wiki/User:Timmy_Foxclaw/About_Coordinate_Systems_and_Rotations#LSL_functions&lt;br /&gt;
// [2] http://wiki.secondlife.com/wiki/User:Timmy_Foxclaw/About_Coordinate_Systems_and_Rotations#Converting_between_coordinate_systems&lt;br /&gt;
list sbGetLinkSitTarget(integer link)&lt;br /&gt;
{&lt;br /&gt;
  // Calling llAvatarOnLinkSitTarget(0) always returns NULL_KEY because the link&lt;br /&gt;
  // number of an unlinked prim changes from 0 to 1 as soon as an avatar sits on&lt;br /&gt;
  // it. So if 0 was passed then they probably meant 1.&lt;br /&gt;
  if (link == 0)&lt;br /&gt;
  {&lt;br /&gt;
    link = 1;&lt;br /&gt;
  }&lt;br /&gt;
  key av = llAvatarOnLinkSitTarget(link);&lt;br /&gt;
  if (av != NULL_KEY)&lt;br /&gt;
  {&lt;br /&gt;
    // Get link_pos_oc and link_rot_oc. See table 2 in [1].&lt;br /&gt;
    vector link_pos_oc = ZERO_VECTOR;&lt;br /&gt;
    rotation link_rot_oc = ZERO_ROTATION;&lt;br /&gt;
    if (link &amp;gt; 1)&lt;br /&gt;
    {&lt;br /&gt;
      list params = llGetLinkPrimitiveParams(link, [PRIM_POS_LOCAL, PRIM_ROT_LOCAL]);&lt;br /&gt;
      link_pos_oc = llList2Vector(params, 0);&lt;br /&gt;
      link_rot_oc = llList2Rot(params, 1);&lt;br /&gt;
    }&lt;br /&gt;
    // Find the link number of the seated avatar.&lt;br /&gt;
    integer avNum = llGetNumberOfPrims();&lt;br /&gt;
    do&lt;br /&gt;
    {&lt;br /&gt;
        if (av == llGetLinkKey(avNum))&lt;br /&gt;
        {&lt;br /&gt;
            // Get ac_pos_oc and ac_rot_oc (ac stands for Avatar Center), exactly the same as above&lt;br /&gt;
            // except that we don&#039;t need to test if avNum &amp;gt; 1, because it always will be.&lt;br /&gt;
            list params = llGetLinkPrimitiveParams(avNum, [PRIM_POS_LOCAL, PRIM_ROT_LOCAL, PRIM_SIZE]);&lt;br /&gt;
            vector ac_pos_oc = llList2Vector(params, 0);&lt;br /&gt;
            rotation ac_rot_oc = llList2Rot(params, 1);&lt;br /&gt;
&lt;br /&gt;
            // We also obtained the agent size.&lt;br /&gt;
            vector agentSize = llList2Vector(params, 2);&lt;br /&gt;
&lt;br /&gt;
            // Convert that to link coordinates. See formula (3) in [2].&lt;br /&gt;
            vector ac_pos_link = (ac_pos_oc - link_pos_oc) / link_rot_oc;&lt;br /&gt;
            rotation ac_rot_link = ac_rot_oc / link_rot_oc;&lt;br /&gt;
&lt;br /&gt;
            // Now we have this little vector in the Avatar Center coordinates.&lt;br /&gt;
            vector sit_pos_ac = &amp;lt;0.0, 0.0, 0.05&amp;gt;;&lt;br /&gt;
&lt;br /&gt;
            // Convert that to link coordinates. See formula (1) in [2].&lt;br /&gt;
            vector sit_pos_link = sit_pos_ac * ac_rot_link + ac_pos_link;&lt;br /&gt;
&lt;br /&gt;
            // Return the values, accounting for the sit target bug of 0.4m.&lt;br /&gt;
            return [sit_pos_link - &amp;lt;0.0, 0.0, 0.4&amp;gt;, ac_rot_link];&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    while (--avNum);&lt;br /&gt;
  }&lt;br /&gt;
  return [ZERO_VECTOR, ZERO_ROTATION];&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
setSitTargets()&lt;br /&gt;
{&lt;br /&gt;
  // Set the same sit target on every prim.&lt;br /&gt;
  integer n = llGetNumberOfPrims();&lt;br /&gt;
  llSay(0, &amp;quot;[&amp;quot; +  llList2CSV([sitTarget_pos_link, sitTarget_rot_link]) + &amp;quot;] set with llSitTarget on &amp;quot; + (string)n + &amp;quot; prims.&amp;quot;);&lt;br /&gt;
  do&lt;br /&gt;
  {&lt;br /&gt;
    llLinkSitTarget(n, sitTarget_pos_link, sitTarget_rot_link);&lt;br /&gt;
  }&lt;br /&gt;
  while(--n);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
//----------------------------------------------------------------------------&lt;br /&gt;
//#line &amp;quot;/opt/secondlife/scripts/scripts/tests/sbGetLinkSitTarget_Test.m4s:105&amp;quot;&lt;br /&gt;
default&lt;br /&gt;
{&lt;br /&gt;
  state_entry()&lt;br /&gt;
  {&lt;br /&gt;
    setSitTargets();&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  touch_start(integer n)&lt;br /&gt;
  {&lt;br /&gt;
    setSitTargets();&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  changed(integer change)&lt;br /&gt;
  {&lt;br /&gt;
    if ((change &amp;amp; CHANGED_LINK))&lt;br /&gt;
    {&lt;br /&gt;
      integer n = llGetNumberOfPrims();&lt;br /&gt;
      do&lt;br /&gt;
      {&lt;br /&gt;
        key av = llAvatarOnLinkSitTarget(n);&lt;br /&gt;
        if (av != NULL_KEY)&lt;br /&gt;
        {&lt;br /&gt;
          llSay(0, &amp;quot;[&amp;quot; + llList2CSV(sbGetLinkSitTarget(n)) + &amp;quot;] returned by sbGetLinkSitTarget(&amp;quot; + (string)n + &amp;quot;).&amp;quot;);&lt;br /&gt;
        }&lt;br /&gt;
      }&lt;br /&gt;
      while(--n);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/lsl&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Using llSetLinkPrimitiveParams for skydiving: why limited to 5m in a linked set?==&lt;br /&gt;
llSetLinkPrimitiveParams can be used as a handy tool to adjust an avatar&#039;s position and rotation.&lt;br /&gt;
This works perfectly when the object consists of 1 prim, with a range for setting the avatar position away to 500m easily!&lt;br /&gt;
When there are more prims linked, this offset seems to be limited to 5m (measured with llVecDist). This is an awfull sideeffect!&lt;br /&gt;
&lt;br /&gt;
Put this next script inside a prim and sit on the prim, it will bring you to 1000.0 higher then the prim.&lt;br /&gt;
Next link this prim to another prim and try again. You will notice you are limited to 5m. My Question: why is this limited?&lt;br /&gt;
&amp;lt;lsl&amp;gt;&lt;br /&gt;
// by Randur Source&lt;br /&gt;
&lt;br /&gt;
integer heightcnt = 0;&lt;br /&gt;
list heights = [0.0, 1.0, 5.0, 6.0, 10.0, 100.0, 300.0, 500.0, 800.0, 1000.0];&lt;br /&gt;
&lt;br /&gt;
default&lt;br /&gt;
{&lt;br /&gt;
    state_entry()&lt;br /&gt;
    {&lt;br /&gt;
        llSitTarget(ZERO_VECTOR,ZERO_ROTATION); // Clear the current sittarget for a clear test&lt;br /&gt;
        llSetRot(ZERO_ROTATION); // set the prim to no rotation, for simple z axis movement&lt;br /&gt;
    }&lt;br /&gt;
    &lt;br /&gt;
    changed(integer change)&lt;br /&gt;
    {&lt;br /&gt;
        if (change &amp;amp; CHANGED_LINK) // detect linked prims and avatars&lt;br /&gt;
        {&lt;br /&gt;
            integer primnum = llGetNumberOfPrims(); // the avatar is the last linked prim&lt;br /&gt;
            if (primnum &amp;lt;= 1) // stop if there is only 1 prim&lt;br /&gt;
                return;&lt;br /&gt;
        &lt;br /&gt;
            key avatar = llGetLinkKey(primnum);&lt;br /&gt;
            if (llGetAgentSize(avatar) == ZERO_VECTOR) // stop if this is not an avatar&lt;br /&gt;
                return;&lt;br /&gt;
                &lt;br /&gt;
            // loop through the list of test heights:&lt;br /&gt;
            for (heightcnt = 0; heightcnt &amp;lt; llGetListLength(heights); heightcnt++)&lt;br /&gt;
            {&lt;br /&gt;
                float height = llList2Float(heights,heightcnt);&lt;br /&gt;
                llSetLinkPrimitiveParams(primnum,[PRIM_POSITION,&amp;lt;0.0,0.0,height&amp;gt;]); // set this to the wanted height using a vector z axis&lt;br /&gt;
                &lt;br /&gt;
                vector avatarpos = llList2Vector(llGetObjectDetails(avatar,[OBJECT_POS]),0); // detect the avatar position within the sim&lt;br /&gt;
                float distance = llVecDist(llGetPos(),avatarpos);&lt;br /&gt;
                llOwnerSay(&amp;quot;Attempt to move &amp;quot; + llKey2Name(llGetLinkKey(primnum)) +&lt;br /&gt;
                           &amp;quot; to &amp;quot; + (string)height + &amp;quot;m high resulting to &amp;quot; + (string)distance + &amp;quot;m&amp;quot;);&lt;br /&gt;
                &lt;br /&gt;
                llSleep(1.0);&lt;br /&gt;
            }&lt;br /&gt;
            llUnSit(avatar);&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/lsl&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Posted by Sylvio Runo : Answer &#039;&#039;&#039; :&lt;br /&gt;
The correct limit is 54 meters.&lt;br /&gt;
You can&#039;t move a linked object more than 54 meters away from the axis of the root prim.&lt;br /&gt;
On SecondLife (other grids like OsGrid, may works diferent) when an agent sit on prim, the agent is attached to it, so the agent is a linked prim of the link set.&lt;br /&gt;
&lt;br /&gt;
More information about link rules, you will find here : http://wiki.secondlife.com/wiki/Linkability_Rules [http://wiki.secondlife.com/wiki/Linkability_Rules]&lt;br /&gt;
&lt;br /&gt;
==UpdateSitTarget changes?==&lt;br /&gt;
I recently worked on a project where I used a version of this function, and it appears that it is a little off. A couple of things I noted: the Z-offset of the sit target is 0.35, not 0.4, and the avatar size doesn&#039;t seem to affect this position at all. When I used this function verbatim, I noticed discrepancies between the actual sit target and the set position call. When I changed the script as noted, I got a perfect match. Has the handling of the sit target been changed since this was written? [[User:Talarus Luan|Talarus Luan]] 22:57, 1 July 2009 (UTC)&lt;br /&gt;
:Seconded. I wish I&#039;d looked at this discussion before spending an hour on trying to figure out how the code actually behaved. -- [[User:Tonya Souther|Tonya Souther]] 15:11, 19 August 2009 (UTC)&lt;br /&gt;
&lt;br /&gt;
::This is news to me but I haven&#039;t been in world in ages :( -- &#039;&#039;&#039;[[User:Strife_Onizuka|Strife]]&#039;&#039;&#039; &amp;lt;sup&amp;gt;&amp;lt;small&amp;gt;([[User talk:Strife_Onizuka|talk]]|[[Special:Contributions/Strife_Onizuka|contribs]])&amp;lt;/small&amp;gt;&amp;lt;/sup&amp;gt; 22:56, 20 August 2009 (UTC)&lt;br /&gt;
&lt;br /&gt;
:::From some quick testing in 1.40, this seems to be how the &amp;quot;true&amp;quot; offset is computed:&lt;br /&gt;
:::1. Start with offset as provided by LSL.&lt;br /&gt;
:::2. Add &amp;lt; 0.0 , 0.0 , 0.4 &amp;gt;&lt;br /&gt;
:::3. Subtract llRot2Up( rot ) * 0.05&lt;br /&gt;
:::[[User:Gregory Maurer|--Gregory Maurer]] 20:00, 28 August 2010 (UTC)&lt;br /&gt;
&lt;br /&gt;
::::Confirmed. The following appears to work fine:&lt;br /&gt;
&amp;lt;lsl&amp;gt;llSetLinkPrimitiveParams(linkNum, [PRIM_POS_LOCAL, pos + &amp;lt;0.0, 0.0, 0.4&amp;gt; - (llRot2Up(rot) * 0.05), PRIM_ROT_LOCAL, rot]);&amp;lt;/lsl&amp;gt;&lt;br /&gt;
::::This of course using the new &amp;lt;code&amp;gt;PRIM_POS_LOCAL&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;PRIM_ROT_LOCAL&amp;lt;/code&amp;gt; values for simplicity. If one or two others can confirm that the above code works correctly, then I can splice it into the example.&amp;lt;br/&amp;gt;-- &#039;&#039;&#039;[[User:Haravikk_Mistral|Haravikk]]&#039;&#039;&#039; &amp;lt;sup&amp;gt;&amp;lt;small&amp;gt;([[User_talk:Haravikk_Mistral|talk]]|[[Special:Contributions/Haravikk_Mistral|contribs]])&amp;lt;/small&amp;gt;&amp;lt;/sup&amp;gt; 14:16, 26 December 2011 (PST)&lt;br /&gt;
&lt;br /&gt;
:::::Be sure to test it with avatars of different shapes, and shoe configurations. I recall that being an issue. {{User|Escort DeFarge}} would know about this best. -- &#039;&#039;&#039;[[User:Strife_Onizuka|Strife]]&#039;&#039;&#039; &amp;lt;sup&amp;gt;&amp;lt;small&amp;gt;([[User talk:Strife_Onizuka|talk]]|[[Special:Contributions/Strife_Onizuka|contribs]])&amp;lt;/small&amp;gt;&amp;lt;/sup&amp;gt; 22:05, 26 December 2011 (PST)&lt;br /&gt;
&lt;br /&gt;
::::::I tried with my two main avatar appearances, one average human height and one closer to 8 feet tall, and it didn&#039;t seem to make a difference. The test I used was a simple object with sit-target set, and a menu allowing it to be repositioned, causing the sit-target to move and if an avatar is seated on it, they will be repositioned using &amp;lt;code&amp;gt;llSetLinkPrimitiveParams()&amp;lt;/code&amp;gt; as done above. In my case the position of the avatar was consistent both when sitting on the object (using the sit-target) and being repositioned. Avatar height appears to have no effect, as the sit-target seems to define the avatar&#039;s hip-location, which is seemingly the avatar&#039;s &amp;quot;centre&amp;quot; when seated. I&#039;ll try to run some more tests when I get a chance, as it&#039;s possible this behaviour may not hold true if the object doesn&#039;t have a sit-target on it. The height of the avatar does however have a marked visual impact, depending exactly what you&#039;re trying to line up where, but that&#039;s a general issue with sitting on objects.&amp;lt;br/&amp;gt;-- &#039;&#039;&#039;[[User:Haravikk_Mistral|Haravikk]]&#039;&#039;&#039; &amp;lt;sup&amp;gt;&amp;lt;small&amp;gt;([[User_talk:Haravikk_Mistral|talk]]|[[Special:Contributions/Haravikk_Mistral|contribs]])&amp;lt;/small&amp;gt;&amp;lt;/sup&amp;gt; 05:38, 28 December 2011 (PST)&lt;br /&gt;
:::::::Sorry for my long delay in responding. Due to various RL issues and SL/LL burnout, I took a year off from SL to pursue other activities. That said, it seems to work fine to me, Haravikk; however, I have not done exhaustive testing with tons of different avs, shoes, etc. I would consider going ahead and changing it, because the version as it is right now is not correct for the majority of avatars, regardless. If Escort DeFarge or someone else wants to amend it later to include edge cases, that&#039;s great, but a better base accuracy is more important at this point. In fact, I think I will go ahead and edit it in, since it has been so long anyway.[[User:Talarus Luan|Talarus Luan]] 12:12, 5 July 2013 (PDT)&lt;br /&gt;
:::::::Holding up on the edit, further testing is revealing that if the script is in a prim other than the root, it is off by varying amounts depending on the rotation.[[User:Talarus Luan|Talarus Luan]] 12:39, 5 July 2013 (PDT)&lt;br /&gt;
:::::::OK, I think I found the error. Still need to keep the local position/rotation values for the child prim the script is in, like so:&lt;br /&gt;
&amp;lt;lsl&amp;gt;llSetLinkPrimitiveParams(linkNum, PRIM_POS_LOCAL, (pos + &amp;lt;0.0, 0.0, 0.4&amp;gt; - (llRot2Up(rot) * 0.05)) * localrot + localpos, PRIM_ROT_LOCAL, rot * localrot]);&amp;lt;/lsl&amp;gt;&lt;br /&gt;
:::::::I&#039;ll hold off on the edit until I can get another verify that this code is good.[[User:Talarus Luan|Talarus Luan]] 12:51, 5 July 2013 (PDT)&lt;br /&gt;
:::::::OK. I think I have analyzed this to death today and have come to the conclusion that Strife&#039;s original code is largely correct, but the error I am seeing comes from the &amp;quot;magic constants&amp;quot; 0.4 and 0.02638. Haravikk&#039;s code is simply a reduced form of Strife&#039;s code. The 0.4 magic constant is still there, but Haravikk is using just a close, but fixed, magic constant of 0.05 instead of Strife&#039;s (size.z * 0.02638), which comes out very close to 0.5 for most normal human avs. Thus, I am concluding that the inaccuracy is in the &amp;quot;magic constants&amp;quot; themselves, and I am going to hold off on the edit until I can get some more information on the source of these constants and see if there are better, more accurate values. It is annoying that, in all these years, we still haven&#039;t gotten LL to just tell us what the damn difference is between avatar sit targets and local position offsets in a linkset. It can&#039;t be that hard for someone who is familiar with the code to look at it and document it. -.- [[User:Talarus Luan|Talarus Luan]] 13:24, 5 July 2013 (PDT)&lt;br /&gt;
&lt;br /&gt;
::::::::Welcome back! I&#039;d like to take credit for that but that&#039;s the part that Escort contributed. As to where 0.02638 comes from, I vaguely recall it came from Escort&#039;s testing. I was driven more by &amp;quot;wouldn&#039;t it be cool to write a function that...&amp;quot; than anything else. I do agree the values have always been not quite right. -- &#039;&#039;&#039;[[User:Strife_Onizuka|Strife]]&#039;&#039;&#039; &amp;lt;sup&amp;gt;&amp;lt;small&amp;gt;([[User talk:Strife_Onizuka|talk]]|[[Special:Contributions/Strife_Onizuka|contribs]])&amp;lt;/small&amp;gt;&amp;lt;/sup&amp;gt; 23:10, 5 July 2013 (PDT)&lt;br /&gt;
:::::::::Thanks! OK, I did a bunch of empirical testing, sampling a bunch of avatars from 1.16m to 2.45m in height, as reported by llGetAgentSize. I picked the lowest and highest and one about standard height, and fitted a parabolic curve through them. I have reduced the inaccuracies to a great degree, but it still isn&#039;t 100% perfect for all sizes in that range, just the ones that I used to solve the curve equation. The rest show a *tiny* bit of movement, but they are very close. Obviously, the difference isn&#039;t parabolic, probably just some kind of discrete step function, but it works.[[User:Talarus Luan|Talarus Luan]] 11:16, 14 July 2013 (PDT)&lt;br /&gt;
&amp;lt;lsl&amp;gt;vector vCoefficients = &amp;lt;0.008906,-0.049831,0.088967&amp;gt;;&lt;br /&gt;
float fAdjust = vCoefficients.x * size.z * size.z + vCoefficients.y * size.z + vCoefficients.z;&lt;br /&gt;
llSetLinkPrimitiveParamsFast(linkNum,&lt;br /&gt;
    [PRIM_POS_LOCAL, (pos + &amp;lt;0.0, 0.0, 0.4&amp;gt; - (llRot2Up(rot) * size.z * fAdjust)) * localrot + localpos,&lt;br /&gt;
     PRIM_ROT_LOCAL, rot * localrot]);&amp;lt;/lsl&amp;gt;&lt;br /&gt;
&lt;br /&gt;
::::::::::I see you mind reading abilities haven&#039;t diminished (I contemplated suggesting the tests you have done, decided to go to bed instead). Any reason not to use parentheses? It looks like something that could get optimized to an a series of FMAs (by the VM). -- &#039;&#039;&#039;[[User:Strife_Onizuka|Strife]]&#039;&#039;&#039; &amp;lt;sup&amp;gt;&amp;lt;small&amp;gt;([[User talk:Strife_Onizuka|talk]]|[[Special:Contributions/Strife_Onizuka|contribs]])&amp;lt;/small&amp;gt;&amp;lt;/sup&amp;gt; 21:33, 14 July 2013 (PDT)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;lsl&amp;gt;vector vCoefficients = &amp;lt;0.008906,-0.049831,0.088967&amp;gt;;&lt;br /&gt;
float fAdjust = ((((vCoefficients.x * size.z) + vCoefficients.y) * size.z) + vCoefficients.z) * size.z;&lt;br /&gt;
llSetLinkPrimitiveParamsFast(linkNum,&lt;br /&gt;
    [PRIM_POS_LOCAL, (pos + &amp;lt;0.0, 0.0, 0.4&amp;gt; - (llRot2Up(rot) * fAdjust)) * localrot + localpos,&lt;br /&gt;
     PRIM_ROT_LOCAL, rot * localrot]);&amp;lt;/lsl&amp;gt;&lt;br /&gt;
:::::::::::Yeah, I thought about optimizing it a bit after I posted it, but decided to leave it unoptimized here so the path from the current function to this change was clear, for demonstrability purposes. Besides, I had to leave some room for it to be Strifed&amp;amp;trade;. :P [[User:Talarus Luan|Talarus Luan]] 15:17, 17 July 2013 (PDT)&lt;br /&gt;
&lt;br /&gt;
::::::::::::I appreciate the gesture :p and I&#039;m not as bad as I use to be. I&#039;m not going to optimize out fAdjust, it&#039;s more readable this way. This is more for myself later as my memory is crap, the reasoning behind using llRot2Up is that it solves the pesky problem of the quaternion not having a magnitude of one. While the following isn&#039;t optimal, it is cool. -- &#039;&#039;&#039;[[User:Strife_Onizuka|Strife]]&#039;&#039;&#039; &amp;lt;sup&amp;gt;&amp;lt;small&amp;gt;([[User talk:Strife_Onizuka|talk]]|[[Special:Contributions/Strife_Onizuka|contribs]])&amp;lt;/small&amp;gt;&amp;lt;/sup&amp;gt; 00:00, 18 July 2013 (PDT)&lt;br /&gt;
&amp;lt;lsl&amp;gt;&lt;br /&gt;
size.x = (size.z * (size.y = (size.z * size.z)));&lt;br /&gt;
float fAdjust = vCoefficients * size;&lt;br /&gt;
&amp;lt;/lsl&amp;gt;&lt;br /&gt;
:::::::::::::Yeah, that is a nice way to represent it, for those used to the LSL representation for vector dot product. I&#039;m a little less enthused about the size vector assignment chain, but that&#039;s just my general dislike for C value assignments and such. In my mind, I separate assignments from expressions, so seeing them mixed together causes a bit of a train wreck in my brain&#039;s lexical analyzer. :P[[User:Talarus Luan|Talarus Luan]] 10:00, 21 July 2013 (PDT)&lt;br /&gt;
&lt;br /&gt;
::::::::::::::I don&#039;t think anyone uses the LSL vector dot product. It took me three days to remember it existed and then I look up the syntax just to make sure I wasn&#039;t crazy (yes yes, I agree it&#039;s insane to think that looking up the syntax of an obscure feature is proof against insanity but I&#039;m sticking to it, my cat agrees). I think a train wreck was my goal. -- &#039;&#039;&#039;[[User:Strife_Onizuka|Strife]]&#039;&#039;&#039; &amp;lt;sup&amp;gt;&amp;lt;small&amp;gt;([[User talk:Strife_Onizuka|talk]]|[[Special:Contributions/Strife_Onizuka|contribs]])&amp;lt;/small&amp;gt;&amp;lt;/sup&amp;gt; 11:13, 21 July 2013 (PDT)&lt;br /&gt;
&lt;br /&gt;
== Avatars Floating After Sit ==&lt;br /&gt;
&lt;br /&gt;
The position of avatars will sometimes change, generally noticeable as a rise on the Z axis of perhaps half a meter - common triggers for this is typing or another AV sitting on the same object - though these are not exhaustive.  Does anyone have a clue why this happens, and how to prevent it from happening? [[User:TaraLi Jie|TaraLi Jie]] 21:14, 11 March 2012 (PDT)&lt;br /&gt;
&lt;br /&gt;
:Hmm, there are a few possible causes, but the main cause are the animations involved, so it&#039;s worth remembering that any animation overrider can potentially cause weirdness while on a sit-target, which is why most good ones can turn themselves off while seated. It&#039;s a bit difficult to describe specific problems with animations, but I think that sometimes it can be caused by animations that have a weird first frame, since it&#039;s used to calculate all the offsets etc. for the rest of the animation; normally this will be a neutral pose since you don&#039;t actually see it in the animation, but if it&#039;s something odd then it can mess with positioning. -- &amp;lt;br/&amp;gt;-- &#039;&#039;&#039;[[User:Haravikk_Mistral|Haravikk]]&#039;&#039;&#039; &amp;lt;sup&amp;gt;&amp;lt;small&amp;gt;([[User_talk:Haravikk_Mistral|talk]]|[[Special:Contributions/Haravikk_Mistral|contribs]])&amp;lt;/small&amp;gt;&amp;lt;/sup&amp;gt; 05:34, 12 March 2012 (PDT)&lt;br /&gt;
&lt;br /&gt;
::When I&#039;ve had problems with this, the root cause has usually been that I&#039;ve (or something has) inadvertently stopped an animation that&#039;s holding the avatar in place before starting another one.   Because animations are all made differently, neither the animator with whom I work most of the time nor I have ever managed to figure out exactly what to avoid, but certainly when it happens to me, I always start debugging by looking very carefully at where I&#039;m turning animations off and considering whether, in fact, I need to turn them off at all.   Quite often, I find that simply turning off the default sit animation when my first animation starts, and then keeping the first animation going throughout, starting and stopping other ones over it, as necessary, solves the problem.&lt;br /&gt;
&lt;br /&gt;
::One &amp;quot;gotcha&amp;quot; is that stopping an animation and then immediately restarting it doesn&#039;t work.  It confuses the viewer something horrible, and often leads to people floating in mid-air.  [[User:Innula Zenovka|Innula Zenovka]] 09:04, 12 March 2012 (PDT)&lt;br /&gt;
&lt;br /&gt;
== Sit Target 0.4m &#039;bug&#039; ==&lt;br /&gt;
The notes say &lt;br /&gt;
&amp;quot;rot affects the position of the sit-target in a buggy way way.&lt;br /&gt;
To correct for the rot bug, simply subtract &amp;lt;0,0,0.4&amp;gt; from the position when rot is zero. See example below.&amp;quot;&lt;br /&gt;
&lt;br /&gt;
But the example script adjusts z by 0.4m when rotation is NOT zero.&lt;br /&gt;
&amp;lt;lsl&amp;gt;&lt;br /&gt;
if (rot!=ZERO_ROTATION) pos -=&amp;lt;0,0,0.4&amp;gt;;  //here is the work around&lt;br /&gt;
&amp;lt;/lsl&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Which should it be?&lt;br /&gt;
&lt;br /&gt;
I&#039;ve just been doing some tests without any 0.4m adjustment, and I am unable to observe any difference in my z position whether rotation is zero or not. Has something changed? If so, wouldn&#039;t the change screw up some furniture?&lt;br /&gt;
[[User:Omei Qunhua|Omei Qunhua]] 14:09, 16 March 2014 (PDT)&lt;br /&gt;
&lt;br /&gt;
:You are right, there shouldn&#039;t be a test there. My understanding is that you always need to subtract 0.4 from z. Changing it would screw up furniture. -- &#039;&#039;&#039;[[User:Strife_Onizuka|Strife]]&#039;&#039;&#039; &amp;lt;sup&amp;gt;&amp;lt;small&amp;gt;([[User talk:Strife_Onizuka|talk]]|[[Special:Contributions/Strife_Onizuka|contribs]])&amp;lt;/small&amp;gt;&amp;lt;/sup&amp;gt; 21:02, 16 March 2014 (PDT)&lt;/div&gt;</summary>
		<author><name>Timmy Foxclaw</name></author>
	</entry>
	<entry>
		<id>https://wiki.secondlife.com/w/index.php?title=Talk:LlSitTarget&amp;diff=1189253</id>
		<title>Talk:LlSitTarget</title>
		<link rel="alternate" type="text/html" href="https://wiki.secondlife.com/w/index.php?title=Talk:LlSitTarget&amp;diff=1189253"/>
		<updated>2014-04-07T17:31:46Z</updated>

		<summary type="html">&lt;p&gt;Timmy Foxclaw: Added a remark that the shown scripts do not (anymore) work.&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Unsitting on wrong side or camera rotation ==&lt;br /&gt;
&lt;br /&gt;
Hi, i am getting frustrated with this. I create a board and set the sit target with&lt;br /&gt;
&amp;lt;code&amp;gt;llSitTarget(&amp;lt;0.4, 0.0, 0.0&amp;gt;, ZERO_ROTATION);&amp;lt;/code&amp;gt;&lt;br /&gt;
and an animation which for &amp;quot;standing&amp;quot;. So while the person technical sits, she stands in front of the board. &lt;br /&gt;
But I have a problem with that: If the board stand freely, the person unsits right through it towards the other side. I can put the board with the back  facing a large wall. In the case the unsitting is correctly in front of it. But on sit down the camera rotates, so that it is behind the avatar again; on the other side of the wall.&lt;br /&gt;
&lt;br /&gt;
If anyone has an idea how to fix, please tell me (even if it is just an idea where to look for more information). --[[User:Maike Short|Maike Short]] 12:41, 24 February 2008 (PST)&lt;br /&gt;
&lt;br /&gt;
:You could position the camera with the {{LSLGC|Camera}} functions.  -- [[User:Strife Onizuka|Strife Onizuka]] 04:46, 25 February 2008 (PST)&lt;br /&gt;
&lt;br /&gt;
==Optimization==&lt;br /&gt;
&amp;lt;lsl&amp;gt;&lt;br /&gt;
list GetSitTarget(integer prim, key av)&lt;br /&gt;
{//WARNING: llGetObjectDetails can introduce an error that goes as far as the 5th decimal place.&lt;br /&gt;
    vector tp = llGetAgentSize(av);&lt;br /&gt;
    if(tp)&lt;br /&gt;
    {&lt;br /&gt;
        if(prim == LINK_THIS)//llGetLinkKey doesn&#039;t like LINK_THIS&lt;br /&gt;
            prim = llGetLinkNumber();&lt;br /&gt;
    &lt;br /&gt;
        list details = OBJECT_POS + (list)OBJECT_ROT;&lt;br /&gt;
        rotation f = llList2Rot(details = (llGetObjectDetails(llGetLinkKey(prim), details) + llGetObjectDetails(av, details)), 1);&lt;br /&gt;
    &lt;br /&gt;
        return [(llRot2Up(f = (llList2Rot(details, 3) / f)) * tp.z * 0.02638) +&lt;br /&gt;
                ((llList2Vector(details, 2) - llList2Vector(details, 0)) / f) - &amp;lt;0.0, 0.0, 0.4&amp;gt;, f];&lt;br /&gt;
    }&lt;br /&gt;
    return [];&lt;br /&gt;
}//Written by Strife Onizuka&lt;br /&gt;
&amp;lt;/lsl&amp;gt;&lt;br /&gt;
Hi Strife! This version of your GetSitTarget, and the other version on the actual LlSitTarget page, both always return &amp;lt;0.000000, 0.000000, 0.707107, 0.707107&amp;gt; for the rotation. --[[User:MartinRJ Fayray|MartinRJ Fayray]] 07:52, 21 January 2013 (PST)&lt;br /&gt;
&lt;br /&gt;
:I haven&#039;t touched this in 5 years but I don&#039;t see a reason why it should be doing what you say. Are you sure you are using it properly? The prim parameter specifies what prim the location will be local to. The function was written to aid in determining sit targets when making furniture. You have the avatar sit on one object and then you get it&#039;s position local to the furniture so you can program in the sit target.&lt;br /&gt;
&lt;br /&gt;
:Just to clarify, you are saying that when you sit on an object with the following script in it, you don&#039;t get approximately the specified value? -- &#039;&#039;&#039;[[User:Strife_Onizuka|Strife]]&#039;&#039;&#039; &amp;lt;sup&amp;gt;&amp;lt;small&amp;gt;([[User talk:Strife_Onizuka|talk]]|[[Special:Contributions/Strife_Onizuka|contribs]])&amp;lt;/small&amp;gt;&amp;lt;/sup&amp;gt; 20:37, 22 January 2013 (PST)&lt;br /&gt;
&lt;br /&gt;
:It seems to work now. No idea what I was doing wrong. Thank you strife!--[[User:MartinRJ Fayray|MartinRJ Fayray]] 07:36, 3 February 2013 (PST)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;lsl&amp;gt;&lt;br /&gt;
vector vOffset = &amp;lt;0,0,1&amp;gt;;&lt;br /&gt;
rotation rOffset = &amp;lt;0,0,0,1&amp;gt;;&lt;br /&gt;
&lt;br /&gt;
list GetSitTarget(integer prim, key av)&lt;br /&gt;
{//WARNING: llGetObjectDetails can introduce an error that goes as far as the 5th decimal place!&lt;br /&gt;
 //This is highly unlikely to be ever noticed unless compounded over time.&lt;br /&gt;
 //Do not use while moving (like in a moving vehicle)!!!&lt;br /&gt;
    vector tp = llGetAgentSize(av);&lt;br /&gt;
    if(tp)&lt;br /&gt;
    {&lt;br /&gt;
        if(prim == LINK_THIS)//llGetLinkKey doesn&#039;t like LINK_THIS&lt;br /&gt;
            prim = llGetLinkNumber();&lt;br /&gt;
 &lt;br /&gt;
        list details = [OBJECT_POS, OBJECT_ROT];&lt;br /&gt;
        rotation f = llList2Rot(details = (llGetObjectDetails(llGetLinkKey(prim), details) + llGetObjectDetails(av, details)), 1);&lt;br /&gt;
        rotation r = llList2Rot(details, 3) / f;&lt;br /&gt;
 &lt;br /&gt;
        return [((llList2Vector(details, 2) - llList2Vector(details, 0)) / f) + (llRot2Up(r) * tp.z * 0.02638) - &amp;lt;0.0, 0.0, 0.4&amp;gt;, r];&lt;br /&gt;
    }&lt;br /&gt;
    return [];&lt;br /&gt;
}//Written by Strife Onizuka&lt;br /&gt;
&lt;br /&gt;
default{&lt;br /&gt;
    state_entry(){&lt;br /&gt;
        llSitTarget(vOffset, rOffset);&lt;br /&gt;
    }&lt;br /&gt;
    changed(integer change){&lt;br /&gt;
        key id = llAvatarOnSitTarget();&lt;br /&gt;
        if(id)&lt;br /&gt;
            llOwnerSay(&amp;quot;[&amp;quot;+llList2CSV([vOffset, rOffset]) +&amp;quot;] ~ [&amp;quot; + llList2CSV(GetSitTarget(LINK_THIS, id))+&amp;quot;]&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/lsl&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Note&#039;&#039;&#039;: the two scripts in this paragraph are incorrect. Most notably, the position of an avatar (it&#039;s Avatar Center) is NOT dependent on the AgentSize of the seated avatar. I added another script that returns the sit target below. [[User:Timmy Foxclaw|Timmy Foxclaw]] 10:31, 7 April 2014 (PDT)&lt;br /&gt;
&lt;br /&gt;
==Using llSetLinkPrimitiveParams for skydiving: why limited to 5m in a linked set?==&lt;br /&gt;
llSetLinkPrimitiveParams can be used as a handy tool to adjust an avatar&#039;s position and rotation.&lt;br /&gt;
This works perfectly when the object consists of 1 prim, with a range for setting the avatar position away to 500m easily!&lt;br /&gt;
When there are more prims linked, this offset seems to be limited to 5m (measured with llVecDist). This is an awfull sideeffect!&lt;br /&gt;
&lt;br /&gt;
Put this next script inside a prim and sit on the prim, it will bring you to 1000.0 higher then the prim.&lt;br /&gt;
Next link this prim to another prim and try again. You will notice you are limited to 5m. My Question: why is this limited?&lt;br /&gt;
&amp;lt;lsl&amp;gt;&lt;br /&gt;
// by Randur Source&lt;br /&gt;
&lt;br /&gt;
integer heightcnt = 0;&lt;br /&gt;
list heights = [0.0, 1.0, 5.0, 6.0, 10.0, 100.0, 300.0, 500.0, 800.0, 1000.0];&lt;br /&gt;
&lt;br /&gt;
default&lt;br /&gt;
{&lt;br /&gt;
    state_entry()&lt;br /&gt;
    {&lt;br /&gt;
        llSitTarget(ZERO_VECTOR,ZERO_ROTATION); // Clear the current sittarget for a clear test&lt;br /&gt;
        llSetRot(ZERO_ROTATION); // set the prim to no rotation, for simple z axis movement&lt;br /&gt;
    }&lt;br /&gt;
    &lt;br /&gt;
    changed(integer change)&lt;br /&gt;
    {&lt;br /&gt;
        if (change &amp;amp; CHANGED_LINK) // detect linked prims and avatars&lt;br /&gt;
        {&lt;br /&gt;
            integer primnum = llGetNumberOfPrims(); // the avatar is the last linked prim&lt;br /&gt;
            if (primnum &amp;lt;= 1) // stop if there is only 1 prim&lt;br /&gt;
                return;&lt;br /&gt;
        &lt;br /&gt;
            key avatar = llGetLinkKey(primnum);&lt;br /&gt;
            if (llGetAgentSize(avatar) == ZERO_VECTOR) // stop if this is not an avatar&lt;br /&gt;
                return;&lt;br /&gt;
                &lt;br /&gt;
            // loop through the list of test heights:&lt;br /&gt;
            for (heightcnt = 0; heightcnt &amp;lt; llGetListLength(heights); heightcnt++)&lt;br /&gt;
            {&lt;br /&gt;
                float height = llList2Float(heights,heightcnt);&lt;br /&gt;
                llSetLinkPrimitiveParams(primnum,[PRIM_POSITION,&amp;lt;0.0,0.0,height&amp;gt;]); // set this to the wanted height using a vector z axis&lt;br /&gt;
                &lt;br /&gt;
                vector avatarpos = llList2Vector(llGetObjectDetails(avatar,[OBJECT_POS]),0); // detect the avatar position within the sim&lt;br /&gt;
                float distance = llVecDist(llGetPos(),avatarpos);&lt;br /&gt;
                llOwnerSay(&amp;quot;Attempt to move &amp;quot; + llKey2Name(llGetLinkKey(primnum)) +&lt;br /&gt;
                           &amp;quot; to &amp;quot; + (string)height + &amp;quot;m high resulting to &amp;quot; + (string)distance + &amp;quot;m&amp;quot;);&lt;br /&gt;
                &lt;br /&gt;
                llSleep(1.0);&lt;br /&gt;
            }&lt;br /&gt;
            llUnSit(avatar);&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/lsl&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Posted by Sylvio Runo : Answer &#039;&#039;&#039; :&lt;br /&gt;
The correct limit is 54 meters.&lt;br /&gt;
You can&#039;t move a linked object more than 54 meters away from the axis of the root prim.&lt;br /&gt;
On SecondLife (other grids like OsGrid, may works diferent) when an agent sit on prim, the agent is attached to it, so the agent is a linked prim of the link set.&lt;br /&gt;
&lt;br /&gt;
More information about link rules, you will find here : http://wiki.secondlife.com/wiki/Linkability_Rules [http://wiki.secondlife.com/wiki/Linkability_Rules]&lt;br /&gt;
&lt;br /&gt;
==UpdateSitTarget changes?==&lt;br /&gt;
I recently worked on a project where I used a version of this function, and it appears that it is a little off. A couple of things I noted: the Z-offset of the sit target is 0.35, not 0.4, and the avatar size doesn&#039;t seem to affect this position at all. When I used this function verbatim, I noticed discrepancies between the actual sit target and the set position call. When I changed the script as noted, I got a perfect match. Has the handling of the sit target been changed since this was written? [[User:Talarus Luan|Talarus Luan]] 22:57, 1 July 2009 (UTC)&lt;br /&gt;
:Seconded. I wish I&#039;d looked at this discussion before spending an hour on trying to figure out how the code actually behaved. -- [[User:Tonya Souther|Tonya Souther]] 15:11, 19 August 2009 (UTC)&lt;br /&gt;
&lt;br /&gt;
::This is news to me but I haven&#039;t been in world in ages :( -- &#039;&#039;&#039;[[User:Strife_Onizuka|Strife]]&#039;&#039;&#039; &amp;lt;sup&amp;gt;&amp;lt;small&amp;gt;([[User talk:Strife_Onizuka|talk]]|[[Special:Contributions/Strife_Onizuka|contribs]])&amp;lt;/small&amp;gt;&amp;lt;/sup&amp;gt; 22:56, 20 August 2009 (UTC)&lt;br /&gt;
&lt;br /&gt;
:::From some quick testing in 1.40, this seems to be how the &amp;quot;true&amp;quot; offset is computed:&lt;br /&gt;
:::1. Start with offset as provided by LSL.&lt;br /&gt;
:::2. Add &amp;lt; 0.0 , 0.0 , 0.4 &amp;gt;&lt;br /&gt;
:::3. Subtract llRot2Up( rot ) * 0.05&lt;br /&gt;
:::[[User:Gregory Maurer|--Gregory Maurer]] 20:00, 28 August 2010 (UTC)&lt;br /&gt;
&lt;br /&gt;
::::Confirmed. The following appears to work fine:&lt;br /&gt;
&amp;lt;lsl&amp;gt;llSetLinkPrimitiveParams(linkNum, [PRIM_POS_LOCAL, pos + &amp;lt;0.0, 0.0, 0.4&amp;gt; - (llRot2Up(rot) * 0.05), PRIM_ROT_LOCAL, rot]);&amp;lt;/lsl&amp;gt;&lt;br /&gt;
::::This of course using the new &amp;lt;code&amp;gt;PRIM_POS_LOCAL&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;PRIM_ROT_LOCAL&amp;lt;/code&amp;gt; values for simplicity. If one or two others can confirm that the above code works correctly, then I can splice it into the example.&amp;lt;br/&amp;gt;-- &#039;&#039;&#039;[[User:Haravikk_Mistral|Haravikk]]&#039;&#039;&#039; &amp;lt;sup&amp;gt;&amp;lt;small&amp;gt;([[User_talk:Haravikk_Mistral|talk]]|[[Special:Contributions/Haravikk_Mistral|contribs]])&amp;lt;/small&amp;gt;&amp;lt;/sup&amp;gt; 14:16, 26 December 2011 (PST)&lt;br /&gt;
&lt;br /&gt;
:::::Be sure to test it with avatars of different shapes, and shoe configurations. I recall that being an issue. {{User|Escort DeFarge}} would know about this best. -- &#039;&#039;&#039;[[User:Strife_Onizuka|Strife]]&#039;&#039;&#039; &amp;lt;sup&amp;gt;&amp;lt;small&amp;gt;([[User talk:Strife_Onizuka|talk]]|[[Special:Contributions/Strife_Onizuka|contribs]])&amp;lt;/small&amp;gt;&amp;lt;/sup&amp;gt; 22:05, 26 December 2011 (PST)&lt;br /&gt;
&lt;br /&gt;
::::::I tried with my two main avatar appearances, one average human height and one closer to 8 feet tall, and it didn&#039;t seem to make a difference. The test I used was a simple object with sit-target set, and a menu allowing it to be repositioned, causing the sit-target to move and if an avatar is seated on it, they will be repositioned using &amp;lt;code&amp;gt;llSetLinkPrimitiveParams()&amp;lt;/code&amp;gt; as done above. In my case the position of the avatar was consistent both when sitting on the object (using the sit-target) and being repositioned. Avatar height appears to have no effect, as the sit-target seems to define the avatar&#039;s hip-location, which is seemingly the avatar&#039;s &amp;quot;centre&amp;quot; when seated. I&#039;ll try to run some more tests when I get a chance, as it&#039;s possible this behaviour may not hold true if the object doesn&#039;t have a sit-target on it. The height of the avatar does however have a marked visual impact, depending exactly what you&#039;re trying to line up where, but that&#039;s a general issue with sitting on objects.&amp;lt;br/&amp;gt;-- &#039;&#039;&#039;[[User:Haravikk_Mistral|Haravikk]]&#039;&#039;&#039; &amp;lt;sup&amp;gt;&amp;lt;small&amp;gt;([[User_talk:Haravikk_Mistral|talk]]|[[Special:Contributions/Haravikk_Mistral|contribs]])&amp;lt;/small&amp;gt;&amp;lt;/sup&amp;gt; 05:38, 28 December 2011 (PST)&lt;br /&gt;
:::::::Sorry for my long delay in responding. Due to various RL issues and SL/LL burnout, I took a year off from SL to pursue other activities. That said, it seems to work fine to me, Haravikk; however, I have not done exhaustive testing with tons of different avs, shoes, etc. I would consider going ahead and changing it, because the version as it is right now is not correct for the majority of avatars, regardless. If Escort DeFarge or someone else wants to amend it later to include edge cases, that&#039;s great, but a better base accuracy is more important at this point. In fact, I think I will go ahead and edit it in, since it has been so long anyway.[[User:Talarus Luan|Talarus Luan]] 12:12, 5 July 2013 (PDT)&lt;br /&gt;
:::::::Holding up on the edit, further testing is revealing that if the script is in a prim other than the root, it is off by varying amounts depending on the rotation.[[User:Talarus Luan|Talarus Luan]] 12:39, 5 July 2013 (PDT)&lt;br /&gt;
:::::::OK, I think I found the error. Still need to keep the local position/rotation values for the child prim the script is in, like so:&lt;br /&gt;
&amp;lt;lsl&amp;gt;llSetLinkPrimitiveParams(linkNum, PRIM_POS_LOCAL, (pos + &amp;lt;0.0, 0.0, 0.4&amp;gt; - (llRot2Up(rot) * 0.05)) * localrot + localpos, PRIM_ROT_LOCAL, rot * localrot]);&amp;lt;/lsl&amp;gt;&lt;br /&gt;
:::::::I&#039;ll hold off on the edit until I can get another verify that this code is good.[[User:Talarus Luan|Talarus Luan]] 12:51, 5 July 2013 (PDT)&lt;br /&gt;
:::::::OK. I think I have analyzed this to death today and have come to the conclusion that Strife&#039;s original code is largely correct, but the error I am seeing comes from the &amp;quot;magic constants&amp;quot; 0.4 and 0.02638. Haravikk&#039;s code is simply a reduced form of Strife&#039;s code. The 0.4 magic constant is still there, but Haravikk is using just a close, but fixed, magic constant of 0.05 instead of Strife&#039;s (size.z * 0.02638), which comes out very close to 0.5 for most normal human avs. Thus, I am concluding that the inaccuracy is in the &amp;quot;magic constants&amp;quot; themselves, and I am going to hold off on the edit until I can get some more information on the source of these constants and see if there are better, more accurate values. It is annoying that, in all these years, we still haven&#039;t gotten LL to just tell us what the damn difference is between avatar sit targets and local position offsets in a linkset. It can&#039;t be that hard for someone who is familiar with the code to look at it and document it. -.- [[User:Talarus Luan|Talarus Luan]] 13:24, 5 July 2013 (PDT)&lt;br /&gt;
&lt;br /&gt;
::::::::Welcome back! I&#039;d like to take credit for that but that&#039;s the part that Escort contributed. As to where 0.02638 comes from, I vaguely recall it came from Escort&#039;s testing. I was driven more by &amp;quot;wouldn&#039;t it be cool to write a function that...&amp;quot; than anything else. I do agree the values have always been not quite right. -- &#039;&#039;&#039;[[User:Strife_Onizuka|Strife]]&#039;&#039;&#039; &amp;lt;sup&amp;gt;&amp;lt;small&amp;gt;([[User talk:Strife_Onizuka|talk]]|[[Special:Contributions/Strife_Onizuka|contribs]])&amp;lt;/small&amp;gt;&amp;lt;/sup&amp;gt; 23:10, 5 July 2013 (PDT)&lt;br /&gt;
:::::::::Thanks! OK, I did a bunch of empirical testing, sampling a bunch of avatars from 1.16m to 2.45m in height, as reported by llGetAgentSize. I picked the lowest and highest and one about standard height, and fitted a parabolic curve through them. I have reduced the inaccuracies to a great degree, but it still isn&#039;t 100% perfect for all sizes in that range, just the ones that I used to solve the curve equation. The rest show a *tiny* bit of movement, but they are very close. Obviously, the difference isn&#039;t parabolic, probably just some kind of discrete step function, but it works.[[User:Talarus Luan|Talarus Luan]] 11:16, 14 July 2013 (PDT)&lt;br /&gt;
&amp;lt;lsl&amp;gt;vector vCoefficients = &amp;lt;0.008906,-0.049831,0.088967&amp;gt;;&lt;br /&gt;
float fAdjust = vCoefficients.x * size.z * size.z + vCoefficients.y * size.z + vCoefficients.z;&lt;br /&gt;
llSetLinkPrimitiveParamsFast(linkNum,&lt;br /&gt;
    [PRIM_POS_LOCAL, (pos + &amp;lt;0.0, 0.0, 0.4&amp;gt; - (llRot2Up(rot) * size.z * fAdjust)) * localrot + localpos,&lt;br /&gt;
     PRIM_ROT_LOCAL, rot * localrot]);&amp;lt;/lsl&amp;gt;&lt;br /&gt;
&lt;br /&gt;
::::::::::I see you mind reading abilities haven&#039;t diminished (I contemplated suggesting the tests you have done, decided to go to bed instead). Any reason not to use parentheses? It looks like something that could get optimized to an a series of FMAs (by the VM). -- &#039;&#039;&#039;[[User:Strife_Onizuka|Strife]]&#039;&#039;&#039; &amp;lt;sup&amp;gt;&amp;lt;small&amp;gt;([[User talk:Strife_Onizuka|talk]]|[[Special:Contributions/Strife_Onizuka|contribs]])&amp;lt;/small&amp;gt;&amp;lt;/sup&amp;gt; 21:33, 14 July 2013 (PDT)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;lsl&amp;gt;vector vCoefficients = &amp;lt;0.008906,-0.049831,0.088967&amp;gt;;&lt;br /&gt;
float fAdjust = ((((vCoefficients.x * size.z) + vCoefficients.y) * size.z) + vCoefficients.z) * size.z;&lt;br /&gt;
llSetLinkPrimitiveParamsFast(linkNum,&lt;br /&gt;
    [PRIM_POS_LOCAL, (pos + &amp;lt;0.0, 0.0, 0.4&amp;gt; - (llRot2Up(rot) * fAdjust)) * localrot + localpos,&lt;br /&gt;
     PRIM_ROT_LOCAL, rot * localrot]);&amp;lt;/lsl&amp;gt;&lt;br /&gt;
:::::::::::Yeah, I thought about optimizing it a bit after I posted it, but decided to leave it unoptimized here so the path from the current function to this change was clear, for demonstrability purposes. Besides, I had to leave some room for it to be Strifed&amp;amp;trade;. :P [[User:Talarus Luan|Talarus Luan]] 15:17, 17 July 2013 (PDT)&lt;br /&gt;
&lt;br /&gt;
::::::::::::I appreciate the gesture :p and I&#039;m not as bad as I use to be. I&#039;m not going to optimize out fAdjust, it&#039;s more readable this way. This is more for myself later as my memory is crap, the reasoning behind using llRot2Up is that it solves the pesky problem of the quaternion not having a magnitude of one. While the following isn&#039;t optimal, it is cool. -- &#039;&#039;&#039;[[User:Strife_Onizuka|Strife]]&#039;&#039;&#039; &amp;lt;sup&amp;gt;&amp;lt;small&amp;gt;([[User talk:Strife_Onizuka|talk]]|[[Special:Contributions/Strife_Onizuka|contribs]])&amp;lt;/small&amp;gt;&amp;lt;/sup&amp;gt; 00:00, 18 July 2013 (PDT)&lt;br /&gt;
&amp;lt;lsl&amp;gt;&lt;br /&gt;
size.x = (size.z * (size.y = (size.z * size.z)));&lt;br /&gt;
float fAdjust = vCoefficients * size;&lt;br /&gt;
&amp;lt;/lsl&amp;gt;&lt;br /&gt;
:::::::::::::Yeah, that is a nice way to represent it, for those used to the LSL representation for vector dot product. I&#039;m a little less enthused about the size vector assignment chain, but that&#039;s just my general dislike for C value assignments and such. In my mind, I separate assignments from expressions, so seeing them mixed together causes a bit of a train wreck in my brain&#039;s lexical analyzer. :P[[User:Talarus Luan|Talarus Luan]] 10:00, 21 July 2013 (PDT)&lt;br /&gt;
&lt;br /&gt;
::::::::::::::I don&#039;t think anyone uses the LSL vector dot product. It took me three days to remember it existed and then I look up the syntax just to make sure I wasn&#039;t crazy (yes yes, I agree it&#039;s insane to think that looking up the syntax of an obscure feature is proof against insanity but I&#039;m sticking to it, my cat agrees). I think a train wreck was my goal. -- &#039;&#039;&#039;[[User:Strife_Onizuka|Strife]]&#039;&#039;&#039; &amp;lt;sup&amp;gt;&amp;lt;small&amp;gt;([[User talk:Strife_Onizuka|talk]]|[[Special:Contributions/Strife_Onizuka|contribs]])&amp;lt;/small&amp;gt;&amp;lt;/sup&amp;gt; 11:13, 21 July 2013 (PDT)&lt;br /&gt;
&lt;br /&gt;
== Avatars Floating After Sit ==&lt;br /&gt;
&lt;br /&gt;
The position of avatars will sometimes change, generally noticeable as a rise on the Z axis of perhaps half a meter - common triggers for this is typing or another AV sitting on the same object - though these are not exhaustive.  Does anyone have a clue why this happens, and how to prevent it from happening? [[User:TaraLi Jie|TaraLi Jie]] 21:14, 11 March 2012 (PDT)&lt;br /&gt;
&lt;br /&gt;
:Hmm, there are a few possible causes, but the main cause are the animations involved, so it&#039;s worth remembering that any animation overrider can potentially cause weirdness while on a sit-target, which is why most good ones can turn themselves off while seated. It&#039;s a bit difficult to describe specific problems with animations, but I think that sometimes it can be caused by animations that have a weird first frame, since it&#039;s used to calculate all the offsets etc. for the rest of the animation; normally this will be a neutral pose since you don&#039;t actually see it in the animation, but if it&#039;s something odd then it can mess with positioning. -- &amp;lt;br/&amp;gt;-- &#039;&#039;&#039;[[User:Haravikk_Mistral|Haravikk]]&#039;&#039;&#039; &amp;lt;sup&amp;gt;&amp;lt;small&amp;gt;([[User_talk:Haravikk_Mistral|talk]]|[[Special:Contributions/Haravikk_Mistral|contribs]])&amp;lt;/small&amp;gt;&amp;lt;/sup&amp;gt; 05:34, 12 March 2012 (PDT)&lt;br /&gt;
&lt;br /&gt;
::When I&#039;ve had problems with this, the root cause has usually been that I&#039;ve (or something has) inadvertently stopped an animation that&#039;s holding the avatar in place before starting another one.   Because animations are all made differently, neither the animator with whom I work most of the time nor I have ever managed to figure out exactly what to avoid, but certainly when it happens to me, I always start debugging by looking very carefully at where I&#039;m turning animations off and considering whether, in fact, I need to turn them off at all.   Quite often, I find that simply turning off the default sit animation when my first animation starts, and then keeping the first animation going throughout, starting and stopping other ones over it, as necessary, solves the problem.&lt;br /&gt;
&lt;br /&gt;
::One &amp;quot;gotcha&amp;quot; is that stopping an animation and then immediately restarting it doesn&#039;t work.  It confuses the viewer something horrible, and often leads to people floating in mid-air.  [[User:Innula Zenovka|Innula Zenovka]] 09:04, 12 March 2012 (PDT)&lt;br /&gt;
&lt;br /&gt;
== Sit Target 0.4m &#039;bug&#039; ==&lt;br /&gt;
The notes say &lt;br /&gt;
&amp;quot;rot affects the position of the sit-target in a buggy way way.&lt;br /&gt;
To correct for the rot bug, simply subtract &amp;lt;0,0,0.4&amp;gt; from the position when rot is zero. See example below.&amp;quot;&lt;br /&gt;
&lt;br /&gt;
But the example script adjusts z by 0.4m when rotation is NOT zero.&lt;br /&gt;
&amp;lt;lsl&amp;gt;&lt;br /&gt;
if (rot!=ZERO_ROTATION) pos -=&amp;lt;0,0,0.4&amp;gt;;  //here is the work around&lt;br /&gt;
&amp;lt;/lsl&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Which should it be?&lt;br /&gt;
&lt;br /&gt;
I&#039;ve just been doing some tests without any 0.4m adjustment, and I am unable to observe any difference in my z position whether rotation is zero or not. Has something changed? If so, wouldn&#039;t the change screw up some furniture?&lt;br /&gt;
[[User:Omei Qunhua|Omei Qunhua]] 14:09, 16 March 2014 (PDT)&lt;br /&gt;
&lt;br /&gt;
:You are right, there shouldn&#039;t be a test there. My understanding is that you always need to subtract 0.4 from z. Changing it would screw up furniture. -- &#039;&#039;&#039;[[User:Strife_Onizuka|Strife]]&#039;&#039;&#039; &amp;lt;sup&amp;gt;&amp;lt;small&amp;gt;([[User talk:Strife_Onizuka|talk]]|[[Special:Contributions/Strife_Onizuka|contribs]])&amp;lt;/small&amp;gt;&amp;lt;/sup&amp;gt; 21:02, 16 March 2014 (PDT)&lt;/div&gt;</summary>
		<author><name>Timmy Foxclaw</name></author>
	</entry>
	<entry>
		<id>https://wiki.secondlife.com/w/index.php?title=User:Timmy_Foxclaw/About_Coordinate_Systems_and_Rotations&amp;diff=1189167</id>
		<title>User:Timmy Foxclaw/About Coordinate Systems and Rotations</title>
		<link rel="alternate" type="text/html" href="https://wiki.secondlife.com/w/index.php?title=User:Timmy_Foxclaw/About_Coordinate_Systems_and_Rotations&amp;diff=1189167"/>
		<updated>2014-04-04T20:48:45Z</updated>

		<summary type="html">&lt;p&gt;Timmy Foxclaw: Replaced script with latest version (now m4 generated from git). This fixes the fact that on opensim &amp;gt;= 0.8 sittarget_pos_ac is in fact a function of agent size!&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== About Coordinate Systems and Rotations ==&lt;br /&gt;
&lt;br /&gt;
=== The four coordinate systems ===&lt;br /&gt;
&lt;br /&gt;
There are four coordinate systems that are related to LSL programming:&lt;br /&gt;
# World coordinates&lt;br /&gt;
# Region coordinates&lt;br /&gt;
# Object coordinates (root prim coordinates)&lt;br /&gt;
# Child prim coordinates (coordinates relative to the prim that the script is in, or refered to by link number)&lt;br /&gt;
&lt;br /&gt;
The World coordinates refer to the map, and allow to include the sim&lt;br /&gt;
in the coordinates, or refer to void water.&lt;br /&gt;
&lt;br /&gt;
Region coordinates are relative to a given sim.&lt;br /&gt;
The origin is in the South/West corner at height 0.&lt;br /&gt;
The North/East corner then is 256, 256 and a Z coordinate&lt;br /&gt;
for the height up to 4096 meter (on opensim you can go even&lt;br /&gt;
higher).&lt;br /&gt;
&lt;br /&gt;
Object coordinates are relative to the root prim. Hence, if the object&lt;br /&gt;
is moved or rotated then the orientation of a child prim, when given&lt;br /&gt;
in object coordinates, doesn&#039;t change. In LSL &amp;quot;local position&amp;quot; and&lt;br /&gt;
&amp;quot;local rotation&amp;quot; refer to this coordinate system. &amp;quot;local&amp;quot; means&lt;br /&gt;
relative to the root prim.&lt;br /&gt;
&lt;br /&gt;
Prim Coordinates are relative to a given prim. If this prim is the root&lt;br /&gt;
prim then the Prim Coordinates are the same as the Object Coordinates.&lt;br /&gt;
For example, if a child prim is a cube with a size of 1,1,1 and one&lt;br /&gt;
red surface where the center of that surface is at 0.5,0,0 then it will&lt;br /&gt;
still be at 0.5,0,0 no matter how you move or rotate that child prim&lt;br /&gt;
(relative to the other linked prims).&lt;br /&gt;
&lt;br /&gt;
=== Positions ===&lt;br /&gt;
&lt;br /&gt;
A different position of the origin of a coordinate system is easy to understand:&lt;br /&gt;
You can think of positions as vectors that start in the origin of the&lt;br /&gt;
coordinate system that they are given in and end in the point that they&lt;br /&gt;
refer to. While the length of the vector is independent of the rotation of&lt;br /&gt;
the coordinate system, the three coordinates are not; but a mental picture&lt;br /&gt;
of an arrow doesn&#039;t have little numbers for three coordinates, so that&lt;br /&gt;
picture works independent of the rotation too.&lt;br /&gt;
&lt;br /&gt;
Since the rotation of the World Coordinate system and the Region Coordinate&lt;br /&gt;
system is the same (X, Y and Z axis are parallel of both), and since&lt;br /&gt;
World Coordinates aren&#039;t used in many LSL functions to begin with, we&lt;br /&gt;
will ignore World Coordinates for now and only refer to Region Coordinates,&lt;br /&gt;
or say &amp;quot;global&amp;quot; when we mean Region Coordinates.&lt;br /&gt;
&lt;br /&gt;
=== Rotations ===&lt;br /&gt;
&lt;br /&gt;
An LSL rotation internally stores a vector that is the axis around which&lt;br /&gt;
to rotate and the angle of the rotation around that axis.&lt;br /&gt;
Let &#039;&#039;&#039;V&#039;&#039;&#039; = &amp;amp;lt;u, v, w&amp;amp;gt; be the normalized vector (that is, with length 1) around&lt;br /&gt;
which we rotate and let &amp;amp;alpha; (alpha) be the angle around which we have to rotate.&lt;br /&gt;
Then the LSL rotation is a quaternion stored as r = &amp;amp;lt;x, y, z, s&amp;amp;gt; = &amp;amp;lt; &#039;&#039;&#039;V&#039;&#039;&#039; * sin(&amp;amp;alpha;/2), cos(&amp;amp;alpha;/2) &amp;amp;gt;.&lt;br /&gt;
Thus, r.x = x * sin(&amp;amp;alpha;/2), and r.s = cos(&amp;amp;alpha;/2) etc. Note that the quaternion&lt;br /&gt;
is also normalized.&lt;br /&gt;
Also note that there is a duality here because inverting &#039;&#039;&#039;V&#039;&#039;&#039; (making it point the&lt;br /&gt;
opposite way) and inverting the angle gives the same rotation; r and -r have&lt;br /&gt;
different values but are the same rotation.&lt;br /&gt;
Also note that if you don&#039;t rotate at all (&amp;amp;alpha; == 0) then it doesn&#039;t matter&lt;br /&gt;
what axis &#039;&#039;&#039;V&#039;&#039;&#039; you pick, which is apparent because &#039;&#039;&#039;V&#039;&#039;&#039; drops out since sin(0) = 0.&lt;br /&gt;
The quaternion &amp;amp;lt;0, 0, 0, 1&amp;amp;gt; is the ZERO_ROTATION quaternion.&lt;br /&gt;
&lt;br /&gt;
The point of this technical story is to show that for an LSL rotation to&lt;br /&gt;
make sense in terms of orientation, you need to be able to express a vector&lt;br /&gt;
in three coordinates (u, v, w above): the axis around which we rotate is&lt;br /&gt;
expressed relative to the X-, Y- and Z-axes of the coordinate system. Hence,&lt;br /&gt;
it is the orientation of the X-, Y- and Z-axes that defines the meaning&lt;br /&gt;
of a rotation in LSL.&lt;br /&gt;
&lt;br /&gt;
In terms of a mental picture the origin with the (orientation of the) three axis,&lt;br /&gt;
the red X-axis, the green Y-axis and the blue Z-axis is all the reference&lt;br /&gt;
we need, combined with a vector for position or a quaternion for rotation.&lt;br /&gt;
&lt;br /&gt;
When you edit an object, the viewer shows either &#039;World&#039; (meaning Region here) or &#039;Local&#039; axes, but&lt;br /&gt;
really the &#039;World&#039; (region) axes show the wrong origin, shifted to an averaged center&lt;br /&gt;
of the object, because if the origin was drawn at (0, 0, 0) you&#039;d most likely&lt;br /&gt;
not see it. The &#039;Local&#039; ruler shows the correct coordinate system for the&lt;br /&gt;
selected prim as its Prim Coordinate System. Selecting the root prim with&lt;br /&gt;
&#039;Local&#039; ruler on then shows the Object Coordinate System.&lt;br /&gt;
&lt;br /&gt;
=== The dimension of rotations ===&lt;br /&gt;
&lt;br /&gt;
As said before, given some coordinate system, any point in space can&lt;br /&gt;
be represented with a vector. Obviously space is three dimensional,&lt;br /&gt;
and thus vectors exists of three real values:&lt;br /&gt;
one needs three distinct floating point numbers, the x coordinate,&lt;br /&gt;
the y coordinate and the z coordinate to uniquely&lt;br /&gt;
identify a position in a given coordinate system.&lt;br /&gt;
&lt;br /&gt;
However, if one limits oneself to only normalized vectors, vectors&lt;br /&gt;
with a length of one, then those represent all points on the surface&lt;br /&gt;
of a sphere with radius 1.&lt;br /&gt;
A surface is obviously two dimensional, so it should be possible to&lt;br /&gt;
uniquely identify any point on the surface of such a sphere with&lt;br /&gt;
only two floating point numbers.&lt;br /&gt;
&lt;br /&gt;
One might think that selecting just two coordinates of the three of&lt;br /&gt;
the vector will suffice because the third is fixed by the length requirement,&lt;br /&gt;
but that only works for half spheres; for example, if x and y are known&lt;br /&gt;
then z can still be either plus the square root of x squared plus y squared,&lt;br /&gt;
&#039;&#039;or&#039;&#039; minus that value.&lt;br /&gt;
&lt;br /&gt;
Instead, a better choice would be the [http://mathworld.wolfram.com/SphericalCoordinates.html spherical coordinate system]&lt;br /&gt;
and express the unit vectors with the two angular coordinates &amp;amp;phi; (phi) and &amp;amp;theta; (theta),&lt;br /&gt;
where &amp;amp;phi; is the angle between the vector and the positive Z axis, and&lt;br /&gt;
&amp;amp;theta; the angle that the projection of the vector on to the X,Y plane makes&lt;br /&gt;
with the positive X axis. In other words, starting with a unit vector&lt;br /&gt;
along the positive Z-axis, one can obtain the required point on&lt;br /&gt;
the surface of the sphere by first rotating this vector around the&lt;br /&gt;
Y axis (towards the positive X axis) by an angle of &amp;amp;phi; and then rotating&lt;br /&gt;
the result around the Z-axis by an angle of &amp;amp;theta;. Note that in both cases&lt;br /&gt;
the rotations are counter-clockwise when one looks at it from the positive&lt;br /&gt;
side of the axis that one rotates around (towards the origin).&lt;br /&gt;
&lt;br /&gt;
What we just did was expressing a unit vector in terms of two rotations:&lt;br /&gt;
one around the Z axis and one around the Y axis; and indeed every rotation&lt;br /&gt;
can be expressed as two rotations around those two axis (or really, any&lt;br /&gt;
two arbitrary axes, as long as they are independent (not parallel)).&lt;br /&gt;
&lt;br /&gt;
It is therefore possible to represent unit vectors (aka, a &#039;&#039;direction&#039;&#039;)&lt;br /&gt;
with a rotation, as both are two dimensional. The mental picture here is&lt;br /&gt;
that any unit vector can be expressed as some fixed unit vector (for example&lt;br /&gt;
the one pointing along the positive Z axis, but any other would do as well)&lt;br /&gt;
and the rotation needed to turn that &#039;starting vector&#039; into the unit vector&lt;br /&gt;
that one wants to represent. The other way around almost works as well, with the&lt;br /&gt;
exception of the starting vector itself, as that can be expressed by any arbitrary&lt;br /&gt;
rotation around itself, so that information was lost and it is not possible&lt;br /&gt;
to know which of those rotations was used. In fact, any vector&lt;br /&gt;
close to the starting vector would give inaccurate results in the light&lt;br /&gt;
of floating point round off errors and is not a good way to represent&lt;br /&gt;
a rotation. Of course, the two dimensional vector (&amp;amp;theta;, &amp;amp;phi;) would be excellent&lt;br /&gt;
to represent both: the unit vector, as well as any rotation; but LSL stores&lt;br /&gt;
vectors in x, y, z coordinates, not in spherical coordinates.&lt;br /&gt;
&lt;br /&gt;
=== Converting between coordinate systems ===&lt;br /&gt;
&lt;br /&gt;
Consider a child prim of an object that is not the root prim and express&lt;br /&gt;
its position with the vector pos_oc, and its orientation with the rotation rot_oc,&lt;br /&gt;
both relative to the Object Coordinates system.&lt;br /&gt;
&lt;br /&gt;
A script inside that prim can easily obtain those values:&lt;br /&gt;
&lt;br /&gt;
 vector pos_oc = [[llGetLocalPos]]();&lt;br /&gt;
 rotation rot_oc = [[llGetLocalRot]]();&lt;br /&gt;
&lt;br /&gt;
The postfix &#039;_oc&#039; stands for Object Coordinates and is used to make clear&lt;br /&gt;
relative to which coordinate system the x, y and z values of both&lt;br /&gt;
variables are. Remember that also the rotation contains a vector&lt;br /&gt;
(the axis around which we rotate), so from now on we&#039;ll talk about&lt;br /&gt;
&#039;coordinates&#039; relative to a coordinate system for both, the position&lt;br /&gt;
as well as the rotation, where the coordinates refer to the x, y and z&lt;br /&gt;
components of the position and the rotation. For example, the first&lt;br /&gt;
sentence of this paragraph will read &amp;quot;...express its position with the&lt;br /&gt;
vector pos_oc, and its orientation with the rotation rot_oc, &#039;&#039;both in Object Coordinates&#039;&#039;.&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Note that&#039;&#039;&#039; one has to be careful here, because a script in the&lt;br /&gt;
root prim of the object will &#039;&#039;&#039;&#039;&#039;not&#039;&#039;&#039;&#039;&#039; obtain&lt;br /&gt;
Object Coordinates but instead Region Coordinates!&lt;br /&gt;
The reason is that the &#039;Local&#039; functions return coordinates relative to&lt;br /&gt;
the &#039;parent&#039; coordinate system, where the parent of a non-root prim is the root prim,&lt;br /&gt;
but the parent of the root prim is the region (or avatar in case&lt;br /&gt;
of an attachment). The position and rotation of the root prim in&lt;br /&gt;
Object Coordinates is trivial (ZERO_VECTOR and ZERO_ROTATION respectively).&lt;br /&gt;
&lt;br /&gt;
Back to the script in the child prim. It can also easily obtain its position&lt;br /&gt;
and rotation in Region Coordinates:&lt;br /&gt;
&lt;br /&gt;
 vector pos_rc = [[llGetPos]]();&lt;br /&gt;
 rotation rot_rc = [[llGetRot]]();&lt;br /&gt;
&lt;br /&gt;
Both sets, (pos_oc, rot_oc) and (pos_rc, rot_rc) refer to the same thing,&lt;br /&gt;
so it should be possible to convert them into each other.&lt;br /&gt;
&lt;br /&gt;
One can do this by looking at the orientation (position and rotation) of&lt;br /&gt;
one coordinate system relative to the other and expressed&lt;br /&gt;
in the coordinates of that other. The position and rotation&lt;br /&gt;
of the Object Coordinate System relative to the Region Coordinate&lt;br /&gt;
System, and in Region Coordinates, could be obtained as follows:&lt;br /&gt;
&lt;br /&gt;
 vector oc_pos_rc = [[llGetRootPosition]]();&lt;br /&gt;
 rotation oc_rot_rc = [[llGetRootRotation]]();&lt;br /&gt;
&lt;br /&gt;
As indicated by the &#039;_rc&#039; postfix, these are again in Region Coordinates.&lt;br /&gt;
&lt;br /&gt;
Having the relative orientation of the Object Coordinate System in Region Coordinates, it is&lt;br /&gt;
possible to convert Object Coordinates into Region Coordinates. More&lt;br /&gt;
abstractly put, if you have two coordinate systems A and B, and you have&lt;br /&gt;
their relative orientation expressed in A then you can convert orientations&lt;br /&gt;
expressed in B into A.&lt;br /&gt;
&lt;br /&gt;
The formula is as follows:&lt;br /&gt;
&lt;br /&gt;
 &#039;&#039;&#039;vector   pos_A = pos_B * B_rot_A + B_pos_A;            (1)&#039;&#039;&#039;&lt;br /&gt;
 &#039;&#039;&#039;rotation rot_A = rot_B * B_rot_A;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
The order of the multiplications is important; swapping the B_rot_A to the front will not work!&lt;br /&gt;
&lt;br /&gt;
Note that the B_*_A are the position and rotation of the coordinate system B expressed&lt;br /&gt;
in terms of the coordinate system A. The reason that I use the prefix and postfix in&lt;br /&gt;
this order is directly related to the order enforced for rotation multiplications.&lt;br /&gt;
Written this way, the left-hand postfix of a multiplication must match the right-hand prefix&lt;br /&gt;
and conviently short-circuits the notation:&lt;br /&gt;
&lt;br /&gt;
 something_A = something&#039;&#039;&#039;_B&#039;&#039;&#039; * &#039;&#039;&#039;B_&#039;&#039;&#039;rot_A&lt;br /&gt;
&lt;br /&gt;
the two B&#039;s &#039;connect&#039; and drop out (along with the &#039;_rot_&#039;) to give something_ ... A.&lt;br /&gt;
This &#039;&#039;only&#039;&#039; works when the postfix (_A or _B) refers to the coordinate system that the variables&lt;br /&gt;
are in, and the prefix is whatever is described by the variable, possibly another&lt;br /&gt;
coordinate system (B_ in this example).&lt;br /&gt;
&lt;br /&gt;
A complete example script follows:&lt;br /&gt;
&amp;lt;lsl&amp;gt;&lt;br /&gt;
default&lt;br /&gt;
{&lt;br /&gt;
    touch(integer num_detected)&lt;br /&gt;
    {&lt;br /&gt;
        llSay(0, &amp;quot;---------&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
        // Get the pos and rot in Object Coordinates.&lt;br /&gt;
        vector pos_oc = llGetLocalPos();&lt;br /&gt;
        rotation rot_oc = llGetLocalRot();&lt;br /&gt;
        &lt;br /&gt;
        // Fix these values when this script is in the root prim!&lt;br /&gt;
        if (llGetLinkNumber() &amp;lt;= 1)&lt;br /&gt;
        {&lt;br /&gt;
            pos_oc = ZERO_VECTOR;&lt;br /&gt;
            rot_oc = ZERO_ROTATION;&lt;br /&gt;
        }&lt;br /&gt;
        &lt;br /&gt;
        // Get the pos and rot in Region Coordinates.&lt;br /&gt;
        vector pos_rc = llGetPos();&lt;br /&gt;
        rotation rot_rc = llGetRot();&lt;br /&gt;
        &lt;br /&gt;
        // Get the pos and rot of the Object Coordinate System in Region Coordinates.&lt;br /&gt;
        vector oc_pos_rc = llGetRootPosition();&lt;br /&gt;
        rotation oc_rot_rc = llGetRootRotation();&lt;br /&gt;
        &lt;br /&gt;
        // Print the values of the positions (the rotations are too hard to understand).&lt;br /&gt;
        llSay(0, &amp;quot;oc_pos_rc = &amp;quot; + (string)oc_pos_rc);&lt;br /&gt;
        llSay(0, &amp;quot;pos_os = &amp;quot; + (string)pos_os);&lt;br /&gt;
        llSay(0, &amp;quot;pos_rc = &amp;quot; + (string)pos_rc);&lt;br /&gt;
        &lt;br /&gt;
        // Calculate pos_rc and rot_rc from pos_oc and rot_oc : converting between _oc and _rc.&lt;br /&gt;
        vector   pos2_rc = pos_oc * oc_rot_rc + oc_pos_rc;&lt;br /&gt;
        rotation rot2_rc = rot_oc * oc_rot_rc;&lt;br /&gt;
        &lt;br /&gt;
        // Print the result for the position, and show the difference with what llGetPos() and llGetRot() returned.&lt;br /&gt;
        llSay(0, &amp;quot;pos2_rc = &amp;quot; + (string)pos2_rc);&lt;br /&gt;
        // These values should be ZERO_VECTOR and ZERO_ROTATION (or -ZERO_ROTATION).&lt;br /&gt;
        llSay(0, &amp;quot;pos_rc - pos2_rc = &amp;quot; + (string)(pos_rc - pos2_rc));&lt;br /&gt;
        llSay(0, &amp;quot;rot_rc / rot2_rc = &amp;quot; + (string)(rot_rc / rot2_rc));&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/lsl&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Obviously there is no preference for one coordinate system over the other for this conversion;&lt;br /&gt;
one can equally as well convert orientations in A into B:&lt;br /&gt;
&lt;br /&gt;
 vector   pos_B = pos_A * A_rot_B + A_pos_B;&lt;br /&gt;
 rotation rot_B = rot_A * A_rot_B;&lt;br /&gt;
&lt;br /&gt;
The question arises then how to obtain the A_*_B values; there is no LSL function that returns directly&lt;br /&gt;
the position or rotation of the region relative to a prim (aka, rc_*_oc).&lt;br /&gt;
&lt;br /&gt;
Intuitively one would say that it has to be possible to express A_*_B in B_*_A on grounds of symmetry, and that&lt;br /&gt;
is indeed the case.&lt;br /&gt;
&lt;br /&gt;
To show how this works, lets just take the formula for pos_A and rot_A (see (1) above) and rework&lt;br /&gt;
them to get pos_B and rot_B on the left-hand side. This results first in&lt;br /&gt;
&lt;br /&gt;
 pos_B * B_rot_A = pos_A - B_pos_A&lt;br /&gt;
 rot_B * B_rot_A = rot_A&lt;br /&gt;
&lt;br /&gt;
Then divide both sides by B_rot_A to get:&lt;br /&gt;
&lt;br /&gt;
 pos_B = pos_A / B_rot_A - B_pos_A / B_rot_A&lt;br /&gt;
 rot_B = rot_A / B_rot_A&lt;br /&gt;
&lt;br /&gt;
from which we can conclude that&lt;br /&gt;
&lt;br /&gt;
 &#039;&#039;&#039;A_pos_B = - B_pos_A / B_rot_A                           (2)&#039;&#039;&#039;&lt;br /&gt;
 &#039;&#039;&#039;A_rot_B = ZERO_ROTATION / B_rot_A&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Note how A_rot_B is the inverse of B_rot_A: A_rot_B * B_rot_A = ZERO_ROTATION.&lt;br /&gt;
As per our notation convention you&#039;d expect A_rot_B * B_rot_A to be A_rot_A, and that is&lt;br /&gt;
actually the case as A_rot_A means the relative orientation of coordinate system A&lt;br /&gt;
expressed in A&#039;s coordinates, which is the trivial ZERO_VECTOR and ZERO_ROTATION as&lt;br /&gt;
we saw before for the root prim orientation expressed in Object Coordinates.&lt;br /&gt;
&lt;br /&gt;
And for fun, note that if we do this inversion again we get:&lt;br /&gt;
&lt;br /&gt;
 B_pos_A = - A_pos_B / A_rot_B = - (- B_pos_A / B_rot_A) / (ZERO_ROTATION / B_rot_A) = B_pos_A / B_rot_A * B_rot_A = B_pos_A&lt;br /&gt;
 B_rot_A = ZERO_ROTATION / A_rot_B = ZERO_ROTATION / (ZERO_ROTATION / B_rot_A) = B_rot_A&lt;br /&gt;
&lt;br /&gt;
as expected.&lt;br /&gt;
&lt;br /&gt;
We can now also convert Region Coordinates to Object Coordinates.&lt;br /&gt;
&lt;br /&gt;
One could first calculate,&lt;br /&gt;
&lt;br /&gt;
 vector rc_pos_oc = - llGetRootPosition() / llGetRootRotation();&lt;br /&gt;
 rotation rc_rot_oc = ZERO_ROTATION / llGetRootRotation();&lt;br /&gt;
&lt;br /&gt;
and then convert as usual:&lt;br /&gt;
&lt;br /&gt;
 vector   pos_oc = pos_rc * rc_rot_oc + rc_pos_oc;&lt;br /&gt;
 rotation rot_oc = rot_rc * rc_rot_oc;&lt;br /&gt;
&lt;br /&gt;
or if you don&#039;t want to calculate the intermediate rc_*_oc values, you could do immediately:&lt;br /&gt;
&lt;br /&gt;
 vector   pos_oc = (pos_rc - llGetRootPosition()) / llGetRootRotation();&lt;br /&gt;
 rotation rot_oc = rot_rc / llGetRootRotation();&lt;br /&gt;
&lt;br /&gt;
To verify this, you could extend the above script with&lt;br /&gt;
&amp;lt;lsl&amp;gt;&lt;br /&gt;
        // Calculate pos_oc and rot_oc from pos_rc and rot_rc.&lt;br /&gt;
        vector   pos2_oc = (pos_rc - llGetRootPosition()) / llGetRootRotation();&lt;br /&gt;
        rotation rot2_oc = rot_rc / llGetRootRotation();&lt;br /&gt;
        &lt;br /&gt;
        llSay(0, &amp;quot;pos2_oc = &amp;quot; + (string)pos2_oc);&lt;br /&gt;
        // These values should again be ZERO_VECTOR and +/- ZERO_ROTATION.&lt;br /&gt;
        llSay(0, &amp;quot;pos_oc - pos2_oc = &amp;quot; + (string)(pos_oc - pos2_oc));&lt;br /&gt;
        llSay(0, &amp;quot;rot_oc / rot2_oc = &amp;quot; + (string)(rot_oc / rot2_oc));&lt;br /&gt;
&amp;lt;/lsl&amp;gt;&lt;br /&gt;
&lt;br /&gt;
More in general, if you want to convert from B to A, but you only have A_*_B instead of B_*_A, then (combining (1) and (2))&lt;br /&gt;
you can do:&lt;br /&gt;
&lt;br /&gt;
 &#039;&#039;&#039;vector   pos_A = (pos_B - A_pos_B) / A_rot_B;           (3)&#039;&#039;&#039;&lt;br /&gt;
 &#039;&#039;&#039;rotation rot_A = rot_B / A_rot_B;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
=== Cascading coordinate systems ===&lt;br /&gt;
&lt;br /&gt;
Imagine you have a castle object where the floor is the root prim. Everything is linked because you&lt;br /&gt;
want it to be easy to move the castle around. One of the child prims is a sculpty representing the hinges&lt;br /&gt;
around which you want to rotate a large gate. The gate has a rotating wheel on it.&lt;br /&gt;
&lt;br /&gt;
You want that the object (castle) to keep working when it is moved and/or rotated, but also when it is edited&lt;br /&gt;
and the hinges are moved and/or rotated. This means that the state of the gate prims&lt;br /&gt;
must be &#039;&#039;stored&#039;&#039; relative to the hinges, which is by far the easiest thing to do to begin with,&lt;br /&gt;
after all, the gate rotates around the hinges and has no relation with the rest of the castle.&lt;br /&gt;
&lt;br /&gt;
Hence, we have the Region Coordinate System, the Object Coordinate System (the castle) and the Hinges Coordinate System.&lt;br /&gt;
The latter is our first example of a Prim Coordinates System, but I&#039;ll use the postfix &#039;_hc&#039; for &amp;quot;Hinges Coordinates&amp;quot;&lt;br /&gt;
instead of &#039;_pc&#039;. Finally we have the Spill Coordinate System (or Gate Coordinates) where the spill is a prim&lt;br /&gt;
around which we want to rotate the wheel, and I&#039;ll use &#039;_sc&#039; as postfix for that.&lt;br /&gt;
&lt;br /&gt;
The variables used then would be an orientation for the wheel in *_sc coordinates, the orientation of the spill,&lt;br /&gt;
and other gate prims, in *_hc coordinates and the orientation of the hinges in *_oc coordinates. Finally we could&lt;br /&gt;
have variables for the orientation of the castle (root prim) in *_rc coordinates of course.&lt;br /&gt;
&lt;br /&gt;
 vector   castle_pos_rc; // The position of the castle in Region Coordinates.&lt;br /&gt;
 rotation castle_rot_rc; // The rotation of the castle in Region Coordinates.&lt;br /&gt;
 &lt;br /&gt;
 vector   hinges_pos_oc; // The position of the hinges in Object Coordinates.&lt;br /&gt;
 rotation hinges_rot_oc; // The rotation of the hinges in Object Coordinates.&lt;br /&gt;
 &lt;br /&gt;
 vector   spill_pos_hc;  // The position of the spill in Hinges Coordinates.&lt;br /&gt;
 rotation spill_rot_hc;  // The rotation of the spill in Hinges Coordinates.&lt;br /&gt;
 &lt;br /&gt;
 vector   wheel_pos_sc;  // The position of the wheel in Spill Coordinates.&lt;br /&gt;
 rotation wheel_rot_sc;  // The rotation of the wheel in Spill Coordinates.&lt;br /&gt;
&lt;br /&gt;
Now because we used existing prims orientations as coordinate system for the next prim, the position&lt;br /&gt;
and rotation of those prims &#039;&#039;are&#039;&#039; the position and rotation of that coordinate system.&lt;br /&gt;
Just like before we saw that llGetPos/llGetRot returns the global orientation of the root prim&lt;br /&gt;
when used in a script in the root prim, while llGetRootPos/llGetRootRot gave us the relative&lt;br /&gt;
orientation of the Object Coordinate System in Region Coordinates, but is in fact the same as&lt;br /&gt;
what llGetPos/llGetRot in the root prim returns: the position/rotation of the root prim &#039;&#039;&#039;is&#039;&#039;&#039;&lt;br /&gt;
the orientation of the Object Coordinate System relative to the Region.&lt;br /&gt;
&lt;br /&gt;
Likewise, in this case, castle_*_rc is the relative orientation of the Object Coordinate System&lt;br /&gt;
in Region Coordinates as well as the orientation of the root prim in Region Coordinates; they&lt;br /&gt;
are the same thing.&lt;br /&gt;
&lt;br /&gt;
The same then applies to the *_oc variables, which we defined as the orientation of&lt;br /&gt;
the hinges in Object Coordinates, but at the same time are the relative orientation&lt;br /&gt;
of the Hinges Coordinate System in Object Coordinates. The *_hc variables are the&lt;br /&gt;
orientation of spill in Hinges Coordinates, but also the relative orientation of&lt;br /&gt;
the Spill Coordinates in Hinges Coordinates.&lt;br /&gt;
&lt;br /&gt;
Lets write it out using the same notation convention as used above, then&lt;br /&gt;
we have:&lt;br /&gt;
&lt;br /&gt;
 vector   oc_pos_rc = castle_pos_rc; // The Object Coordinate System orientation in Region Coordinates.&lt;br /&gt;
 rotation oc_rot_rc = castle_rot_rc;&lt;br /&gt;
 &lt;br /&gt;
 vector   hc_pos_oc = hinges_pos_oc; // The Hinges Coordinate System orientation in Object Coordinates.&lt;br /&gt;
 rotation hc_rot_oc = hinges_rot_oc;&lt;br /&gt;
 &lt;br /&gt;
 vector   sc_pos_hc = spill_pos_hc;  // The Spill Coordinate System orientation in Hinges Coordinates.&lt;br /&gt;
 rotation sc_rot_hc = spill_rot_hc;&lt;br /&gt;
&lt;br /&gt;
It will therefore probably not surprise you that&lt;br /&gt;
&lt;br /&gt;
 vector   hc_pos_rc = hc_pos_oc * oc_rot_rc + oc_pos_rc; // The Hinges Coordinate System orientation in Region Coordinates.&lt;br /&gt;
 rotation hc_rot_rc = hc_rot_oc * oc_rot_rc;&lt;br /&gt;
 &lt;br /&gt;
 vector   sc_pos_rc = sc_pos_hc * hc_rot_rc + hc_pos_rc; // The Spill Coordinate System orientation in Region Coordinates.&lt;br /&gt;
 rotation sc_rot_rc = sc_rot_hc * hc_rot_rc;&lt;br /&gt;
&lt;br /&gt;
And finally, using the latter, we can express the wheel orientation in region coordinates:&lt;br /&gt;
&lt;br /&gt;
 vector   wheel_pos_rc = wheel_pos_sc * sc_rot_rc + sc_pos_rc;&lt;br /&gt;
 rotation wheel_rot_rc = wheel_rot_sc * sc_rot_rc;&lt;br /&gt;
&lt;br /&gt;
Although this was nothing else but applying the coordinate system conversion formula ((1)) three times,&lt;br /&gt;
it might give some insight to get rid of the intermediate variables and express the wheel&lt;br /&gt;
orientation in region coordinates without them, giving:&lt;br /&gt;
&lt;br /&gt;
 wheel_pos_rc = ((wheel_pos_sc * sc_rot_hc + sc_pos_hc) * hc_rot_oc + hc_pos_oc) * oc_rot_rc + oc_pos_rc&lt;br /&gt;
 wheel_rot_rc = wheel_rot_sc * sc_rot_hc * hc_rot_oc * oc_rot_rc&lt;br /&gt;
&lt;br /&gt;
=== Applying rotations and translations ===&lt;br /&gt;
&lt;br /&gt;
Applying rotations and translations (moving) is very much the same as coordinate system transformations described above.&lt;br /&gt;
To show this consider the following: imagine you have a prim &#039;pa&#039; with its own coordinate system A.&lt;br /&gt;
Then it trivially has position ZERO_VECTOR and rotation ZERO_ROTATION relative to A, per definition.&lt;br /&gt;
&lt;br /&gt;
 vector   pa_pos_A = ZERO_VECTOR;&lt;br /&gt;
 rotation pa_rot_A = ZERO_ROTATION;&lt;br /&gt;
&lt;br /&gt;
Now consider a prim &#039;pb&#039; that has some relative position pb_pos_A and rotation pb_rot_A given in A coordinates.&lt;br /&gt;
For example,&lt;br /&gt;
&lt;br /&gt;
 vector   pb_pos_A = &amp;lt;0.5, 0.6, 0.7&amp;gt;;&lt;br /&gt;
 rotation pb_rot_A = &amp;lt;0.38, 0.26, 0.34, 0.82&amp;gt;;&lt;br /&gt;
&lt;br /&gt;
Note that 0.38&amp;amp;sup2; + 0.26&amp;amp;sup2; + 0.34&amp;amp;sup2; + 0.82&amp;amp;sup2; = 1, as it must be since rotations are normalized.&lt;br /&gt;
&lt;br /&gt;
As seen before, the orientation of pb relative to pa is the same as the orientation of pb relative to A,&lt;br /&gt;
and the same as the orientation of B relative to A. pa and A are interchangeable as long as pa has&lt;br /&gt;
ZERO_VECTOR and ZERO_ROTATION relative to A. Thus, with B being the coordinate system where pb currently&lt;br /&gt;
is, we also have:&lt;br /&gt;
&lt;br /&gt;
 vector   B_pos_A = pb_pos_A; // The orientation of coordinate system B, in coordinates of A.&lt;br /&gt;
 rotation B_rot_A = pb_rot_A;&lt;br /&gt;
&lt;br /&gt;
Now suppose we want move the prim pa (without moving the coordinate system A),&lt;br /&gt;
by applying the translation &#039;B_pos_A&#039;, after all a translation is stored in a vector&lt;br /&gt;
and B_pos_A is a vector. Likewise, we want to rotate pa (again without influencing A)&lt;br /&gt;
by applying the rotation B_rot_A. Then the most logical order to this in is by&lt;br /&gt;
&#039;&#039;first&#039;&#039; applying the rotation and &#039;&#039;then&#039;&#039; applying the translation, because then&lt;br /&gt;
the meaning of the translation is preserved and will match the meaning of B_pos_A&lt;br /&gt;
in that pa will end up where pb is now. If you&#039;d first apply the translation so that&lt;br /&gt;
pa ends up where pb is, and then apply the rotation (around A!) then pa would swoop&lt;br /&gt;
around the origin of A and move away from its desired position.&lt;br /&gt;
&lt;br /&gt;
Doing this correctly should leave us with pa_pos_A == pb_pos_A and pa_rot_A == pb_rot_A,&lt;br /&gt;
so that pa ended up precisely where pb is now. We can&#039;t just assign those values&lt;br /&gt;
however, because we&#039;re looking for a formula that works in general; a way to apply&lt;br /&gt;
B_rot_A and then B_pos_A to any prim with -say- orientation pc_pos_A, pc_rot_A.&lt;br /&gt;
&lt;br /&gt;
Thus, first we apply the rotation:&lt;br /&gt;
&lt;br /&gt;
 pc_rot_A *= B_rot_A;&lt;br /&gt;
 pc_pos_A *= B_rot_A;&lt;br /&gt;
&lt;br /&gt;
And then apply the translation:&lt;br /&gt;
&lt;br /&gt;
 pc_pos_A += B_pos_A;&lt;br /&gt;
&lt;br /&gt;
Now lets check if indeed this would cause pa to end up where pb is.&lt;br /&gt;
The effect on pa_*_A would be:&lt;br /&gt;
&lt;br /&gt;
 pa_rot_A = pa_rot_A * B_rot_A = ZERO_ROTATION * B_rot_A = B_rot_A = pb_rot_A;&lt;br /&gt;
 pa_pos_A = pa_pos_A * B_rot_A = ZERO_VECTOR * B_rot_A = ZERO_VECTOR;&lt;br /&gt;
 &lt;br /&gt;
 and then the translation&lt;br /&gt;
 &lt;br /&gt;
 pa_pos_A = pa_pos_A + B_pos_A = ZERO_VECTOR + B_pos_A = B_pos_A = pb_pos_A;&lt;br /&gt;
&lt;br /&gt;
So yes, pa_*_A ends up as pb_*_A!&lt;br /&gt;
&lt;br /&gt;
The real test however would be if we first applied some transformation to pa&lt;br /&gt;
to bring it to some arbitrary orientation (aka, pc), then apply the transformation&lt;br /&gt;
B_rot_A,B_pos_A and then reverse the first transformation but now relative to B,&lt;br /&gt;
and then find that we indeed end up at pb.&lt;br /&gt;
&lt;br /&gt;
Let us first define a &#039;transformation&#039;, which exists of a vector for the&lt;br /&gt;
translation and a rotation for the rotation. We will have two transformations&lt;br /&gt;
during this test: t1: pa -&amp;gt; pc, and t2: pa -&amp;gt; pb.&lt;br /&gt;
&lt;br /&gt;
As we just saw (or we hope this is going to be the case), t2 can be defined as:&lt;br /&gt;
&lt;br /&gt;
 vector   t2_translation = B_pos_A;&lt;br /&gt;
 rotation t2_rotation = B_rot_A;&lt;br /&gt;
&lt;br /&gt;
where as t1 is arbitrary, just some values t1_translation and t1_rotation.&lt;br /&gt;
&lt;br /&gt;
Applying t1 to pa, we get (this is thus the same as above, but now with the &#039;t1&#039; notation):&lt;br /&gt;
&lt;br /&gt;
 pa_rot_A *= t1_rotation;&lt;br /&gt;
 pa_pos_A *= t1_rotation;&lt;br /&gt;
 pa_pos_A += t1_translation;&lt;br /&gt;
&lt;br /&gt;
Next we apply translation t2 to that:&lt;br /&gt;
&lt;br /&gt;
 pa_rot_A *= t2_rotation;&lt;br /&gt;
 pa_pos_A *= t2_rotation;&lt;br /&gt;
 pa_pos_A += t2_translation;&lt;br /&gt;
&lt;br /&gt;
Finally we want to reverse t1, but in the coordinate system of B.&lt;br /&gt;
Therefore, we first convert our coordinates to that of B (formula (1)):&lt;br /&gt;
&lt;br /&gt;
 pa_pos_B = pa_pos_A * A_rot_B + A_pos_B;&lt;br /&gt;
 pa_rot_B = pa_rot_A * A_rot_B;&lt;br /&gt;
&lt;br /&gt;
where (formula (2))&lt;br /&gt;
&lt;br /&gt;
 A_pos_B = - B_pos_A / B_rot_A;&lt;br /&gt;
 A_rot_B = ZERO_ROTATION / B_rot_A;&lt;br /&gt;
&lt;br /&gt;
and then reverse t1. Note now we have to do the translation first!&lt;br /&gt;
&lt;br /&gt;
 pa_pos_B -= t1_translation;&lt;br /&gt;
 pa_pos_B /= t1_rotation;&lt;br /&gt;
 pa_rot_B /= t1_rotation;&lt;br /&gt;
&lt;br /&gt;
And if everything worked out then pa now should be at ZERO_VECTOR, ZERO_ROTATION relative to B!&lt;br /&gt;
&lt;br /&gt;
As pa_pos_A,pa_rot_A started as ZERO_VECTOR,ZERO_ROTATION, the first step&lt;br /&gt;
of applying t1 resulted in pa_rot_A = t1_rotation and pa_pos_A = t1_translation.&lt;br /&gt;
&lt;br /&gt;
After applying t2 we get pa_rot_A = t1_rotation * t2_rotation, and pa_pos_A = t1_translation * t2_rotation + t2_translation.&lt;br /&gt;
&lt;br /&gt;
Converting that to B gives&lt;br /&gt;
&lt;br /&gt;
 pa_pos_B = (t1_translation * t2_rotation + t2_translation) * A_rot_B + A_pos_B&lt;br /&gt;
 pa_rot_B = (t1_rotation * t2_rotation) * A_rot_B&lt;br /&gt;
&lt;br /&gt;
where, remembering that t2_translation = B_pos_A and t2_rotation = B_rot_A,&lt;br /&gt;
&lt;br /&gt;
 A_pos_B = - B_pos_A / B_rot_A = - t2_translation / t2_rotation&lt;br /&gt;
 A_rot_B = ZERO_ROTATION / B_rot_A = ZERO_ROTATION / t2_rotation&lt;br /&gt;
&lt;br /&gt;
so that we get&lt;br /&gt;
&lt;br /&gt;
 pa_pos_B = (t1_translation * t2_rotation + t2_translation) / t2_rotation - t2_translation / t2_rotation = t1_translation&lt;br /&gt;
 pa_rot_B = (t1_rotation * t2_rotation) / t2_rotation = t1_rotation&lt;br /&gt;
&lt;br /&gt;
and finally reversing t1 gives:&lt;br /&gt;
&lt;br /&gt;
 pa_pos_B = (t1_translation - t1_translation) / t1_rotation = ZERO_VECTOR&lt;br /&gt;
 pa_rot_B = t1_rotation / t1_rotation = ZERO_ROTATION&lt;br /&gt;
&lt;br /&gt;
So that we can conclude that if you have two prims pa and pb, each representing their own coordinate system A and B respectively,&lt;br /&gt;
and you express the orientation of B relative to A as the pair (B_pos_A, B_rot_A) &amp;amp;mdash; then the following holds.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;The transformation pair (t_translation, t_rotation) equals (B_pos_A, B_rot_A) as long as you first apply the rotation and then the translation while working in the coordinate system of A&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
The latter is also very practical, because you normally won&#039;t know&lt;br /&gt;
anything about the target coordinate system B until you actually did the transformation.&lt;br /&gt;
&lt;br /&gt;
Now remember that we found that in order to convert variables from being relative to a coordinate system B to a coordinate system A,&lt;br /&gt;
we did (formula (1)):&lt;br /&gt;
&lt;br /&gt;
 pos_A = pos_B * B_rot_A + B_pos_A&lt;br /&gt;
 rot_A = rot_B * B_rot_A&lt;br /&gt;
&lt;br /&gt;
which is thus exactly the same as first applying the rotation t1_rotation and then the translation t1_translation&lt;br /&gt;
on the pair (pos_B, rot_B) where that pair is relative to A! That isn&#039;t too weird because if you consider a prim&lt;br /&gt;
in the origin of A with no rotation, aka (ZERO_VECTOR, ZERO_ROTATION) relative to A and then apply the transformation&lt;br /&gt;
then you expect to end up in the origin of B with no rotation relative to B. Aka pos_B = ZERO_VECTOR and rot_B = ZERO_ROTATION.&lt;br /&gt;
So now work backwards: assume you already have the prim in B like that, then what are its coordinates in A?&lt;br /&gt;
That would be the above conversion thus, with pos_B = ZERO_VECTOR and rot_B = ZERO_ROTATION.&lt;br /&gt;
&lt;br /&gt;
Hence, doing the conversion with ZERO as input gives the same results as doing the t transformation with ZERO as input!&lt;br /&gt;
And the final formula for a transformation just looks exactly the same:&lt;br /&gt;
&lt;br /&gt;
 &#039;&#039;&#039;target_pos_A = source_pos_A * t_rotation + t_translation        (4)&#039;&#039;&#039;&lt;br /&gt;
 &#039;&#039;&#039;target_rot_A = source_rot_A * t_rotation&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
=== Scaling coordinate systems ===&lt;br /&gt;
&lt;br /&gt;
Apart from rotation and translation, there is one more linear operator that can be used to convert&lt;br /&gt;
between coordinate systems: scaling.&lt;br /&gt;
&lt;br /&gt;
Let A_pos_B be the position of the origin of A in the coordinates of B. Let A_rot_B be the orientation of A within B,&lt;br /&gt;
and let the vector A_B_scale be the scaling factors for each axes. Scaling has no influence on the origin of&lt;br /&gt;
a coordinate system, but it matters for the rotation when the scaling factors per axis are different.&lt;br /&gt;
&lt;br /&gt;
I think that a good choice is scale first and rotate afterwards. Because that leaves the values&lt;br /&gt;
of the coordinates of A_rot_B alone: it remains the rotation as defined in B, which makes sense&lt;br /&gt;
since it is written in the coordinates of B. However, it&#039;s just a matter of choice really, which&lt;br /&gt;
in this case will deform B_rot_A instead of A_rot_B. I can imagine that the choice might depend&lt;br /&gt;
on the application.&lt;br /&gt;
&lt;br /&gt;
Chosing that we first scale, a point at pos_A is mapped onto the point pos_B as follows:&lt;br /&gt;
&lt;br /&gt;
 pos_B = (S * pos_A) * A_rot_B + A_pos_B&lt;br /&gt;
&lt;br /&gt;
where S is a 3x3 matrix with as diagonal the vector A_B_scale (and the rest zeroes).&lt;br /&gt;
Note that when each element of A_B_scale is the same then you can just use a scalar for S, equal to the scale of each axis.&lt;br /&gt;
&lt;br /&gt;
Whether or not S is a matrix or a scalar, lets just replace it with &#039;A_B_scale&#039; here. Just keep in&lt;br /&gt;
mind that if it isn&#039;t a scalar then this won&#039;t work in LSL directly: then you&#039;ll have to split&lt;br /&gt;
it up in three different code lines because LSL doesn&#039;t support scaling or matrices.&lt;br /&gt;
&lt;br /&gt;
  pos_B = pos_A;&lt;br /&gt;
  pos_B.x *= A_B_scale.x;  // Scale&lt;br /&gt;
  pos_B.y *= A_B_scale.y;&lt;br /&gt;
  pos_B.z *= A_B_scale.z;&lt;br /&gt;
  pos_B *= A_rot_B;        // Rotate&lt;br /&gt;
  pos_B += A_pos_B;        // Translate&lt;br /&gt;
&lt;br /&gt;
Note that the inverse of S, 1/S, is a 3x3 matrix with as diagonal the inverse of each element of A_B_scale.&lt;br /&gt;
We will either write &#039;B_A_scale&#039;, or divide by &#039;A_B_scale&#039; in our notation.&lt;br /&gt;
&lt;br /&gt;
Therefore our notation becomes:&lt;br /&gt;
&lt;br /&gt;
 pos_B = (&#039;A_B_scale&#039; * pos_A) * A_rot_B + A_pos_B&lt;br /&gt;
&lt;br /&gt;
Since A and B are arbitrary, we would expect the same formula to hold when swapping A and B:&lt;br /&gt;
&lt;br /&gt;
 pos_A = (&#039;B_A_scale&#039; * pos_B) * B_rot_A + B_pos_A&lt;br /&gt;
&lt;br /&gt;
Solving pos_B from that by subtracting B_pos_A from both sides, then dividing both sides by B_rot_A&lt;br /&gt;
and finally left multiplying both sides with the inverse of B_A_scale, gives:&lt;br /&gt;
&lt;br /&gt;
 pos_B = &#039;A_B_scale&#039; * ((pos_A - B_pos_A) / B_rot_A) = &#039;A_B_scale&#039; * (pos_A / B_rot_A) - &#039;A_B_scale&#039; * (B_pos_A / B_rot_A)&lt;br /&gt;
&lt;br /&gt;
from which we can conclude (by setting pos_A to ZERO_VECTOR) that&lt;br /&gt;
&lt;br /&gt;
 A_pos_B = -&#039;A_B_scale&#039; * (B_pos_A / B_rot_A)&lt;br /&gt;
&lt;br /&gt;
Solving B_pos_A from that by left multiplying both sides with -B_A_scale and then right multiplying both sides with B_rot_A, gives:&lt;br /&gt;
&lt;br /&gt;
 B_pos_A = - (&#039;B_A_scale&#039; * A_pos_B) * B_rot_A&lt;br /&gt;
&lt;br /&gt;
By setting A_pos_B to ZERO_VECTOR, and this B_pos_A too, we can also conclude that&lt;br /&gt;
&lt;br /&gt;
 (&#039;A_B_scale&#039; * pos_A) * A_rot_B = &#039;A_B_scale&#039; * (pos_A / B_rot_A)&lt;br /&gt;
&lt;br /&gt;
If &#039;A_B_scale&#039; is a scalar, so that the order of multiplication doesn&#039;t matter,&lt;br /&gt;
then the scale just cancels on both sides and we find the conversion that we&lt;br /&gt;
found before, that B_rot_A is the inverse of A_rot_B. However, if A_B_scale&lt;br /&gt;
is a diagonal matrix then the order matters and the brackets are significant.&lt;br /&gt;
&lt;br /&gt;
There is no way to let pos_A drop out: we cannot write B_rot_A as function&lt;br /&gt;
of A_B_scale and A_rot_B.&lt;br /&gt;
&lt;br /&gt;
The conclusion is that a scale is asymmetrical: if you choose that a scale A_B_scale&lt;br /&gt;
means that you first apply the scale on a vector in A and then rotate, then&lt;br /&gt;
that automatically implies that when going from B to A you first have to rotate&lt;br /&gt;
and &#039;&#039;then&#039;&#039; apply the scale.&lt;br /&gt;
&lt;br /&gt;
To make the choice clear in the name, I suggest to put an &#039;r&#039; in front of the&lt;br /&gt;
coordinate system that need rotation to be applied first. &lt;br /&gt;
&lt;br /&gt;
In summary, if A_rB_scale is defined as&lt;br /&gt;
&lt;br /&gt;
 &#039;&#039;&#039;pos_B = (&#039;A_rB_scale&#039; * pos_A) * A_rot_B + A_pos_B      (5)&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
then that implies that rB_A_scale has to be applied after rotation.&lt;br /&gt;
Note this means braces, NOT changing the left- or right- side of&lt;br /&gt;
multiplications! Matrices (scales) are always on the left side&lt;br /&gt;
of a vector, while rotations are always on the right side. Thus we get: &lt;br /&gt;
&lt;br /&gt;
 &#039;&#039;&#039;pos_A = &#039;rB_A_scale&#039; * (pos_B * B_rot_A) + B_pos_A      (6)&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
If now we solve pos_B from the latter, we get:&lt;br /&gt;
&lt;br /&gt;
 pos_B = (&#039;A_rB_scale&#039; * (pos_A - B_pos_A)) / B_rot_A = (&#039;A_rB_scale&#039; * pos_A) / B_rot_A - (&#039;A_rB_scale&#039; * B_pos_A) / B_rot_A&lt;br /&gt;
&lt;br /&gt;
Hence&lt;br /&gt;
&lt;br /&gt;
 &#039;&#039;&#039;B_pos_A = - &#039;rB_A_scale&#039; * (A_pos_B / A_rot_B)          (7)&#039;&#039;&#039;&lt;br /&gt;
 &#039;&#039;&#039;B_rot_A = ZERO_ROTATION / A_rot_B&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
and&lt;br /&gt;
&lt;br /&gt;
 &#039;&#039;&#039;A_pos_B = - (&#039;A_rB_scale&#039; * B_posA) / B_rot_A           (8)&#039;&#039;&#039;&lt;br /&gt;
 &#039;&#039;&#039;A_rot_B = ZERO_ROTATION / B_rot_A&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Note how these two sets condense into the same thing when the scale is a scalar,&lt;br /&gt;
but also when A_rot_B and B_rot_A are ZERO_ROTATION. In fact, when the rotation&lt;br /&gt;
involved is of the special case of one or more rotations of 90 degrees around&lt;br /&gt;
any of the axes, so that the rotation merely swaps axes, one could define&lt;br /&gt;
the inverse of A_B_scale by applying that rotation to that vector (swapping&lt;br /&gt;
the scaling factors), next to inverting each factor individually.&lt;br /&gt;
That is a different way of how we defined B_A_scale, but it would collapse&lt;br /&gt;
the two sets into one for that special set of rotations. I&#039;m using that trick&lt;br /&gt;
in the example script below.&lt;br /&gt;
&lt;br /&gt;
=== Direction vectors ===&lt;br /&gt;
&lt;br /&gt;
A &#039;direction&#039; is a normalized vector (its length is 1), or unit vector, where only the direction&lt;br /&gt;
it points to is important.&lt;br /&gt;
&lt;br /&gt;
Of course, in the light of rotations between coordinate systems, also the directions&lt;br /&gt;
are relative to some coordinate system.&lt;br /&gt;
&lt;br /&gt;
As stated before, using some &#039;starting&#039; unit vector a rotation can be expressed&lt;br /&gt;
as a direction by applying the rotation to a starting vector. Reversing this&lt;br /&gt;
process runs into floating point round off errors however, or might even have lost&lt;br /&gt;
all information of the rotation when we rotate around the starting vector itself.&lt;br /&gt;
&lt;br /&gt;
There is a better way to convert directions (back) to a rotation however: by using &#039;&#039;two&#039;&#039;&lt;br /&gt;
directions that are perpendicular, each having a unit vector along one of the axes&lt;br /&gt;
as starting vector. That way there is always at least one vector enough rotated away&lt;br /&gt;
from the actual rotation axis in order not to suffer from (too much) information loss.&lt;br /&gt;
&lt;br /&gt;
For example, let us use the unit vector along the positive X axis and the unit vector&lt;br /&gt;
along the positive Z axis. In LSL those are often called fwd and up respectively.&lt;br /&gt;
Furthermore, lets work in a coordinate system A. Then we have the &#039;starting&#039; vectors:&lt;br /&gt;
&lt;br /&gt;
 &#039;&#039;&#039;vector A_fwd_A  = &amp;lt;1, 0, 0&amp;gt;;&#039;&#039;&#039;&lt;br /&gt;
 &#039;&#039;&#039;vector A_left_A = &amp;lt;0, 1, 0&amp;gt;;&#039;&#039;&#039;&lt;br /&gt;
 &#039;&#039;&#039;vector A_up_A   = &amp;lt;0, 0, 1&amp;gt;;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
We said we only knew the fwd and up directions, but the third can always be&lt;br /&gt;
calculated from the other two with a cross product:&lt;br /&gt;
&lt;br /&gt;
 &#039;&#039;&#039;A_fwd_B  = A_left_B % A_up_B;&#039;&#039;&#039;&lt;br /&gt;
 &#039;&#039;&#039;A_left_B = A_up_B % A_fwd_B;&#039;&#039;&#039;&lt;br /&gt;
 &#039;&#039;&#039;A_up_B   = A_fwd_B % A_left_B;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Hence, the cross product exists of the other two in the order left to right where after &#039;up&#039; you start at &#039;fwd&#039; again; they rotate: ... left up fwd left up fwd ...&lt;br /&gt;
Put a &#039;=&#039; at any space in that sequence and a &#039;%&#039; at the next space and you have the right formula. Also note that x % y = - y % x, in case you were wondering.&lt;br /&gt;
&lt;br /&gt;
Now assume we have the target directions A_*_B, then we can find the rotation between&lt;br /&gt;
A and B with:&lt;br /&gt;
&lt;br /&gt;
 &#039;&#039;&#039;A_rot_B = [[llAxes2Rot]](A_fwd_B, A_left_B, A_up_B);&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Where A_rot_B is the rotation that turns A_*_A into A_*_B:&lt;br /&gt;
&lt;br /&gt;
 A_fwd_B  = A_fwd_A  * A_rot_B&lt;br /&gt;
 A_left_B = A_left_A * A_rot_B&lt;br /&gt;
 A_up_B   = A_up_A   * A_rot_B&lt;br /&gt;
&lt;br /&gt;
=== Finding coordinate systems ===&lt;br /&gt;
&lt;br /&gt;
Assume you already have a coordinate system B (for example, region or object coordinates, the orientations of which you can find directly with [[#LSL functions]]).&lt;br /&gt;
&lt;br /&gt;
Finding coordinate system A means that you find A_rot_B (or B_rot_A which is just the inverse), and A_pos_B or B_pos_A.&lt;br /&gt;
&lt;br /&gt;
Finding the rotation is usually the easiest since it doesn&#039;t depend on where the origin is and can most likely&lt;br /&gt;
be derived somehow. For example, in many cases you will have two orthogonal direction vectors in B that you know&lt;br /&gt;
to be parallel with the x, y or z axes of A. Lets say that you have AsX_dir_B and a AsY_dir_B that make an angle&lt;br /&gt;
of 90 degrees and have a length of 1, where AsX_dir_B is known to be parallel with the X axis of A and AsY_dir_B&lt;br /&gt;
is known to be parallel with the Y axis of A. Note that in this case we can also use the notation A_fwd_B for AsX_dir_B since&lt;br /&gt;
&#039;fwd&#039; is in the X direction (AsX_dir_B means &amp;quot;A&#039;s X-axis direction in coordinates of B&amp;quot;, and A_fwd_B means &amp;quot;A&#039;s&lt;br /&gt;
forwards direction in coordinates of B&amp;quot;, so they are the same thing). Then we find:&lt;br /&gt;
&lt;br /&gt;
 A_rot_B = [[llAxes2Rot]](AsX_dir_B, AsY_dir_B, AsX_dir_B % AsY_dir_B);&lt;br /&gt;
&lt;br /&gt;
as discussed in the previous paragraph.&lt;br /&gt;
&lt;br /&gt;
Next, if you have a vector from_B_to_A pointing from the origin of B to the origin of A, then you have&lt;br /&gt;
the translation between A and B too:&lt;br /&gt;
&lt;br /&gt;
If from_B_to_A is in coordinates of A, then&lt;br /&gt;
&lt;br /&gt;
 B_pos_A = -from_B_to_A&lt;br /&gt;
&lt;br /&gt;
while if from_B_to_A is in coordinates of B, then&lt;br /&gt;
&lt;br /&gt;
 A_pos_B = from_B_to_A&lt;br /&gt;
&lt;br /&gt;
Slight counter intuitive you have to read &#039;A_pos_B&#039; as &#039;The vector pointing from the origin of B to the origin of A&#039;,&lt;br /&gt;
but plausible since it is in the coordinates of B and thus you should expect the vector to start in the origin&lt;br /&gt;
of B.&lt;br /&gt;
&lt;br /&gt;
If you have a series of vectors that are stacked, all the way from B to A, then of course you just add them all up&lt;br /&gt;
to get A_pos_B. Likewise, if you have a series of vectors in the coordinates of A that are stacked to add up&lt;br /&gt;
to go from A to B, then add them all up to get B_pos_A.&lt;br /&gt;
&lt;br /&gt;
The interesting case therefore is where you have a vector C_pos_A that points from A to C and is in the coordinates&lt;br /&gt;
of A, and a vector C_pos_B that points from B to C and is in the coordinates of B.&lt;br /&gt;
&lt;br /&gt;
To solve this puzzle, lets first write the vectors slightly different so we&#039;re not confused about&lt;br /&gt;
what they mean, even after converting between the coordinate systems A and B.&lt;br /&gt;
&lt;br /&gt;
Let AC_vec_A be C_pos_A: the vector (arrow) from the origin of A to C (in coordinates of A) and&lt;br /&gt;
let BC_vec_B be C_pos_B: the vector from the origin of B to C (in the coordinates of B).&lt;br /&gt;
Note how the notation of _vec_ is similar to that of _dir_, except that a direction vector has&lt;br /&gt;
a length of 1, and this vector has both a direction and a length: it describes how to get from&lt;br /&gt;
one point to another. Like directions, when converting them between A and B you ONLY&lt;br /&gt;
apply the rotation A_rot_B! Also note that a vector with a minus sign just means &amp;quot;in the opposite direction&amp;quot;,&lt;br /&gt;
hence CA_vec_A = -AC_vec_A.&lt;br /&gt;
&lt;br /&gt;
Thus, we find that&lt;br /&gt;
&lt;br /&gt;
 AC_vec_B = AC_vec_A * A_rot_B&lt;br /&gt;
&lt;br /&gt;
and find&lt;br /&gt;
&lt;br /&gt;
 A_pos_B = BA_vec_B = BC_vec_B + CA_vec_B = BC_vec_B - AC_vec_B = BC_vec_B - AC_vec_A * A_rot_B&lt;br /&gt;
&lt;br /&gt;
then dropping the extra notation again&lt;br /&gt;
&lt;br /&gt;
 &#039;&#039;&#039;A_pos_B = C_pos_B - C_pos_A * A_rot_B&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Which is rather logical when you read it in English as &amp;quot;To go from B to A in coordinates of B (A_pos_B),&lt;br /&gt;
you first go from B to C in coordinates of B (C_pos_B) and then in the opposite direction (the minus sign)&lt;br /&gt;
of going from A to C (namely from C to A) converted to the coordinates of B.&lt;br /&gt;
&lt;br /&gt;
And oh wonder - if we write this result a little different we find:&lt;br /&gt;
&lt;br /&gt;
 C_pos_A = (C_pos_B - A_pos_B) / A_rot_B&lt;br /&gt;
&lt;br /&gt;
which is the normal conversion (formula (3)) for the position of C from A to B coordinates!&lt;br /&gt;
&lt;br /&gt;
=== LSL functions ===&lt;br /&gt;
&lt;br /&gt;
What all of the above taught you is mainly a coding style: use prefixes and postfixes for your rotations (and translations)!&lt;br /&gt;
It&#039;s all in the &#039;&#039;&#039;&#039;&#039;names&#039;&#039;&#039;&#039;&#039; of your variables. A &#039;rotation&#039; type can be the rotation part of a transformation&lt;br /&gt;
(not tied to a particular coordinate system, but rather rotating around whatever coordinate system you apply it to),&lt;br /&gt;
it can be the representation of a unit vector, it can be the rotation part of the orientation of a prim relative to a&lt;br /&gt;
given coordinate system, or it can represent the rotation part of a coordinate system conversion.&lt;br /&gt;
If you don&#039;t use a consistent way to reflect all that in your variable names then you &#039;&#039;will&#039;&#039; get confused.&lt;br /&gt;
&lt;br /&gt;
The LSL functions mostly deal with two types: orientations (position + rotation) of prims relative to some coordinate system,&lt;br /&gt;
and simply transformations (rotation and/or translation).&lt;br /&gt;
&lt;br /&gt;
The table below shows the coordinate systems involved.&lt;br /&gt;
&lt;br /&gt;
{| rules=&amp;quot;all&amp;quot; style=&amp;quot;margin:2em 1em 2em 1em; border:none 2px #000000; background-color:#F9F9F9; font-size:120%; empty-cells:hide;&amp;quot;&lt;br /&gt;
 |-&lt;br /&gt;
 | colspan=2 |&lt;br /&gt;
 | style=&amp;quot;padding: 5px 10px 5px 10px; background-color: #ffdddd; text-align: center&amp;quot; colspan=2 | Coordinates of the prim containing the script (&#039;&#039;&#039;sc_&#039;&#039;&#039;)&lt;br /&gt;
 |- {{Hl2}}&lt;br /&gt;
 ! style=&amp;quot;padding: 5px 10px 5px 10px; color: blue; background-color: #eeeeb0&amp;quot; | Coordinate System&lt;br /&gt;
 ! style=&amp;quot;padding: 5px 10px 5px 10px; color: green; background-color: lightgray&amp;quot; | Abbreviation &lt;br /&gt;
 ! style=&amp;quot;padding: 5px 10px 5px 10px&amp;quot; | script in child prim&lt;br /&gt;
 ! style=&amp;quot;padding: 5px 10px 5px 10px&amp;quot; | script in root prim&lt;br /&gt;
 |-&lt;br /&gt;
 | style=&amp;quot;padding: 5px 10px 5px 10px; color: blue; background-color: #ffffa0&amp;quot; | World/Map Coordinates&lt;br /&gt;
 | style=&amp;quot;padding: 5px 10px 5px 10px&amp;quot;                                         | &#039;&#039;&#039;wc&#039;&#039;&#039;&lt;br /&gt;
 | style=&amp;quot;padding: 5px 10px 5px 10px&amp;quot; colspan=2                               | &amp;lt;span style=&amp;quot;font-family: mono; font-size: 90%&amp;quot;&amp;gt;sc_pos_&#039;&#039;&#039;wc&#039;&#039;&#039; = sc_pos_rc + [[llGetRegionCorner]]()&amp;lt;br&amp;gt;sc_rot_&#039;&#039;&#039;wc&#039;&#039;&#039; = sc_rot_rc&amp;lt;/span&amp;gt;&lt;br /&gt;
 |-&lt;br /&gt;
 | style=&amp;quot;padding: 5px 10px 5px 10px; color: blue; background-color: #ffffa0&amp;quot; | Region Coordinates&lt;br /&gt;
 | style=&amp;quot;padding: 5px 10px 5px 10px&amp;quot;                                         | &#039;&#039;&#039;rc&#039;&#039;&#039;&lt;br /&gt;
 | style=&amp;quot;padding: 5px 10px 5px 10px&amp;quot; colspan=2                               | &amp;lt;span style=&amp;quot;font-family: mono; font-size: 90%&amp;quot;&amp;gt;sc_pos_&#039;&#039;&#039;rc&#039;&#039;&#039; = [[llGetPos]]()&amp;lt;br&amp;gt;sc_rot_&#039;&#039;&#039;rc&#039;&#039;&#039; = [[llGetRot]]()&amp;lt;/span&amp;gt;&lt;br /&gt;
 |-&lt;br /&gt;
 | style=&amp;quot;padding: 5px 10px 5px 10px; color: blue; background-color: #ffffa0&amp;quot; | Object/Root Coordinates&lt;br /&gt;
 | style=&amp;quot;padding: 5px 10px 5px 10px&amp;quot;                                         | &#039;&#039;&#039;oc&#039;&#039;&#039;&lt;br /&gt;
 | style=&amp;quot;padding: 5px 10px 5px 10px&amp;quot;                                         | &amp;lt;span style=&amp;quot;font-family: mono; font-size: 90%&amp;quot;&amp;gt;sc_pos_&#039;&#039;&#039;oc&#039;&#039;&#039; = [[llGetLocalPos]]()&amp;lt;br&amp;gt;sc_rot_&#039;&#039;&#039;oc&#039;&#039;&#039; = [[llGetLocalRot]]()&amp;lt;/span&amp;gt;&lt;br /&gt;
 | style=&amp;quot;padding: 5px 10px 5px 10px&amp;quot;                                         | &amp;lt;span style=&amp;quot;font-family: mono; font-size: 90%&amp;quot;&amp;gt;sc_pos_&#039;&#039;&#039;oc&#039;&#039;&#039; = [[ZERO_VECTOR]]&amp;lt;br&amp;gt;sc_rot_&#039;&#039;&#039;oc&#039;&#039;&#039; = [[ZERO_ROTATION]]&amp;lt;/span&amp;gt;&lt;br /&gt;
 |-&lt;br /&gt;
 | style=&amp;quot;padding: 5px 10px 5px 10px; color: blue; background-color: #ffffa0&amp;quot; | Self Coordinates&lt;br /&gt;
 | style=&amp;quot;padding: 5px 10px 5px 10px&amp;quot;                                         | &#039;&#039;&#039;sc&#039;&#039;&#039;&lt;br /&gt;
 | style=&amp;quot;padding: 5px 10px 5px 10px&amp;quot; colspan=2                               | &amp;lt;span style=&amp;quot;font-family: mono; font-size: 90%&amp;quot;&amp;gt;sc_pos_&#039;&#039;&#039;sc&#039;&#039;&#039; = [[ZERO_VECTOR]]&amp;lt;br&amp;gt;sc_rot_&#039;&#039;&#039;sc&#039;&#039;&#039; = [[ZERO_ROTATION]]&amp;lt;/span&amp;gt;&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
Where &#039;in the root prim&#039; can be detect by testing that [[llGetLinkNumber]]() returns a value &amp;lt;= 1.&lt;br /&gt;
&lt;br /&gt;
Alternatively, you can set link = [[llGetLinkNumber]]() and use the following table which&lt;br /&gt;
shows how to obtain the coordinates of a prim with link number &#039;link&#039; from a script anywhere in the same object.&lt;br /&gt;
Note that this doesn&#039;t work when the object exist of a single prim: then [[llGetLinkNumber]]() returns 0,&lt;br /&gt;
while &#039;link&#039; must be larger than 0 here. If you need to get Object Coordinates (_oc) then do not use the&lt;br /&gt;
negative value [[LINK_THIS]]. You can use [[LINK_THIS]] for the other coordinate systems, provided&lt;br /&gt;
the object exists of at least two prims.&lt;br /&gt;
&lt;br /&gt;
{| rules=&amp;quot;all&amp;quot; style=&amp;quot;margin:2em 1em 2em 1em; border:none 2px #000000; background-color:#F9F9F9; font-size:120%; empty-cells:hide;&amp;quot;&lt;br /&gt;
 |-&lt;br /&gt;
 | colspan=2 |&lt;br /&gt;
 | style=&amp;quot;padding: 5px 10px 5px 10px; background-color: #ffdddd; text-align: center&amp;quot; colspan=2 | Coordinates of a linked prim (&#039;&#039;&#039;link_&#039;&#039;&#039;)&lt;br /&gt;
 |- {{Hl2}}&lt;br /&gt;
 ! style=&amp;quot;padding: 5px 10px 5px 10px; color: blue; background-color: #eeeeb0&amp;quot; | Coordinate System&lt;br /&gt;
 ! style=&amp;quot;padding: 5px 10px 5px 10px; color: green; background-color: lightgray&amp;quot; | Abbreviation &lt;br /&gt;
 ! style=&amp;quot;padding: 5px 10px 5px 10px&amp;quot; | link &amp;gt; 1&lt;br /&gt;
 ! style=&amp;quot;padding: 5px 10px 5px 10px&amp;quot; | link = 1&lt;br /&gt;
 |-&lt;br /&gt;
 | style=&amp;quot;padding: 5px 10px 5px 10px; color: blue; background-color: #ffffa0&amp;quot; | World/Map Coordinates&lt;br /&gt;
 | style=&amp;quot;padding: 5px 10px 5px 10px&amp;quot;                                         | &#039;&#039;&#039;wc&#039;&#039;&#039;&lt;br /&gt;
 | style=&amp;quot;padding: 5px 10px 5px 10px&amp;quot; colspan=2                               | &amp;lt;span style=&amp;quot;font-family: mono; font-size: 90%&amp;quot;&amp;gt;link_pos_&#039;&#039;&#039;wc&#039;&#039;&#039; = link_pos_rc + [[llGetRegionCorner]]()&amp;lt;br&amp;gt;link_rot_&#039;&#039;&#039;wc&#039;&#039;&#039; = link_rot_rc&amp;lt;/span&amp;gt;&lt;br /&gt;
 |-&lt;br /&gt;
 | style=&amp;quot;padding: 5px 10px 5px 10px; color: blue; background-color: #ffffa0&amp;quot; | Region Coordinates&lt;br /&gt;
 | style=&amp;quot;padding: 5px 10px 5px 10px&amp;quot;                                         | &#039;&#039;&#039;rc&#039;&#039;&#039;&lt;br /&gt;
 | style=&amp;quot;padding: 5px 10px 5px 10px&amp;quot; colspan=2                               | &amp;lt;span style=&amp;quot;font-family: mono; font-size: 90%&amp;quot;&amp;gt;link_pos_&#039;&#039;&#039;rc&#039;&#039;&#039; = [[llList2Vector]]([[llGetLinkPrimitiveParams]](&#039;&#039;&#039;link&#039;&#039;&#039;, [&amp;lt;span&amp;gt;&amp;lt;/span&amp;gt;[[PRIM_POSITION]]]), 0)&amp;lt;br&amp;gt;link_rot_&#039;&#039;&#039;rc&#039;&#039;&#039; = [[llList2Rot]]([[llGetLinkPrimitiveParams]](&#039;&#039;&#039;link&#039;&#039;&#039;, [&amp;lt;span&amp;gt;&amp;lt;/span&amp;gt;[[PRIM_ROTATION]]]), 0)&amp;lt;/span&amp;gt;&lt;br /&gt;
 |-&lt;br /&gt;
 | style=&amp;quot;padding: 5px 10px 5px 10px; color: blue; background-color: #ffffa0&amp;quot; | Object/Root Coordinates&lt;br /&gt;
 | style=&amp;quot;padding: 5px 10px 5px 10px&amp;quot;                                         | &#039;&#039;&#039;oc&#039;&#039;&#039;&lt;br /&gt;
 | style=&amp;quot;padding: 5px 10px 5px 10px&amp;quot;                                         | &amp;lt;span style=&amp;quot;font-family: mono; font-size: 90%&amp;quot;&amp;gt;link_pos_&#039;&#039;&#039;oc&#039;&#039;&#039; = [[llList2Vector]]([[llGetLinkPrimitiveParams]](&#039;&#039;&#039;link&#039;&#039;&#039;, [&amp;lt;span&amp;gt;&amp;lt;/span&amp;gt;[[PRIM_POS_LOCAL]]]), 0)&amp;lt;br&amp;gt;link_rot_&#039;&#039;&#039;oc&#039;&#039;&#039; = [[llList2Rot]]([[llGetLinkPrimitiveParams]](&#039;&#039;&#039;link&#039;&#039;&#039;, [&amp;lt;span&amp;gt;&amp;lt;/span&amp;gt;[[PRIM_ROT_LOCAL]]]), 0)&amp;lt;/span&amp;gt;&lt;br /&gt;
 | style=&amp;quot;padding: 5px 10px 5px 10px&amp;quot;                                         | &amp;lt;span style=&amp;quot;font-family: mono; font-size: 90%&amp;quot;&amp;gt;link_pos_&#039;&#039;&#039;oc&#039;&#039;&#039; = [[ZERO_VECTOR]]&amp;lt;br&amp;gt;link_rot_&#039;&#039;&#039;oc&#039;&#039;&#039; = [[ZERO_ROTATION]]&amp;lt;/span&amp;gt;&lt;br /&gt;
 |-&lt;br /&gt;
 | style=&amp;quot;padding: 5px 10px 5px 10px; color: blue; background-color: #ffffa0&amp;quot; | Self Coordinates&lt;br /&gt;
 | style=&amp;quot;padding: 5px 10px 5px 10px&amp;quot;                                         | &#039;&#039;&#039;sc&#039;&#039;&#039;&lt;br /&gt;
 | style=&amp;quot;padding: 5px 10px 5px 10px&amp;quot; colspan=2                               | &amp;lt;span style=&amp;quot;font-family: mono; font-size: 90%&amp;quot;&amp;gt;link_pos_&#039;&#039;&#039;sc&#039;&#039;&#039; = (link_pos_oc - sc_pos_oc) / sc_rot_oc&amp;lt;br&amp;gt;link_rot_&#039;&#039;&#039;sc&#039;&#039;&#039; = link_rot_oc / sc_rot_oc&amp;lt;/span&amp;gt;&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
While the above table works for link = [[LINK_ROOT]], it is probably more convenient to use the following table:&lt;br /&gt;
&lt;br /&gt;
{| rules=&amp;quot;all&amp;quot; style=&amp;quot;margin:2em 1em 2em 1em; border:none 2px #000000; background-color:#F9F9F9; font-size:120%; empty-cells:hide;&amp;quot;&lt;br /&gt;
 |-&lt;br /&gt;
 | colspan=2 |&lt;br /&gt;
 | style=&amp;quot;padding: 5px 10px 5px 10px; background-color: #ffdddd; text-align: center&amp;quot; colspan=2 | Coordinates of the root prim (&#039;&#039;&#039;oc_&#039;&#039;&#039;)&lt;br /&gt;
 |- {{Hl2}}&lt;br /&gt;
 ! style=&amp;quot;padding: 5px 10px 5px 10px; color: blue; background-color: #eeeeb0&amp;quot; | Coordinate System&lt;br /&gt;
 ! style=&amp;quot;padding: 5px 10px 5px 10px; color: green; background-color: lightgray&amp;quot; | Abbreviation &lt;br /&gt;
 ! style=&amp;quot;padding: 5px 10px 5px 10px&amp;quot; | script in any prim&lt;br /&gt;
 |-&lt;br /&gt;
 | style=&amp;quot;padding: 5px 10px 5px 10px; color: blue; background-color: #ffffa0&amp;quot; | World/Map Coordinates&lt;br /&gt;
 | style=&amp;quot;padding: 5px 10px 5px 10px&amp;quot;                                         | &#039;&#039;&#039;wc&#039;&#039;&#039;&lt;br /&gt;
 | style=&amp;quot;padding: 5px 10px 5px 10px&amp;quot;                                         | &amp;lt;span style=&amp;quot;font-family: mono; font-size: 90%&amp;quot;&amp;gt;oc_pos_&#039;&#039;&#039;wc&#039;&#039;&#039; = oc_pos_rc + [[llGetRegionCorner]]()&amp;lt;br&amp;gt;oc_rot_&#039;&#039;&#039;wc&#039;&#039;&#039; = oc_rot_rc&amp;lt;/span&amp;gt;&lt;br /&gt;
 |-&lt;br /&gt;
 | style=&amp;quot;padding: 5px 10px 5px 10px; color: blue; background-color: #ffffa0&amp;quot; | Region Coordinates&lt;br /&gt;
 | style=&amp;quot;padding: 5px 10px 5px 10px&amp;quot;                                         | &#039;&#039;&#039;rc&#039;&#039;&#039;&lt;br /&gt;
 | style=&amp;quot;padding: 5px 10px 5px 10px&amp;quot;                                         | &amp;lt;span style=&amp;quot;font-family: mono; font-size: 90%&amp;quot;&amp;gt;oc_pos_&#039;&#039;&#039;rc&#039;&#039;&#039; = [[llGetRootPosition]]()&amp;lt;br&amp;gt;oc_rot_&#039;&#039;&#039;rc&#039;&#039;&#039; = [[llGetRootRotation]]()&amp;lt;/span&amp;gt;&lt;br /&gt;
 |-&lt;br /&gt;
 | style=&amp;quot;padding: 5px 10px 5px 10px; color: blue; background-color: #ffffa0&amp;quot; | Object/Root Coordinates&lt;br /&gt;
 | style=&amp;quot;padding: 5px 10px 5px 10px&amp;quot;                                         | &#039;&#039;&#039;oc&#039;&#039;&#039;&lt;br /&gt;
 | style=&amp;quot;padding: 5px 10px 5px 10px&amp;quot;                                         | &amp;lt;span style=&amp;quot;font-family: mono; font-size: 90%&amp;quot;&amp;gt;oc_pos_&#039;&#039;&#039;oc&#039;&#039;&#039; = [[ZERO_VECTOR]]&amp;lt;br&amp;gt;oc_rot_&#039;&#039;&#039;oc&#039;&#039;&#039; = [[ZERO_ROTATION]]&amp;lt;/span&amp;gt;&lt;br /&gt;
 |-&lt;br /&gt;
 | style=&amp;quot;padding: 5px 10px 5px 10px; color: blue; background-color: #ffffa0&amp;quot; | Self Coordinates&lt;br /&gt;
 | style=&amp;quot;padding: 5px 10px 5px 10px&amp;quot;                                         | &#039;&#039;&#039;sc&#039;&#039;&#039;&lt;br /&gt;
 | style=&amp;quot;padding: 5px 10px 5px 10px&amp;quot;                                         | &amp;lt;span style=&amp;quot;font-family: mono; font-size: 90%&amp;quot;&amp;gt;oc_pos_&#039;&#039;&#039;sc&#039;&#039;&#039; = - sc_pos_oc / sc_rot_oc&amp;lt;br&amp;gt;oc_rot_&#039;&#039;&#039;sc&#039;&#039;&#039; = [[ZERO_ROTATION]] / sc_rot_oc&amp;lt;/span&amp;gt;&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
As shows from the above table, LSL does not directly support &#039;&#039;&#039;_sc&#039;&#039;&#039; coordinates,&lt;br /&gt;
and I used conversions to fill in the tables. All in all, we listed four coordinate systems (wc, rc, oc and sc; not including the &#039;link_&#039; stuff,&lt;br /&gt;
which isn&#039;t really a separate coordinate system)&lt;br /&gt;
and thus could write out four times four is sixteen ways to convert one into the other. Four of those would be trivial, and of the remaining&lt;br /&gt;
twelve we can express six as the inverse of the other six.&lt;br /&gt;
&lt;br /&gt;
However, lets ignore the World Coordinates for now, which are just the same as the Region Coordinates with an offset for the position.&lt;br /&gt;
Then we have three coordinate systems (rc, oc and sc), leading to nine conversion, three of which are trivial, and of the remaining&lt;br /&gt;
six three can be expressed as the inverse of the other three. Those three are: oc_*_rc, sc_*_rc and sc_*_oc, which are all listed above.&lt;br /&gt;
The trivial ones, rc_*_rc, oc_*_oc and sc_*_sc, are all ZERO_* (the latter two also are listed in the tables above).&lt;br /&gt;
Finally, the inverse values, rc_*_oc, rc_*_sc and oc_*_sc can be expressed with the inversion formula given in [[#Converting between coordinate systems]].&lt;br /&gt;
So this is really all there is.&lt;br /&gt;
&lt;br /&gt;
=== The fourth dimension ===&lt;br /&gt;
&lt;br /&gt;
Picture a coordinate system as three perpendicular lines, like an object in-world perhaps existing of&lt;br /&gt;
three really long prims in the colors red, green and blue. You can toss them into the region&lt;br /&gt;
where they randomly bounce around like dice &amp;amp;ndash; a whole bunch of them!&lt;br /&gt;
And then you freeze time - make a snapshot.&lt;br /&gt;
&lt;br /&gt;
With the knowledge so far you can now express the position and rotation of an object or prim relative&lt;br /&gt;
to any of those coordinate systems &amp;amp;ndash; and convert between them at will.&lt;br /&gt;
Apply rotations and translations relative to any chosen system.&lt;br /&gt;
All of the coordinate systems are virtually the same! But in practice this isn&#039;t the case, why is that?&lt;br /&gt;
&lt;br /&gt;
The reason is that in practice coordinate systems change in time, in a way that you cannot predict.&lt;br /&gt;
It&#039;s like they are still tumbling and bouncing around and you have no idea where they are.&lt;br /&gt;
&lt;br /&gt;
This noise comes mainly from one thing: objects are being moved. Taken into repositories and rezzed back,&lt;br /&gt;
rotated and possibly even scaled! In fact, not just objects, but also prims inside objects can be changed&lt;br /&gt;
at will at any moment and a good script must take that into account.&lt;br /&gt;
&lt;br /&gt;
The art of programming therefore becomes &#039;&#039;design&#039;&#039;. You must choose which coordinate systems you&lt;br /&gt;
want to use; what your global variables store, relative to which coordinate system.&lt;br /&gt;
&lt;br /&gt;
Unfortunately, a script can &#039;&#039;not&#039;&#039; detect when this might have happened and only perform extra computations&lt;br /&gt;
or re-computation, of otherwise constant variables, when a prim or object has actually been changed.&lt;br /&gt;
There is an LSL event [[moving_start]] but that only works half on SL and not at all on opensim.&lt;br /&gt;
For rotation detection there is nothing.&lt;br /&gt;
&lt;br /&gt;
As such, it is necessary to call the LSL functions listed in the tables above every time you&lt;br /&gt;
want to do anything that depends on them; which hopefully won&#039;t be too often.&lt;br /&gt;
&lt;br /&gt;
The following example script can be put in the root prim of an object of any number of cubes&lt;br /&gt;
and allows one to sit on each cube, using [[llLinkSitTarget]], even when you move or rotate&lt;br /&gt;
child prims.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;lsl&amp;gt;&lt;br /&gt;
// A script written to show how to use coordinate systems in LSL.&lt;br /&gt;
//&lt;br /&gt;
// Copyright(c) Timmy Songbird @DreamNation&lt;br /&gt;
//              Timmy Foxclaw  @SL,&lt;br /&gt;
//              2014&lt;br /&gt;
//&lt;br /&gt;
// This program is free software; you can redistribute it and/or modify&lt;br /&gt;
// it under the terms of the GNU General Public License as published by&lt;br /&gt;
// the Free Software Foundation; either version 2 of the License, or&lt;br /&gt;
// (at your option) any later version.&lt;br /&gt;
//&lt;br /&gt;
// This program is distributed in the hope that it will be useful,&lt;br /&gt;
// but WITHOUT ANY WARRANTY; without even the implied warranty of&lt;br /&gt;
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the&lt;br /&gt;
// GNU General Public License for more details.&lt;br /&gt;
//&lt;br /&gt;
// You should have received a copy of the GNU General Public License&lt;br /&gt;
// along with this program; if not, write to the Free Software&lt;br /&gt;
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307, USA.&#039;)&lt;br /&gt;
&lt;br /&gt;
//----------------------------------------------------------------------------&lt;br /&gt;
//#line &amp;quot;/opt/secondlife/scripts/scripts/tests/llLinkSitTarget_Test.m4s:5&amp;quot;&lt;br /&gt;
// GitLocation: tests/llLinkSitTarget_Test.m4s&lt;br /&gt;
// GitID: 32c3ab5a6f17d96eafe4e110bb91a700e2fd589b&lt;br /&gt;
&lt;br /&gt;
// This script uses the follow coordinate systems:&lt;br /&gt;
//&lt;br /&gt;
// rc     : Region Coordinates.&lt;br /&gt;
// oc     : Object, or root prim, Coordinates.&lt;br /&gt;
// link   : Coordinates of prim with link number &#039;link&#039;.&lt;br /&gt;
// STc    : Coordinates of the touched face (see llDetectedTouchST)&lt;br /&gt;
//          (x and y in the ranger [0, 1] with (0, 0) in the bottom-left corner).&lt;br /&gt;
// center : Coordinates of the touched face with the origin in the center,&lt;br /&gt;
//          the orientation is the same as STc (z is the normal of the surface),&lt;br /&gt;
//          but scaled to be in meters.&lt;br /&gt;
// ac     : Avatar center Coordinates. This is really the same as stc, but&lt;br /&gt;
//          moved up an offset. Rotations passed to llLinkSitTarget are&lt;br /&gt;
//          relative to this coordinate system.&lt;br /&gt;
&lt;br /&gt;
//----------------------------------------------------------------------------&lt;br /&gt;
//#line &amp;quot;/opt/secondlife/scripts/scripts/tests/llLinkSitTarget_Test.m4s:24&amp;quot;&lt;br /&gt;
// The sit position of the sit target.&lt;br /&gt;
// This value is *different* in SL and opensim, and even changed since opensim version 0.7.6.&lt;br /&gt;
// The currently measured values for the z component are:&lt;br /&gt;
// SL: 0.05, opensim 0.7.6: 0.0, opensim 0.8.x: -agentSize.z / 37.9075&lt;br /&gt;
&lt;br /&gt;
// Use this in SL:&lt;br /&gt;
//vector sittarget_pos_ac = &amp;lt;0.0, 0.0, 0.05&amp;gt;;&lt;br /&gt;
//integer opensimver = 0; // SL&lt;br /&gt;
&lt;br /&gt;
// Use this on opensim:&lt;br /&gt;
vector sittarget_pos_ac = &amp;lt;0.0, 0.0, 0.0&amp;gt;;&lt;br /&gt;
//integer opensimver = 7; // Opensim 0.7.6&lt;br /&gt;
integer opensimver = 8; // Opensim &amp;gt;= 0.8&lt;br /&gt;
&lt;br /&gt;
//----------------------------------------------------------------------------&lt;br /&gt;
//#line &amp;quot;/opt/secondlife/scripts/scripts/tests/llLinkSitTarget_Test.m4s:40&amp;quot;&lt;br /&gt;
// face_link() returns a list of vectors in link coordinates.&lt;br /&gt;
//&lt;br /&gt;
// Returns: [bottomLeft_link, topRight_link].&lt;br /&gt;
//&lt;br /&gt;
// bottomLeft_link is the bottom left corner of the given face,&lt;br /&gt;
// that is - the corner where (S, T) = (0, 0).&lt;br /&gt;
// topRight_link is the top right corner of the given face,&lt;br /&gt;
// that is - the corner where (S, T) = (1, 1).&lt;br /&gt;
list face_link(integer link, integer face)&lt;br /&gt;
{&lt;br /&gt;
  list params = llGetLinkPrimitiveParams(link, [PRIM_TYPE, PRIM_SIZE]);&lt;br /&gt;
  vector bottomLeft_link;&lt;br /&gt;
  vector topRight_link;&lt;br /&gt;
  integer prim_type = llList2Integer(params, 0);&lt;br /&gt;
  if (prim_type == PRIM_TYPE_BOX)&lt;br /&gt;
  {&lt;br /&gt;
    topRight_link = llList2Vector(params, 7) * 0.5;&lt;br /&gt;
    if (face == 0)&lt;br /&gt;
    {&lt;br /&gt;
      bottomLeft_link = -topRight_link;&lt;br /&gt;
      bottomLeft_link.z = topRight_link.z;&lt;br /&gt;
    }&lt;br /&gt;
    else if (face == 1)&lt;br /&gt;
    {&lt;br /&gt;
      bottomLeft_link = -topRight_link;&lt;br /&gt;
      topRight_link.y = bottomLeft_link.y;&lt;br /&gt;
    }&lt;br /&gt;
    else if (face == 2)&lt;br /&gt;
    {&lt;br /&gt;
      bottomLeft_link = -topRight_link;&lt;br /&gt;
      bottomLeft_link.x = topRight_link.x;&lt;br /&gt;
    }&lt;br /&gt;
    else if (face == 3)&lt;br /&gt;
    {&lt;br /&gt;
      topRight_link.x = -topRight_link.x;&lt;br /&gt;
      bottomLeft_link = -topRight_link;&lt;br /&gt;
      bottomLeft_link.y = topRight_link.y;&lt;br /&gt;
    }&lt;br /&gt;
    else if (face == 4)&lt;br /&gt;
    {&lt;br /&gt;
      topRight_link.y = -topRight_link.y;&lt;br /&gt;
      bottomLeft_link = -topRight_link;&lt;br /&gt;
      topRight_link.x = bottomLeft_link.x;&lt;br /&gt;
    }&lt;br /&gt;
    else if (face == 5)&lt;br /&gt;
    {&lt;br /&gt;
      topRight_link.y = -topRight_link.y;&lt;br /&gt;
      topRight_link.z = -topRight_link.z;&lt;br /&gt;
      bottomLeft_link = -topRight_link;&lt;br /&gt;
      bottomLeft_link.z = topRight_link.z;&lt;br /&gt;
    }&lt;br /&gt;
    else&lt;br /&gt;
    {&lt;br /&gt;
      llWhisper(0, &amp;quot;This script only supports sitting on boxes without cuts or holes.&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
  else&lt;br /&gt;
  {&lt;br /&gt;
    llWhisper(0, &amp;quot;This script does not work for non-box prims.&amp;quot;);&lt;br /&gt;
  }&lt;br /&gt;
  return [bottomLeft_link, topRight_link];&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
//----------------------------------------------------------------------------&lt;br /&gt;
//#line &amp;quot;/opt/secondlife/scripts/scripts/tests/llLinkSitTarget_Test.m4s:104&amp;quot;&lt;br /&gt;
default&lt;br /&gt;
{&lt;br /&gt;
  touch_start(integer num)&lt;br /&gt;
  {&lt;br /&gt;
    integer n;&lt;br /&gt;
    // Run over everyone that might have touch a prim (it could be more than one!)&lt;br /&gt;
    for (n = 0; n &amp;lt; num; ++n)&lt;br /&gt;
    {&lt;br /&gt;
      // Get the link number of the touch prim.&lt;br /&gt;
      integer link = llDetectedLinkNumber(n);&lt;br /&gt;
&lt;br /&gt;
      // Some conversion variables we need, copied directly from the table above.&lt;br /&gt;
      vector   link_pos_rc = llList2Vector(llGetLinkPrimitiveParams(link, [PRIM_POSITION]), 0);&lt;br /&gt;
      rotation link_rot_rc = llList2Rot(llGetLinkPrimitiveParams(link, [PRIM_ROTATION]), 0);&lt;br /&gt;
&lt;br /&gt;
      // Get the face of the prim that was touched.&lt;br /&gt;
      integer face = llDetectedTouchFace(n);&lt;br /&gt;
      if (face == TOUCH_INVALID_FACE)&lt;br /&gt;
      {&lt;br /&gt;
        llInstantMessage(llDetectedKey(n), &amp;quot;Sorry, your viewer does not support touched faces.&amp;quot;);&lt;br /&gt;
      }&lt;br /&gt;
      else&lt;br /&gt;
      {&lt;br /&gt;
        // llDetectedTouchPos returns the position where an object was touched in Region Coordinates.&lt;br /&gt;
        vector touch_pos_rc = llDetectedTouchPos(n);&lt;br /&gt;
        // Convert that into link coordinates.&lt;br /&gt;
        vector touch_pos_link = (touch_pos_rc - link_pos_rc) / link_rot_rc;&lt;br /&gt;
&lt;br /&gt;
        // llDetectedTouchBinormal returns a normalized, directional vector in Region Coordinates.&lt;br /&gt;
        // So, it&#039;s not a position; it is a direction (dir), really representing a rotation.&lt;br /&gt;
        vector binormal_dir_rc = llDetectedTouchBinormal(n);&lt;br /&gt;
&lt;br /&gt;
        // In general a direction vector can not be converted to a rotation (when the&lt;br /&gt;
        // starting reference vector is (almost) the same as the direction vector, which&lt;br /&gt;
        // might be the case here since we have no idea where the vector is pointing to).&lt;br /&gt;
        // Therefore we just leave it as a vector, but we treat it the same as a rotation:&lt;br /&gt;
        // leave the origin alone and just correct the rotation when converting to the&lt;br /&gt;
        // local coordinate system of the link prim.&lt;br /&gt;
        vector binormal_dir_link = binormal_dir_rc / link_rot_rc; // binormal_dir_rc * rc_rot_link&lt;br /&gt;
&lt;br /&gt;
        // llDetectedTouchNormal returns a normalized, directional vector in Region Coordinates.&lt;br /&gt;
        // It is perpendicular to the surface (pointing outwards) and makes an angle of 90 degrees&lt;br /&gt;
        // with binormal_dir. Here we immediately convert it to _link coordinates.&lt;br /&gt;
        vector normal_dir_link = llDetectedTouchNormal(n) / link_rot_rc;&lt;br /&gt;
&lt;br /&gt;
        // Calculate the tangent vector.&lt;br /&gt;
        vector tangent_dir_link = binormal_dir_link % normal_dir_link;&lt;br /&gt;
&lt;br /&gt;
        // Get the [bottomLeft_link, topRight_link] positions of the surface &#039;face&#039;, in link coordinates.&lt;br /&gt;
        list surface_link = face_link(link, face);&lt;br /&gt;
        vector bottomLeft_pos_link = llList2Vector(surface_link, 0);&lt;br /&gt;
        vector topRight_pos_link = llList2Vector(surface_link, 1);&lt;br /&gt;
&lt;br /&gt;
        // Calculate the center of the surface.&lt;br /&gt;
        vector center_pos_link = (bottomLeft_pos_link + topRight_pos_link) * 0.5;&lt;br /&gt;
&lt;br /&gt;
        // The unit x vector in link coordinates is obviously &amp;lt;1, 0, 0&amp;gt;, center_rot_link is&lt;br /&gt;
        // therefore the rotation that is needed to rotate that to tangent_dir_link, which&lt;br /&gt;
        // represents &amp;lt;1, 0, 0&amp;gt; in center coordinates (the positive S direction).&lt;br /&gt;
        // The positive T direction, or &amp;lt;0, 1, 0&amp;gt; in center coordinates, is the binormal vector.&lt;br /&gt;
        // llAxes2Rot(fwd, left, up) returns the rotation needed to rotate &amp;lt;1, 0, 0&amp;gt; to fwd,&lt;br /&gt;
        // and &amp;lt;0, 1, 0&amp;gt; to left (and thus &amp;lt;0, 0, 1&amp;gt; to up).&lt;br /&gt;
        rotation center_rot_link = llAxes2Rot(tangent_dir_link, binormal_dir_link, normal_dir_link);&lt;br /&gt;
&lt;br /&gt;
        // llDetectedTouchST returns a vector in the plane of the touched surface,&lt;br /&gt;
        // with x and y ranging from 0,0 in the &amp;quot;bottom left&amp;quot; corner till 1,1 for&lt;br /&gt;
        // opposite corner. The value is thus in ST Coordinates.&lt;br /&gt;
        vector touch_pos_STc = llDetectedTouchST(n);&lt;br /&gt;
&lt;br /&gt;
        // Caluclate the size of the surface and rotate it in the plane of the center coordinates.&lt;br /&gt;
        vector center_link_scale = (topRight_pos_link - bottomLeft_pos_link) / center_rot_link;&lt;br /&gt;
&lt;br /&gt;
        // Convert touch_pos to center coordinates.&lt;br /&gt;
        vector touch_pos_center = &amp;lt;(touch_pos_STc.x - 0.5) * center_link_scale.x, (touch_pos_STc.y - 0.5) * center_link_scale.y, 0.0&amp;gt;;&lt;br /&gt;
&lt;br /&gt;
        // Calculate a unit vector from the touch position to the edge.&lt;br /&gt;
        vector edge_dir_center;&lt;br /&gt;
        // Find the nearest edge.&lt;br /&gt;
        vector edge_pos_center = touch_pos_center;&lt;br /&gt;
        if (center_link_scale.x * 0.5 - llFabs(edge_pos_center.x) &amp;gt; center_link_scale.y * 0.5 - llFabs(edge_pos_center.y))&lt;br /&gt;
        {&lt;br /&gt;
          integer positive = llRound(touch_pos_STc.y);&lt;br /&gt;
          edge_pos_center.y = (positive - 0.5) * center_link_scale.y;&lt;br /&gt;
          edge_dir_center = &amp;lt;0, positive * 2 - 1, 0&amp;gt;;&lt;br /&gt;
        }&lt;br /&gt;
        else&lt;br /&gt;
        {&lt;br /&gt;
          integer positive = llRound(touch_pos_STc.x);&lt;br /&gt;
          edge_pos_center.x = (positive - 0.5) * center_link_scale.x;&lt;br /&gt;
          edge_dir_center = &amp;lt;positive * 2 - 1, 0, 0&amp;gt;;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        // Convert edge_dir_center to link coordinates (because llLinkSitTarget takes link coordinates).&lt;br /&gt;
        vector edge_dir_link = edge_dir_center * center_rot_link;&lt;br /&gt;
&lt;br /&gt;
        // Calculate the rotation of the seated avatar from this direction, using the fact that we still have normal_dir_link.&lt;br /&gt;
        // This puts the fwd direction of the avatar in the direction edge_dir (from touch point to nearest edge)&lt;br /&gt;
        // and the up direction of the avatar perpendicular to the touched surface.&lt;br /&gt;
        rotation ac_rot_link = llAxes2Rot(edge_dir_link, normal_dir_link % edge_dir_link, normal_dir_link);&lt;br /&gt;
&lt;br /&gt;
        // Where do we want to sit?&lt;br /&gt;
        // Currently lets just sit where the user clicked, without limits or corrections.&lt;br /&gt;
        vector sit_pos_center = touch_pos_center;&lt;br /&gt;
&lt;br /&gt;
        // Convert the sit position to link coordinates (because llLinkSitTarget takes link coordinates).&lt;br /&gt;
        vector sit_pos_link = sit_pos_center * center_rot_link + center_pos_link;&lt;br /&gt;
&lt;br /&gt;
        // This vector is really a function of avatar shape and what looks&lt;br /&gt;
        // aesthetically pleasing. However, it is only minimal a function&lt;br /&gt;
        // avatar height (the only thing we can roughly know from a script)&lt;br /&gt;
        // and much more a function of shape values that we can&#039;t know.&lt;br /&gt;
        // So for now, just leave this as a constant.&lt;br /&gt;
        //&lt;br /&gt;
        // In ascii art, a sitting avatar looks more or less like this:&lt;br /&gt;
        //                ^&lt;br /&gt;
        //                |z&lt;br /&gt;
        //            ac_ |&lt;br /&gt;
        //               \S           &#039;S&#039; is the sittarget_pos_ac, in SL it is 0.05m above(_ac) &#039;O&#039;.&lt;br /&gt;
        //         &amp;lt;--x---O   ()      &#039;O&#039; is the Origin of ac (Avatar center (attach point) Coordinates).&lt;br /&gt;
        //                |   /|      &#039;*&#039; is the sittarget (as passed to llSitTarget) and is 0.4m below(_link) S.&lt;br /&gt;
        //    sittarget--&amp;gt;*__/_/&lt;br /&gt;
        //               _/   ^__ sit_pos_ac, 0.62 below(_ac) &#039;O&#039;, and 0.34 backwards(_ac).&lt;br /&gt;
        //                |&lt;br /&gt;
        vector sit_pos_ac = &amp;lt;-0.34, 0.0, -0.62&amp;gt;;&lt;br /&gt;
&lt;br /&gt;
        // Correct grid dependent sittarget_pos_ac.&lt;br /&gt;
        if (opensimver == 7)&lt;br /&gt;
        {&lt;br /&gt;
          sittarget_pos_ac.z = 0.0;&lt;br /&gt;
        }&lt;br /&gt;
        else if (opensimver == 8)&lt;br /&gt;
        {&lt;br /&gt;
          vector agentSize = llGetAgentSize(llDetectedKey(n));&lt;br /&gt;
          sittarget_pos_ac.z = agentSize.z / -37.9075; // Constant determined on &amp;quot;OpenSim 0.8.0 Dev&amp;quot;, April 2014.&lt;br /&gt;
          llSay(0, &amp;quot;sittarget_pos_ac = &amp;quot; + (string)sittarget_pos_ac);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        // Find the translation of the ac coordinate system.&lt;br /&gt;
        vector ac_pos_link = sit_pos_link - sit_pos_ac * ac_rot_link;&lt;br /&gt;
&lt;br /&gt;
        // Convert the sittarget from ac coordinates to link coordinates.&lt;br /&gt;
        vector sittarget_pos_link = sittarget_pos_ac * ac_rot_link + ac_pos_link;&lt;br /&gt;
&lt;br /&gt;
        // Grid dependent vertical offset.&lt;br /&gt;
        //&lt;br /&gt;
        // This is a historical offset introduced by Linden Lab from the beginning.&lt;br /&gt;
        // It is actually a mistake because when the avatar is rotated this causes&lt;br /&gt;
        // the avatar to move sideways! Apparently also Philips Linden found rotations&lt;br /&gt;
        // hard to understand.&lt;br /&gt;
        if (opensimver == 7)&lt;br /&gt;
        {&lt;br /&gt;
          // opensim version 0.7.6&lt;br /&gt;
          // Obviously, this should have been the same as on SL.&lt;br /&gt;
          // Later it got &amp;quot;corrected&amp;quot;, but in a wrong way (sittarget_pos_ac still differs with SL).&lt;br /&gt;
          sittarget_pos_link.z -= 0.418;&lt;br /&gt;
        }&lt;br /&gt;
        else&lt;br /&gt;
        {&lt;br /&gt;
          // SL and opensim &amp;gt;= 0.8.&lt;br /&gt;
          sittarget_pos_link.z -= 0.4;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        // Set the sit target.&lt;br /&gt;
        llLinkSitTarget(link, sittarget_pos_link, ac_rot_link);&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/lsl&amp;gt;&lt;/div&gt;</summary>
		<author><name>Timmy Foxclaw</name></author>
	</entry>
	<entry>
		<id>https://wiki.secondlife.com/w/index.php?title=User:Timmy_Foxclaw&amp;diff=1188839</id>
		<title>User:Timmy Foxclaw</title>
		<link rel="alternate" type="text/html" href="https://wiki.secondlife.com/w/index.php?title=User:Timmy_Foxclaw&amp;diff=1188839"/>
		<updated>2014-03-28T01:00:51Z</updated>

		<summary type="html">&lt;p&gt;Timmy Foxclaw: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;* [[User:Timmy_Foxclaw/About_Coordinate_Systems_and_Rotations|About Coordinate Systems and Rotations]]&lt;/div&gt;</summary>
		<author><name>Timmy Foxclaw</name></author>
	</entry>
	<entry>
		<id>https://wiki.secondlife.com/w/index.php?title=User:Timmy_Foxclaw&amp;diff=1188838</id>
		<title>User:Timmy Foxclaw</title>
		<link rel="alternate" type="text/html" href="https://wiki.secondlife.com/w/index.php?title=User:Timmy_Foxclaw&amp;diff=1188838"/>
		<updated>2014-03-28T00:57:19Z</updated>

		<summary type="html">&lt;p&gt;Timmy Foxclaw: Created page with &amp;quot;* User:Timmy_Foxclaw/About_Coordinate_Systems_and_Rotations, About Coordinate Systems and Rotations&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;* [[User:Timmy_Foxclaw/About_Coordinate_Systems_and_Rotations, About Coordinate Systems and Rotations]]&lt;/div&gt;</summary>
		<author><name>Timmy Foxclaw</name></author>
	</entry>
	<entry>
		<id>https://wiki.secondlife.com/w/index.php?title=User:Timmy_Foxclaw/About_Coordinate_Systems_and_Rotations&amp;diff=1188837</id>
		<title>User:Timmy Foxclaw/About Coordinate Systems and Rotations</title>
		<link rel="alternate" type="text/html" href="https://wiki.secondlife.com/w/index.php?title=User:Timmy_Foxclaw/About_Coordinate_Systems_and_Rotations&amp;diff=1188837"/>
		<updated>2014-03-28T00:53:34Z</updated>

		<summary type="html">&lt;p&gt;Timmy Foxclaw: An LSL tutorial on how to work with rotations.&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== About Coordinate Systems and Rotations ==&lt;br /&gt;
&lt;br /&gt;
=== The four coordinate systems ===&lt;br /&gt;
&lt;br /&gt;
There are four coordinate systems that are related to LSL programming:&lt;br /&gt;
# World coordinates&lt;br /&gt;
# Region coordinates&lt;br /&gt;
# Object coordinates (root prim coordinates)&lt;br /&gt;
# Child prim coordinates (coordinates relative to the prim that the script is in, or refers to by link number)&lt;br /&gt;
&lt;br /&gt;
The World coordinates refer to the map, and allow to include the sim&lt;br /&gt;
in the coordinates, or refer to void water.&lt;br /&gt;
&lt;br /&gt;
Region coordinates are relative to a given sim.&lt;br /&gt;
The origin is in the South/West corner at height 0.&lt;br /&gt;
The North/East corner then is 256, 256 and a Z coordinate&lt;br /&gt;
for the height up to 4096 meter (on opensim you can go even&lt;br /&gt;
higher).&lt;br /&gt;
&lt;br /&gt;
Object coordinates are relative to the root prim. Hence, if the object&lt;br /&gt;
is moved or rotated then the orientation of a child prim, when given&lt;br /&gt;
in object coordinates, doesn&#039;t change. In LSL &amp;quot;local position&amp;quot; and&lt;br /&gt;
&amp;quot;local rotation&amp;quot; refer to this coordinate system. &amp;quot;local&amp;quot; means&lt;br /&gt;
relative to the root prim.&lt;br /&gt;
&lt;br /&gt;
Prim Coordinates are relative to a given prim. If this prim is the root&lt;br /&gt;
prim then the Prim Coordinates are the same as the Object Coordinates.&lt;br /&gt;
For example, if a child prim is a cube with a size of 1,1,1 and one&lt;br /&gt;
red surface where the center of that surface is at 1,0,0 then it will&lt;br /&gt;
still be at 1,0,0 no matter how you move or rotate that child prim&lt;br /&gt;
(relative to the other linked prims).&lt;br /&gt;
&lt;br /&gt;
=== Positions ===&lt;br /&gt;
&lt;br /&gt;
A different position of the origin of a coordinate system is easy to understand:&lt;br /&gt;
You can think of positions as vectors that start in the origin of the&lt;br /&gt;
coordinate system that they are given in and end in the point that they&lt;br /&gt;
refer to. While the length of the vector is independent of the rotation of&lt;br /&gt;
the coordinate system, the three coordinates are not; but a mental picture&lt;br /&gt;
of an arrow doesn&#039;t have little numbers for three coordinates, so that&lt;br /&gt;
picture works independent of the rotation too.&lt;br /&gt;
&lt;br /&gt;
Since the rotation of the World Coordinate system and the Region Coordinate&lt;br /&gt;
system is the same (X, Y and Z axis are parallel of both), and since&lt;br /&gt;
World Coordinates aren&#039;t used in many LSL functions to begin with, we&lt;br /&gt;
will ignore World Coordinates for now and only refer to Region Coordinates,&lt;br /&gt;
or say &amp;quot;global&amp;quot; when we mean Region Coordinates.&lt;br /&gt;
&lt;br /&gt;
=== Rotations ===&lt;br /&gt;
&lt;br /&gt;
An LSL rotation internally stores a vector that is the axis around which&lt;br /&gt;
to rotate and the angle of the rotation around that axis.&lt;br /&gt;
Let &#039;&#039;&#039;V&#039;&#039;&#039; = &amp;amp;lt;u, v, w&amp;amp;gt; be the normalized vector (that is, with length 1) around&lt;br /&gt;
which we rotate and let &amp;amp;alpha; (alpha) be the angle around which we have to rotate.&lt;br /&gt;
Then the LSL rotation is a quaternion stored as r = &amp;amp;lt;x, y, z, s&amp;amp;gt; = &amp;amp;lt; &#039;&#039;&#039;V&#039;&#039;&#039; * sin(&amp;amp;alpha;/2), cos(&amp;amp;alpha;/2) &amp;amp;gt;.&lt;br /&gt;
Thus, r.x = x * sin(&amp;amp;alpha;/2), and r.s = cos(&amp;amp;alpha;/2) etc. Note that the quaternion&lt;br /&gt;
is also normalized.&lt;br /&gt;
Also note that there is a duality here because inverting &#039;&#039;&#039;V&#039;&#039;&#039; (making it point the&lt;br /&gt;
opposite way) and inverting the angle gives the same rotation; r and -r have&lt;br /&gt;
different values but are the same rotation.&lt;br /&gt;
Also note that if you don&#039;t rotate at all (&amp;amp;alpha; == 0) then it doesn&#039;t matter&lt;br /&gt;
what axis &#039;&#039;&#039;V&#039;&#039;&#039; you pick, which is apparent because &#039;&#039;&#039;V&#039;&#039;&#039; drops out since sin(0) = 0.&lt;br /&gt;
The quaternion &amp;amp;lt;0, 0, 0, 1&amp;amp;gt; is the ZERO_ROTATION quaternion.&lt;br /&gt;
&lt;br /&gt;
The point of this technical story is to show that for an LSL rotation to&lt;br /&gt;
make sense in terms of orientation, you need to be able to express a vector&lt;br /&gt;
in three coordinates (u, v, w above): the axis around which we rotate is&lt;br /&gt;
expressed relative to the X-, Y- and Z-axes of the coordinate system. Hence,&lt;br /&gt;
it is the orientation of the X-, Y- and Z-axes that defines the meaning&lt;br /&gt;
of a rotation in LSL.&lt;br /&gt;
&lt;br /&gt;
In terms of a mental picture the origin with the (orientation of the) three axis,&lt;br /&gt;
the red X-axis, the green Y-axis and the blue Z-axis is all the reference&lt;br /&gt;
we need, combined with a vector for position or a quaternion for rotation.&lt;br /&gt;
&lt;br /&gt;
When you edit an object, the viewer shows either &#039;World&#039; or &#039;Local&#039; axes, but&lt;br /&gt;
really the &#039;World&#039; axes show the wrong origin, shifted to an averaged center&lt;br /&gt;
of the object, because if the origin was drawn at (0, 0, 0) you&#039;d most likely&lt;br /&gt;
not see it. The &#039;Local&#039; ruler shows the correct coordinate system for the&lt;br /&gt;
selected prim as its Prim Coordinate System. Selecting the root prim with&lt;br /&gt;
&#039;Local&#039; ruler on then shows the Object Coordinate System.&lt;br /&gt;
&lt;br /&gt;
=== The dimension of rotations ===&lt;br /&gt;
&lt;br /&gt;
As said before, given some coordinate system, any point in space can&lt;br /&gt;
be represented with a vector. Obviously space is three dimensional,&lt;br /&gt;
and thus vectors exists of three real values:&lt;br /&gt;
one needs three distinct floating point numbers, the x coordinate,&lt;br /&gt;
the y coordinate and the z coordinate to uniquely&lt;br /&gt;
identify a position in a given coordinate system.&lt;br /&gt;
&lt;br /&gt;
However, if one limits oneself to only normalized vectors, vectors&lt;br /&gt;
with a length of one, then those represent all points on the surface&lt;br /&gt;
of a sphere with radius 1.&lt;br /&gt;
A surface is obviously two dimensional, so it should be possible to&lt;br /&gt;
uniquely identify any point on the surface of such a sphere with&lt;br /&gt;
only two floating point numbers.&lt;br /&gt;
&lt;br /&gt;
One might think that selecting just two coordinates of the three of&lt;br /&gt;
the vector will suffice because the third is fixed by the length requirement,&lt;br /&gt;
but that only works for half spheres; for example, if x and y are known&lt;br /&gt;
then z can still be either plus the square root of x squared plus y squared,&lt;br /&gt;
&#039;&#039;or&#039;&#039; minus that value.&lt;br /&gt;
&lt;br /&gt;
Instead, a better choice would be the [http://mathworld.wolfram.com/SphericalCoordinates.html spherical coordinate system]&lt;br /&gt;
and express the unit vectors with the two the angular coordinates &amp;amp;phi; (phi) and &amp;amp;theta; (theta),&lt;br /&gt;
where &amp;amp;phi; is the angle between the vector and the positive Z axis, and&lt;br /&gt;
&amp;amp;theta; the angle that the projection of the vector on to the X,Y plane makes&lt;br /&gt;
with the positive X axis. In other words, starting with a unit vector&lt;br /&gt;
along the positive Z-axis, one can obtain the required point on&lt;br /&gt;
the surface of the sphere by first rotating this vector around the&lt;br /&gt;
Y axis (towards the positive X axis) by an angle of &amp;amp;phi; and then rotating&lt;br /&gt;
the result around the Z-axis by an angle of &amp;amp;theta;. Note that in both cases&lt;br /&gt;
the rotations are counter-clockwise when one looks at it from the positive&lt;br /&gt;
side of the axis that one rotates around (towards the origin).&lt;br /&gt;
&lt;br /&gt;
What we just did was expressing a unit vector in terms of two rotations:&lt;br /&gt;
one around the Z axis and one around the Y axis; and indeed every rotation&lt;br /&gt;
can be expressed as two rotations around those two axis (or really, any&lt;br /&gt;
two arbitrary axes, as long as they are independent (not parallel)).&lt;br /&gt;
&lt;br /&gt;
It is therefore possible to represent unit vectors (aka, a &#039;&#039;direction&#039;&#039;)&lt;br /&gt;
with a rotation, as both are two dimensional. The mental picture here is&lt;br /&gt;
that any unit vector can be expressed as some fixed unit vector (for example&lt;br /&gt;
the one pointing along the positive Z axis, but any other would do as well)&lt;br /&gt;
and the rotation needed to turn that &#039;starting vector&#039; into the unit vector&lt;br /&gt;
that one wants to represent. The other way around almost works as well, with the&lt;br /&gt;
exception of the starting vector itself, as that can be expressed by any arbitrary&lt;br /&gt;
rotation around itself, so that information was lost and it is not possible&lt;br /&gt;
to know which of those rotations was used. In fact, any vector&lt;br /&gt;
close to the starting vector would give inaccurate results in the light&lt;br /&gt;
of floating point round off errors and is not a good way to represent&lt;br /&gt;
a rotation. Of course, the two dimensional vector (&amp;amp;theta;, &amp;amp;phi;) would be excellent&lt;br /&gt;
to represent both: the unit vector, as well as any rotation; but LSL stores&lt;br /&gt;
vectors in x, y, z coordinates, not in spherical coordinates.&lt;br /&gt;
&lt;br /&gt;
=== Converting between coordinate systems ===&lt;br /&gt;
&lt;br /&gt;
Consider a child prim of an object that is not the root prim and express&lt;br /&gt;
its position with the vector pos_oc, and its orientation with the rotation rot_oc,&lt;br /&gt;
both relative to the Object Coordinates System.&lt;br /&gt;
&lt;br /&gt;
A script inside that prim can easily obtain those values:&lt;br /&gt;
&lt;br /&gt;
 vector pos_oc = [[llGetLocalPos]]();&lt;br /&gt;
 rotation rot_oc = [[llGetLocalRot]]();&lt;br /&gt;
&lt;br /&gt;
The postfix &#039;_oc&#039; stands for Object Coordinates and is used to make clear&lt;br /&gt;
relative to which coordinate system the x, y and z values of both&lt;br /&gt;
variables are. Remember that also the rotation contains a vector&lt;br /&gt;
(the axis around which we rotate), so from now on we&#039;ll talk about&lt;br /&gt;
&#039;coordinates&#039; relative to a coordinate system for both, the position&lt;br /&gt;
as well as the rotation, where the coordinates refer to the x, y and z&lt;br /&gt;
components of the position and the rotation. For example, the first&lt;br /&gt;
sentence of this paragraph will read &amp;quot;...express its position with the&lt;br /&gt;
vector pos_oc, and its orientation with the rotation rot_oc, &#039;&#039;both in Object Coordinates&#039;&#039;.&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Note that&#039;&#039;&#039; one has to be careful here, because a script in the&lt;br /&gt;
root prim of the object will &#039;&#039;&#039;&#039;&#039;not&#039;&#039;&#039;&#039;&#039; obtain&lt;br /&gt;
Object Coordinates but instead Region Coordinates!&lt;br /&gt;
The reason is that the &#039;Local&#039; functions return coordinates relative to&lt;br /&gt;
the &#039;parent&#039; coordinate system, where the parent of a non-root prim is the root prim,&lt;br /&gt;
but the parent of the root prim is the region (or avatar in case&lt;br /&gt;
of an attachment). The position and rotation of the root prim in&lt;br /&gt;
Object Coordinates is trivial (ZERO_VECTOR and ZERO_ROTATION respectively).&lt;br /&gt;
&lt;br /&gt;
Back to the script in the child prim. It can also easily obtain its position&lt;br /&gt;
and rotation in Region Coordinates:&lt;br /&gt;
&lt;br /&gt;
 vector pos_rc = [[llGetPos]]();&lt;br /&gt;
 rotation rot_rc = [[llGetRot]]();&lt;br /&gt;
&lt;br /&gt;
Both sets, (pos_oc, rot_oc) and (pos_rc, rot_rc) refer to the same thing,&lt;br /&gt;
so it should be possible to convert them into each other.&lt;br /&gt;
&lt;br /&gt;
One can do this by looking at the orientation (position and rotation) of&lt;br /&gt;
one coordinate system relative to the other and expressed&lt;br /&gt;
in the coordinates of that other. The position and rotation&lt;br /&gt;
of the Object Coordinate System relative to the Region Coordinate&lt;br /&gt;
System, and in Region Coordinates, could be obtained as follows:&lt;br /&gt;
&lt;br /&gt;
 vector oc_pos_rc = [[llGetRootPosition]]();&lt;br /&gt;
 rotation oc_rot_rc = [[llGetRootRotation]]();&lt;br /&gt;
&lt;br /&gt;
As indicated by the &#039;_rc&#039; postfix, these are again in Region Coordinates.&lt;br /&gt;
&lt;br /&gt;
Having the relative orientation of the Object Coordinate System in Region Coordinates, it is&lt;br /&gt;
possible to convert Object Coordinates into Region Coordinates. More&lt;br /&gt;
abstractly put, if you have two coordinate systems A and B, and you have&lt;br /&gt;
their relative orientation expressed in A then you can convert orientations&lt;br /&gt;
expressed in B into A.&lt;br /&gt;
&lt;br /&gt;
The formula is as follows:&lt;br /&gt;
&lt;br /&gt;
 &#039;&#039;&#039;vector   pos_A = pos_B * B_rot_A + B_pos_A;&#039;&#039;&#039;&lt;br /&gt;
 &#039;&#039;&#039;rotation rot_A = rot_B * B_rot_A;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
The order of the multiplications is important; swapping the B_rot_A to the front will not work!&lt;br /&gt;
&lt;br /&gt;
Note that the B_*_A are the position and rotation of the coordinate system B expressed&lt;br /&gt;
in terms of the coordinate system A. The reason that I use the prefix and postfix in&lt;br /&gt;
the order is directly related to the order enforced for rotation multiplications.&lt;br /&gt;
Written this way, the left-hand postfix of a multiplication must match the right-hand prefix&lt;br /&gt;
and conviently short-circuits the notation:&lt;br /&gt;
&lt;br /&gt;
 something_A = something_B * B_rot_A&lt;br /&gt;
&lt;br /&gt;
the two B&#039;s &#039;connect&#039; and drop out (along with the &#039;_rot_&#039;) to give something_ ... A.&lt;br /&gt;
This &#039;&#039;only&#039;&#039; works when the postfix refers to the coordinate system that the variable&lt;br /&gt;
is in, and the prefix is whatever is described by the variable, possibly another&lt;br /&gt;
coordinate system. &lt;br /&gt;
&lt;br /&gt;
A complete example script follows:&lt;br /&gt;
&amp;lt;lsl&amp;gt;&lt;br /&gt;
default&lt;br /&gt;
{&lt;br /&gt;
    touch(integer num_detected)&lt;br /&gt;
    {&lt;br /&gt;
        llSay(0, &amp;quot;---------&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
        // Get the pos and rot in Object Coordinates.&lt;br /&gt;
        vector pos_oc = llGetLocalPos();&lt;br /&gt;
        rotation rot_oc = llGetLocalRot();&lt;br /&gt;
        &lt;br /&gt;
        // Fix these values when this script is in the root prim!&lt;br /&gt;
        if (llGetLinkNumber() == 0)&lt;br /&gt;
        {&lt;br /&gt;
            pos_oc = ZERO_VECTOR;&lt;br /&gt;
            rot_oc = ZERO_ROTATION;&lt;br /&gt;
        }&lt;br /&gt;
        &lt;br /&gt;
        // Get the pos and rot in Region Coordinates.&lt;br /&gt;
        vector pos_rc = llGetPos();&lt;br /&gt;
        rotation rot_rc = llGetRot();&lt;br /&gt;
        &lt;br /&gt;
        // Get the pos and rot of the Object Coordinate System in Region Coordinates.&lt;br /&gt;
        vector oc_pos_rc = llGetRootPosition();&lt;br /&gt;
        rotation oc_rot_rc = llGetRootRotation();&lt;br /&gt;
        &lt;br /&gt;
        // Print the values of the positions (the rotations are too hard to understand).&lt;br /&gt;
        llSay(0, &amp;quot;oc_pos_rc = &amp;quot; + (string)oc_pos_rc);&lt;br /&gt;
        llSay(0, &amp;quot;pos_os = &amp;quot; + (string)pos_os);&lt;br /&gt;
        llSay(0, &amp;quot;pos_rc = &amp;quot; + (string)pos_rc);&lt;br /&gt;
        &lt;br /&gt;
        // Calculate pos_rc and rot_rc from pos_oc and rot_oc : converting between _oc and _rc.&lt;br /&gt;
        vector   pos2_rc = pos_oc * oc_rot_rc + oc_pos_rc;&lt;br /&gt;
        rotation rot2_rc = rot_oc * oc_rot_rc;&lt;br /&gt;
        &lt;br /&gt;
        // Print the result for the position, and show the difference with what llGetPos() and llGetRot() returned.&lt;br /&gt;
        llSay(0, &amp;quot;pos2_rc = &amp;quot; + (string)pos2_rc);&lt;br /&gt;
        // These values should be ZERO_VECTOR and ZERO_ROTATION (or -ZERO_ROTATION).&lt;br /&gt;
        llSay(0, &amp;quot;pos_rc - pos2_rc = &amp;quot; + (string)(pos_rc - pos2_rc));&lt;br /&gt;
        llSay(0, &amp;quot;rot_rc / rot2_rc = &amp;quot; + (string)(rot_rc / rot2_rc));&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/lsl&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Obviously there is no preference for one coordinate system over the other for this conversion;&lt;br /&gt;
one can equally as well convert orientations in A into B:&lt;br /&gt;
&lt;br /&gt;
 vector   pos_B = pos_A * A_rot_B + A_pos_B;&lt;br /&gt;
 rotation rot_B = rot_A * A_rot_B;&lt;br /&gt;
&lt;br /&gt;
The question arises then how to obtain the A_*_B values. For example, there is no LSL function that returns directly&lt;br /&gt;
the position or rotation of the region relative to a prim (aka, rc_*_oc).&lt;br /&gt;
&lt;br /&gt;
Intuitively one would say that it has to be possible to express A_*_B in B_*_A on grounds of symmetry, and that&lt;br /&gt;
is indeed the case.&lt;br /&gt;
&lt;br /&gt;
To show how this works, lets just take the formula for pos_A and rot_A (see above) and rework&lt;br /&gt;
them to get pos_B and rot_B on the left-hand side. This results first in&lt;br /&gt;
&lt;br /&gt;
 pos_B * B_rot_A = pos_A - B_pos_A&lt;br /&gt;
 rot_B * B_rot_A = rot_A&lt;br /&gt;
&lt;br /&gt;
Then divide both sides by B_rot_A to get:&lt;br /&gt;
&lt;br /&gt;
 pos_B = pos_A / B_rot_A - B_pos_A / B_rot_A&lt;br /&gt;
 rot_B = rot_A / B_rot_A&lt;br /&gt;
&lt;br /&gt;
from which we can conclude that&lt;br /&gt;
&lt;br /&gt;
 &#039;&#039;&#039;A_pos_B = - B_pos_A / B_rot_A&#039;&#039;&#039;&lt;br /&gt;
 &#039;&#039;&#039;A_rot_B = ZERO_ROTATION / B_rot_A&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Note how A_rot_B is the inverse of B_rot_A: A_rot_B * B_rot_A = ZERO_ROTATION.&lt;br /&gt;
As per our notation convention you&#039;d expect A_rot_B * B_rot_A to be A_rot_A, and that is&lt;br /&gt;
actually the case as A_rot_A means the relative orientation of coordinate system A&lt;br /&gt;
expressed in A&#039;s coordinates, which is the trivial ZERO_VECTOR and ZERO_ROTATION as&lt;br /&gt;
we saw before for the root prim orientation expressed in Object Coordinates.&lt;br /&gt;
&lt;br /&gt;
And for fun, note that if we do this inversion again we get:&lt;br /&gt;
&lt;br /&gt;
 B_pos_A = - A_pos_B / A_rot_B = - (- B_pos_A / B_rot_A) / (ZERO_ROTATION / B_rot_A) = B_pos_A / B_rot_A * B_rot_A = B_pos_A&lt;br /&gt;
 B_rot_A = ZERO_ROTATION / A_rot_B = ZERO_ROTATION / (ZERO_ROTATION / B_rot_A) = B_rot_A&lt;br /&gt;
&lt;br /&gt;
as expected.&lt;br /&gt;
&lt;br /&gt;
We can now also convert Region Coordinates to Object Coordinates.&lt;br /&gt;
&lt;br /&gt;
One could first calculate,&lt;br /&gt;
&lt;br /&gt;
 vector rc_pos_oc = - llGetRootPosition() / llGetRootRotation();&lt;br /&gt;
 rotation rc_rot_oc = ZERO_ROTATION / llGetRootRotation();&lt;br /&gt;
&lt;br /&gt;
and then convert as usual:&lt;br /&gt;
&lt;br /&gt;
 vector   pos_oc = pos_rc * rc_rot_oc + rc_pos_oc;&lt;br /&gt;
 rotation rot_oc = rot_rc * rc_rot_oc;&lt;br /&gt;
&lt;br /&gt;
or if you don&#039;t want to calculate the intermediate rc_*_oc values, you could do immediately:&lt;br /&gt;
&lt;br /&gt;
 vector   pos_oc = (pos_rc - llGetRootPosition()) / llGetRootRotation();&lt;br /&gt;
 rotation rot_oc = rot_rc / llGetRootRotation();&lt;br /&gt;
&lt;br /&gt;
To verify this, you could extend the above script with&lt;br /&gt;
&amp;lt;lsl&amp;gt;&lt;br /&gt;
        // Calculate pos_oc and rot_oc from pos_rc and rot_rc.&lt;br /&gt;
        vector   pos2_oc = (pos_rc - llGetRootPosition()) / llGetRootRotation();&lt;br /&gt;
        rotation rot2_oc = rot_rc / llGetRootRotation();&lt;br /&gt;
        &lt;br /&gt;
        llSay(0, &amp;quot;pos2_oc = &amp;quot; + (string)pos2_oc);&lt;br /&gt;
        // These values should again be ZERO_VECTOR and +/- ZERO_ROTATION.&lt;br /&gt;
        llSay(0, &amp;quot;pos_oc - pos2_oc = &amp;quot; + (string)(pos_oc - pos2_oc));&lt;br /&gt;
        llSay(0, &amp;quot;rot_oc / rot2_oc = &amp;quot; + (string)(rot_oc / rot2_oc));&lt;br /&gt;
&amp;lt;/lsl&amp;gt;&lt;br /&gt;
&lt;br /&gt;
More in general, if you want to convert from B to A, but you only have A_*_B instead of B_*_A, then (combining the above)&lt;br /&gt;
you can do:&lt;br /&gt;
&lt;br /&gt;
 &#039;&#039;&#039;vector   pos_A = (pos_B - A_pos_B) / A_rot_B;&#039;&#039;&#039;&lt;br /&gt;
 &#039;&#039;&#039;rotation rot_A = rot_B / A_rot_B;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
=== Cascading coordinate systems ===&lt;br /&gt;
&lt;br /&gt;
Imagine you have a castle object where the floor is the root prim. Everything is linked because you&lt;br /&gt;
want it to be easy to move the castle around. One of the child prims is a sculpty representing the hinges&lt;br /&gt;
around which you want to rotate a large gate. The gate has a rotating wheel on it.&lt;br /&gt;
&lt;br /&gt;
You want that the object (castle) to keep working when it is moved and/or rotated, but also when it is edited&lt;br /&gt;
and the hinges are moved and/or rotated. This means that the state of the gate prims&lt;br /&gt;
must be &#039;&#039;stored&#039;&#039; relative to the hinges, which is by far the easiest thing to do to begin with,&lt;br /&gt;
after all, the gate rotates around the hinges and has no relation with the rest of the castle.&lt;br /&gt;
&lt;br /&gt;
Hence, we have the Region Coordinate System, the Object Coordinate System (the castle) and the Hinges Coordinate System.&lt;br /&gt;
The latter is our first example of a Prim Coordinates System, but I&#039;ll use the postfix &#039;_hc&#039; for &amp;quot;Hinges Coordinates&amp;quot;&lt;br /&gt;
instead of &#039;_pc&#039;. Finally we have the Spill Coordinate System (or Gate Coordinates) where the spill is a prim&lt;br /&gt;
around which we want to rotate the wheel, and I&#039;ll used &#039;_sc&#039; as postfix for that.&lt;br /&gt;
&lt;br /&gt;
The variables used then would be an orientation for the wheel in *_sc coordinates, the orientation of the spill,&lt;br /&gt;
and other gate prims, in *_hc coordinates and the orientation of the hinges in *_oc coordinates. Finally we could&lt;br /&gt;
have variables for the orientation of the castle (root prim) in *_rc coordinates of course.&lt;br /&gt;
&lt;br /&gt;
 vector   castle_pos_rc; // The position of the castle in Region Coordinates.&lt;br /&gt;
 rotation castle_rot_rc; // The rotation of the castle in Region Coordinates.&lt;br /&gt;
 &lt;br /&gt;
 vector   hinges_pos_oc; // The position of the hinges in Object Coordinates.&lt;br /&gt;
 rotation hinges_rot_oc; // The rotation of the hinges in Object Coordinates.&lt;br /&gt;
 &lt;br /&gt;
 vector   spill_pos_hc;  // The position of the spill in Hinges Coordinates.&lt;br /&gt;
 rotation spill_rot_hc;  // The rotation of the spill in Hinges Coordinates.&lt;br /&gt;
 &lt;br /&gt;
 vector   wheel_pos_sc;  // The position of the wheel in Spill Coordinates.&lt;br /&gt;
 rotation wheel_rot_sc;  // The rotation of the wheel in Spill Coordinates.&lt;br /&gt;
&lt;br /&gt;
Now because we used existing prims orientations as coordinate system for the next prim, the position&lt;br /&gt;
and rotation of those prims &#039;&#039;are&#039;&#039; the position and rotation of that coordinate system.&lt;br /&gt;
Just like before we saw that llGetPos/llGetRot returns the global orientation of the root prim&lt;br /&gt;
when used in a script in the root prim, while llGetRootPos/llGetRootRot gave us the relative&lt;br /&gt;
orientation of the Object Coordinate System in Region Coordinates, but is in fact the same as&lt;br /&gt;
what llGetPos/llGetRot in the root prim returns: the position/rotation of the root prim &#039;&#039;&#039;is&#039;&#039;&#039;&lt;br /&gt;
the orientation of the Object Coordinate System relative to the Region.&lt;br /&gt;
&lt;br /&gt;
Likewise, in this case, castle_*_rc is the relative orientation of the Object Coordinate System&lt;br /&gt;
in Region Coordinates as well as the orientation of the root prim in Region Coordinates; they&lt;br /&gt;
are the same thing.&lt;br /&gt;
&lt;br /&gt;
The same then applies to the *_oc variables, which we defined as the orientation of&lt;br /&gt;
the hinges in Object Coordinates, but at the same time are the relative orientation&lt;br /&gt;
of the Hinges Coordinate System in Object Coordinates. The *_hc variables are the&lt;br /&gt;
orientation of spill in Hinges Coordinates, but also the relative orientation of&lt;br /&gt;
the Spill Coordinates in Hinges Coordinates.&lt;br /&gt;
&lt;br /&gt;
Lets write it out using the same notation convention as used above, then&lt;br /&gt;
we have:&lt;br /&gt;
&lt;br /&gt;
 vector   oc_pos_rc = castle_pos_rc; // The Object Coordinate System orientation in Region Coordinates.&lt;br /&gt;
 rotation oc_rot_rc = castle_rot_rc;&lt;br /&gt;
 &lt;br /&gt;
 vector   hc_pos_oc = hinges_pos_oc; // The Hinges Coordinate System orientation in Object Coordinates.&lt;br /&gt;
 rotation hc_rot_oc = hinges_rot_oc;&lt;br /&gt;
&lt;br /&gt;
 vector   sc_pos_hc = spill_pos_hc;  // The Spill Coordinate System orientation in Hinges Coordinates.&lt;br /&gt;
 rotation sc_rot_hc = spill_rot_hc;&lt;br /&gt;
&lt;br /&gt;
It will therefore probably not surprise you that&lt;br /&gt;
&lt;br /&gt;
 vector   hc_pos_rc = hc_pos_oc * oc_rot_rc + oc_pos_rc; // The Hinges Coordinate System orientation in Region Coordinates.&lt;br /&gt;
 rotation hc_rot_rc = hc_rot_oc * oc_rot_rc;&lt;br /&gt;
 &lt;br /&gt;
 vector   sc_pos_rc = sc_pos_hc * hc_rot_rc + hc_pos_rc; // The Spill Coordinate System orientation in Region Coordinates.&lt;br /&gt;
 rotation sc_rot_rc = sc_rot_hc * hc_rot_rc;&lt;br /&gt;
&lt;br /&gt;
And finally, using the latter, we can express the wheel orientation in region coordinates:&lt;br /&gt;
&lt;br /&gt;
 vector   wheel_pos_rc = wheel_pos_sc * sc_rot_rc + sc_pos_rc;&lt;br /&gt;
 rotation wheel_rot_rc = wheel_rot_sc * sc_rot_rc;&lt;br /&gt;
&lt;br /&gt;
Although this was nothing else but applying the coordinate system conversion formula three times,&lt;br /&gt;
it might give some insight to get rid of the intermediate variables and express the wheel&lt;br /&gt;
orientation in region coordinates without them, giving:&lt;br /&gt;
&lt;br /&gt;
 wheel_pos_rc = ((wheel_pos_sc * sc_rot_hc + sc_pos_hc) * hc_rot_oc + hc_pos_oc) * oc_rot_rc + oc_pos_rc&lt;br /&gt;
 wheel_rot_rc = wheel_rot_sc * sc_rot_hc * hc_rot_oc * oc_rot_rc&lt;br /&gt;
&lt;br /&gt;
=== Applying rotations and translations ===&lt;br /&gt;
&lt;br /&gt;
Applying rotations and translations (moving) is very much the same as coordinate system transformations described above.&lt;br /&gt;
To show this consider the following: imagine you have a prim &#039;pa&#039; with its own coordinate system A.&lt;br /&gt;
Then it trivially has position ZERO_VECTOR and rotation ZERO_ROTATION relative to A, per definition.&lt;br /&gt;
&lt;br /&gt;
 vector   pa_pos_A = ZERO_VECTOR;&lt;br /&gt;
 rotation pa_rot_A = ZERO_ROTATION;&lt;br /&gt;
&lt;br /&gt;
Now consider a prim &#039;pb&#039; that has some relative position pb_pos_A and rotation pb_rot_A given in A coordinates.&lt;br /&gt;
For example,&lt;br /&gt;
&lt;br /&gt;
 vector   pb_pos_A = &amp;lt;0.5, 0.6, 0.7&amp;gt;;&lt;br /&gt;
 rotation pb_rot_A = &amp;lt;0.38, 0.26, 0.34, 0.82&amp;gt;;&lt;br /&gt;
&lt;br /&gt;
Note that 0.38&amp;amp;sup2; + 0.26&amp;amp;sup2; + 0.34&amp;amp;sup2; + 0.82&amp;amp;sup2; = 1, as it must be since rotations are normalized.&lt;br /&gt;
&lt;br /&gt;
As seen before, the orientation of pb relative to pa is the same as the orientation of pb relative to A,&lt;br /&gt;
and the same as the orientation of B relative to A. pa and A are interchangeable as long as pa has&lt;br /&gt;
ZERO_VECTOR and ZERO_ROTATION relative to A. Thus, with B being the coordinate system where pb currently&lt;br /&gt;
is, we also have:&lt;br /&gt;
&lt;br /&gt;
 vector   B_pos_A = pb_pos_A; // The orientation of coordinate system B, in coordinates of A.&lt;br /&gt;
 rotation B_rot_A = pb_rot_A;&lt;br /&gt;
&lt;br /&gt;
Now suppose we want move the prim pa (without moving the coordinate system A),&lt;br /&gt;
by applying the translation &#039;B_pos_A&#039;, after all a translation is stored in a vector&lt;br /&gt;
and B_pos_A is a vector. Likewise, we want to rotate pa (again without influencing A)&lt;br /&gt;
by applying the rotation B_rot_A. Then the most logical order to this in is by&lt;br /&gt;
&#039;&#039;first&#039;&#039; applying the rotation and &#039;&#039;then&#039;&#039; applying the translation, because then&lt;br /&gt;
the meaning of the translation is preserved and will match the meaning of B_pos_A&lt;br /&gt;
in that pa will end up where pb is now. If you&#039;d first apply the translation so that&lt;br /&gt;
pa ends up where pb is, and then apply the rotation (around A!) then pa would swoop&lt;br /&gt;
around the origin of A and move away from its desired position.&lt;br /&gt;
&lt;br /&gt;
Doing this correctly should leave us with pa_pos_A == pb_pos_A and pa_rot_A == pb_rot_A,&lt;br /&gt;
so that pa ended up precisely where pb is now. We can&#039;t just assign those values&lt;br /&gt;
however, because we&#039;re looking for a formula that works in general; a way to apply&lt;br /&gt;
B_rot_A and then B_pos_A to any prim with -say- orientation pc_pos_A, pc_rot_A.&lt;br /&gt;
&lt;br /&gt;
Thus, first we apply the rotation:&lt;br /&gt;
&lt;br /&gt;
 pc_rot_A *= B_rot_A;&lt;br /&gt;
 pc_pos_A *= B_rot_A;&lt;br /&gt;
&lt;br /&gt;
And then apply the translation:&lt;br /&gt;
&lt;br /&gt;
 pc_pos_A += B_pos_A;&lt;br /&gt;
&lt;br /&gt;
Now lets check if indeed this would cause pa to end up where pb is.&lt;br /&gt;
The effect on pa_*_A would be:&lt;br /&gt;
&lt;br /&gt;
 pa_rot_A = pa_rot_A * B_rot_A = ZERO_ROTATION * B_rot_A = B_rot_A = pb_rot_A;&lt;br /&gt;
 pa_pos_A = pa_pos_A * B_rot_A = ZERO_VECTOR * B_rot_A = ZERO_VECTOR;&lt;br /&gt;
 &lt;br /&gt;
 and then the translation&lt;br /&gt;
 &lt;br /&gt;
 pa_pos_A = pa_pos_A + B_pos_A = ZERO_VECTOR + B_pos_A = B_pos_A = pb_pos_A;&lt;br /&gt;
&lt;br /&gt;
So yes, pa_*_A ends up as pb_*_A!&lt;br /&gt;
&lt;br /&gt;
The real test however would be if we first applied some transformation to pa&lt;br /&gt;
to bring it to some arbitrary orientation (aka, pc), then apply the transformation&lt;br /&gt;
B_rot_A,B_pos_A and then reverse the first transformation but now relative to B,&lt;br /&gt;
and then find that we indeed end up at pb.&lt;br /&gt;
&lt;br /&gt;
Let us first define a &#039;transformation&#039;, which exists of a vector for the&lt;br /&gt;
translation and a rotation for the rotation. We will have two transformation&lt;br /&gt;
during this test: t1: pa -&amp;gt; pc, and t2: pa -&amp;gt; pb.&lt;br /&gt;
&lt;br /&gt;
As we just saw (or we hope this is going to be the case), t2 can be defined as:&lt;br /&gt;
&lt;br /&gt;
 vector   t2_translation = B_pos_A;&lt;br /&gt;
 rotation t2_rotation = B_rot_A;&lt;br /&gt;
&lt;br /&gt;
where as t1 is arbitrary, just some values t1_translation and t1_rotation.&lt;br /&gt;
&lt;br /&gt;
Applying t1 to pa, we get (this is thus the same as above, but now with the &#039;t1&#039; notation):&lt;br /&gt;
&lt;br /&gt;
 pa_rot_A *= t1_rotation;&lt;br /&gt;
 pa_pos_A *= t1_rotation;&lt;br /&gt;
 pa_pos_A += t1_translation;&lt;br /&gt;
&lt;br /&gt;
Next we apply translation t2 to that:&lt;br /&gt;
&lt;br /&gt;
 pa_rot_A *= t2_rotation;&lt;br /&gt;
 pa_pos_A *= t2_rotation;&lt;br /&gt;
 pa_pos_A += t2_translation;&lt;br /&gt;
&lt;br /&gt;
Finally we want to reverse t1, but in the coordinate system of B.&lt;br /&gt;
Therefore, we first convert our coordinates to that of B:&lt;br /&gt;
&lt;br /&gt;
 pa_pos_B = pa_pos_A * A_rot_B + A_pos_B;&lt;br /&gt;
 pa_rot_B = pa_rot_A * A_rot_B;&lt;br /&gt;
&lt;br /&gt;
where&lt;br /&gt;
&lt;br /&gt;
 A_pos_B = - B_pos_A / B_rot_A;&lt;br /&gt;
 A_rot_B = ZERO_ROTATION / B_rot_A;&lt;br /&gt;
&lt;br /&gt;
and then reverse t1. Note now we have to do the translation first!&lt;br /&gt;
&lt;br /&gt;
 pa_pos_B -= t1_translation;&lt;br /&gt;
 pa_pos_B /= t1_rotation;&lt;br /&gt;
 pa_rot_B /= t1_rotation;&lt;br /&gt;
&lt;br /&gt;
And if everything worked out then pa now should be at ZERO_VECTOR, ZERO_ROTATION relative to B!&lt;br /&gt;
&lt;br /&gt;
As pa_pos_A,pa_rot_A started as ZERO_VECTOR,ZERO_ROTATION, the first step&lt;br /&gt;
of applying t1 resulted in pa_rot_A = t1_rotation and pa_pos_A = t1_translation.&lt;br /&gt;
&lt;br /&gt;
After applying t2 we get pa_rot_A = t1_rotation * t2_rotation, and pa_pos_A = t1_translation * t2_rotation + t2_translation.&lt;br /&gt;
&lt;br /&gt;
Converting that to B gives&lt;br /&gt;
&lt;br /&gt;
 pa_pos_B = (t1_translation * t2_rotation + t2_translation) * A_rot_B + A_pos_B&lt;br /&gt;
 pa_rot_B = (t1_rotation * t2_rotation) * A_rot_B&lt;br /&gt;
&lt;br /&gt;
where, remembering that t2_translation = B_pos_A and t2_rotation = B_rot_A,&lt;br /&gt;
&lt;br /&gt;
 A_pos_B = - B_pos_A / B_rot_A = - t2_translation / t2_rotation&lt;br /&gt;
 A_rot_B = ZERO_ROTATION / B_rot_A = ZERO_ROTATION / t2_rotation&lt;br /&gt;
&lt;br /&gt;
so that we get&lt;br /&gt;
&lt;br /&gt;
 pa_pos_B = (t1_translation * t2_rotation + t2_translation) / t2_rotation - t2_translation / t2_rotation = t1_translation&lt;br /&gt;
 pa_rot_B = (t1_rotation * t2_rotation) / t2_rotation = t1_rotation&lt;br /&gt;
&lt;br /&gt;
and finally reversing t1 gives:&lt;br /&gt;
&lt;br /&gt;
 pa_pos_B = (t1_translation - t1_translation) / t1_rotation = ZERO_VECTOR&lt;br /&gt;
 pa_rot_B = t1_rotation / t1_rotation = ZERO_ROTATION&lt;br /&gt;
&lt;br /&gt;
So that we can conclude that if you have two prims pa and pb, each representing their own coordinate system A and B respectively,&lt;br /&gt;
and you express the orientation of B relative to A as the pair (B_pos_A, B_rot_A) &amp;amp;mdash; then the following holds.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;The transformation pair (t_translation, t_rotation) equals (B_pos_A, B_rot_A) as long as you first apply the rotation and then the translation while working in the coordinate system of A&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
The latter is also very practical, because you normally won&#039;t know&lt;br /&gt;
anything about the target coordinate system B until you actually did the transformation.&lt;br /&gt;
&lt;br /&gt;
Now remember that we found that in order to convert variables from being relative to a coordinate system B to a coordinate system A,&lt;br /&gt;
we did:&lt;br /&gt;
&lt;br /&gt;
 pos_A = pos_B * B_rot_A + B_pos_A&lt;br /&gt;
 rot_A = rot_B * B_rot_A&lt;br /&gt;
&lt;br /&gt;
which is thus exactly the same as first applying the rotation t1_rotation and then the translation t1_translation&lt;br /&gt;
on the pair (pos_B, rot_B) where that pair is relative to A! That isn&#039;t too weird because if you consider a prim&lt;br /&gt;
in the origin of A with no rotation, aka (ZERO_VECTOR, ZERO_ROTATION) relative to A and then apply the transformation&lt;br /&gt;
then you expect to end up in the origin of B with no rotation relative to B. Aka pos_B = ZERO_VECTOR and rot_B = ZERO_ROTATION.&lt;br /&gt;
So now work backwards: assume you already have the prim in B like that, then what are its coordinates in A?&lt;br /&gt;
That would be the above conversion thus, with pos_B = ZERO_VECTOR and rot_B = ZERO_ROTATION.&lt;br /&gt;
&lt;br /&gt;
Hence, doing the conversion with ZERO as input gives the same results as doing the t transformation with ZERO as input!&lt;br /&gt;
And the final formula for a transformation just looks exactly the same:&lt;br /&gt;
&lt;br /&gt;
 &#039;&#039;&#039;target_pos_A = source_pos_A * t_rotation + t_translation&#039;&#039;&#039;&lt;br /&gt;
 &#039;&#039;&#039;target_rot_A = source_rot_A * t_rotation&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
=== Scaling coordinate systems ===&lt;br /&gt;
&lt;br /&gt;
Apart from rotation and translation, there is one more linear operator that can be used to convert&lt;br /&gt;
between coordinate systems: scaling.&lt;br /&gt;
&lt;br /&gt;
Let A_pos_B be the position of the origin of A in the coordinates of B. Let A_rot_B be the orientation of A within B,&lt;br /&gt;
and let the vector A_B_scale be the scaling factors for each axes. Scaling has no influence on the origin of&lt;br /&gt;
a coordinate system, but it matters for the rotation when the scaling factors per axis are different.&lt;br /&gt;
&lt;br /&gt;
I think that a good choice is scale first and rotate afterwards. Because that leaves the values&lt;br /&gt;
of the coordinates of A_rot_B alone: it remains the rotation as defined in B, which makes sense&lt;br /&gt;
since it is written in the coordinates of B. However, it&#039;s just a matter of choice really, which&lt;br /&gt;
in this case will deform B_rot_A instead of A_rot_B. I can imagine that the choice might depend&lt;br /&gt;
on the application.&lt;br /&gt;
&lt;br /&gt;
Chosing that we first scale, a point at pos_A is mapped onto the point pos_B as follows:&lt;br /&gt;
&lt;br /&gt;
 pos_B = (S * pos_A) * A_rot_B + A_pos_B&lt;br /&gt;
&lt;br /&gt;
where S is a 3x3 matrix with as diagonal the vector A_B_scale (and the rest zeroes).&lt;br /&gt;
Note that when each element of A_B_scale is the same then you can just use a scalar for S, equal to the scale of each axis.&lt;br /&gt;
&lt;br /&gt;
Whether or not S is a matrix or a scalar, lets just replace it with &#039;A_B_scale&#039; here. Just keep in&lt;br /&gt;
mind that if it isn&#039;t a scalar then this won&#039;t work in LSL directly: then you&#039;ll have to split&lt;br /&gt;
it up in three different code lines because LSL doesn&#039;t support scaling or matrices.&lt;br /&gt;
&lt;br /&gt;
  pos_B = pos_A;&lt;br /&gt;
  pos_B.x *= A_B_scale.x;  // Scale&lt;br /&gt;
  pos_B.y *= A_B_scale.y;&lt;br /&gt;
  pos_B.z *= A_B_scale.z;&lt;br /&gt;
  pos_B *= A_rot_B;        // Rotate&lt;br /&gt;
  pos_B += A_pos_B;        // Translate&lt;br /&gt;
&lt;br /&gt;
Note that the inverse of S, 1/S, is a 3x3 matrix with as diagonal the inverse of each element of A_B_scale.&lt;br /&gt;
We will either write &#039;B_A_scale&#039;, or divide by &#039;A_B_scale&#039; in our notation.&lt;br /&gt;
&lt;br /&gt;
Therefore our notation becomes:&lt;br /&gt;
&lt;br /&gt;
 pos_B = (&#039;A_B_scale&#039; * pos_A) * A_rot_B + A_pos_B&lt;br /&gt;
&lt;br /&gt;
Since A and B are arbitrary, we would expect the same formula to hold when swapping A and B:&lt;br /&gt;
&lt;br /&gt;
 pos_A = (&#039;B_A_scale&#039; * pos_B) * B_rot_A + B_pos_A&lt;br /&gt;
&lt;br /&gt;
Solving pos_B from that by subtracting B_pos_A from both sides, then dividing both sides by B_rot_A&lt;br /&gt;
and finally left multiplying both sides with the inverse of B_A_scale, gives:&lt;br /&gt;
&lt;br /&gt;
 pos_B = &#039;A_B_scale&#039; * ((pos_A - B_pos_A) / B_rot_A) = &#039;A_B_scale&#039; * (pos_A / B_rot_A) - &#039;A_B_scale&#039; * (B_pos_A / B_rot_A)&lt;br /&gt;
&lt;br /&gt;
from which we can conclude (by setting pos_A to ZERO_VECTOR) that&lt;br /&gt;
&lt;br /&gt;
 A_pos_B = -&#039;A_B_scale&#039; * (B_pos_A / B_rot_A)&lt;br /&gt;
&lt;br /&gt;
Solving B_pos_A from that by left multiplying both sides with -B_A_scale and then right multiplying both sides with B_rot_A, gives:&lt;br /&gt;
&lt;br /&gt;
 B_pos_A = - (&#039;B_A_scale&#039; * A_pos_B) * B_rot_A&lt;br /&gt;
&lt;br /&gt;
By setting A_pos_B to ZERO_VECTOR, and this B_pos_A too, we can also conclude that&lt;br /&gt;
&lt;br /&gt;
 (&#039;A_B_scale&#039; * pos_A) * A_rot_B = &#039;A_B_scale&#039; * (pos_A / B_rot_A)&lt;br /&gt;
&lt;br /&gt;
If &#039;A_B_scale&#039; is a scalar, so that the order of multiplication doesn&#039;t matter,&lt;br /&gt;
then the scale just cancels on both sides and we find the conversion that we&lt;br /&gt;
found before, that B_rot_A is the inverse of A_rot_B. However, if A_B_scale&lt;br /&gt;
is a diagonal matrix then the order matters and the brackets are significant.&lt;br /&gt;
&lt;br /&gt;
There is no way to let pos_A drop out: we cannot write B_rot_A as function&lt;br /&gt;
of A_B_scale and A_rot_B.&lt;br /&gt;
&lt;br /&gt;
The conclusion is that a scale is asymmetrical: if you choose that a scale A_B_scale&lt;br /&gt;
means that you first apply the scale on a vector in A and then rotate, then&lt;br /&gt;
that automatically implies that when going from B to A you first have to rotate&lt;br /&gt;
and &#039;&#039;then&#039;&#039; apply the scale.&lt;br /&gt;
&lt;br /&gt;
To make the choice clear in the name, I suggest to put an &#039;r&#039; in front of the&lt;br /&gt;
coordinate system that need rotation to be applied first. &lt;br /&gt;
&lt;br /&gt;
In summary, if A_rB_scale is defined as&lt;br /&gt;
&lt;br /&gt;
 &#039;&#039;&#039;pos_B = (&#039;A_rB_scale&#039; * pos_A) * A_rot_B + A_pos_B&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
then that implies that rB_A_scale has to be applied after rotation.&lt;br /&gt;
Note this means braces, NOT changing the left- or right- side of&lt;br /&gt;
multiplications! Matrices (scales) are always on the left side&lt;br /&gt;
of a vector, while rotations are always on the right side. Thus we get: &lt;br /&gt;
&lt;br /&gt;
 &#039;&#039;&#039;pos_A = &#039;rB_A_scale&#039; * (pos_B * B_rot_A) + B_pos_A&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
If now we solve pos_B from the latter, we get:&lt;br /&gt;
&lt;br /&gt;
 pos_B = (&#039;A_rB_scale&#039; * (pos_A - B_pos_A)) / B_rot_A = (&#039;A_rB_scale&#039; * pos_A) / B_rot_A - (&#039;A_rB_scale&#039; * B_pos_A) / B_rot_A&lt;br /&gt;
&lt;br /&gt;
Hence&lt;br /&gt;
&lt;br /&gt;
 &#039;&#039;&#039;B_pos_A = - &#039;rB_A_scale&#039; * (A_pos_B / A_rot_B)&#039;&#039;&#039;&lt;br /&gt;
 &#039;&#039;&#039;B_rot_A = ZERO_ROTATION / A_rot_B&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
and&lt;br /&gt;
&lt;br /&gt;
 &#039;&#039;&#039;A_pos_B = - (&#039;A_rB_scale&#039; * B_posA) / B_rot_A&#039;&#039;&#039;&lt;br /&gt;
 &#039;&#039;&#039;A_rot_B = ZERO_ROTATION / B_rot_A&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Note how these two sets condense into the same thing when the scale is a scalar,&lt;br /&gt;
but also when A_rot_B and B_rot_A are ZERO_ROTATION. In fact, when the rotation&lt;br /&gt;
involved is of the special case of one or more rotations of 90 degrees around&lt;br /&gt;
any of the axes, so that the rotation merely swaps axes, one could define&lt;br /&gt;
the inverse of A_B_scale by applying that rotation to that vector (swapping&lt;br /&gt;
the scaling factors), next to inverting each factor individually.&lt;br /&gt;
That is a different way of how we defined B_A_scale, but it would collapse&lt;br /&gt;
the two sets into one for that special set of rotations. I&#039;m using that trick&lt;br /&gt;
in the example script below.&lt;br /&gt;
&lt;br /&gt;
=== Direction vectors ===&lt;br /&gt;
&lt;br /&gt;
A &#039;direction&#039; is a normalized vector (its length is 1), or unit vector, where only the direction&lt;br /&gt;
is points to is important.&lt;br /&gt;
&lt;br /&gt;
Of course, in the light of rotations between coordinate systems, also the directions&lt;br /&gt;
are relative to some coordinate system.&lt;br /&gt;
&lt;br /&gt;
As stated before, using some &#039;starting&#039; unit vector a rotation can be expressed&lt;br /&gt;
as a direction by applying the rotation on the starting vector. Reversing this&lt;br /&gt;
process runs into floating point round off errors however, or might even have lost&lt;br /&gt;
all information of the rotation when we rotate around the starting vector itself.&lt;br /&gt;
&lt;br /&gt;
There is a better way to convert directions (back) to a rotation however: by using &#039;&#039;two&#039;&#039;&lt;br /&gt;
directions that are perpendicular, each having a unit vector along one of the axes&lt;br /&gt;
as starting vector. That way there is always at least one vector enough rotated away&lt;br /&gt;
from the actual rotation in order not to suffer from (too much) information loss.&lt;br /&gt;
&lt;br /&gt;
For example, let us use the unit vector along the positive X axis and the unit vector&lt;br /&gt;
along the positive Z axis. In LSL those are often called fwd and up respectively.&lt;br /&gt;
Furthermore, lets work in a coordinate system A. Then we have the &#039;starting&#039; vectors:&lt;br /&gt;
&lt;br /&gt;
 &#039;&#039;&#039;vector A_fwd_A  = &amp;lt;1, 0, 0&amp;gt;;&#039;&#039;&#039;&lt;br /&gt;
 &#039;&#039;&#039;vector A_left_A = &amp;lt;0, 1, 0&amp;gt;;&#039;&#039;&#039;&lt;br /&gt;
 &#039;&#039;&#039;vector A_up_A   = &amp;lt;0, 0, 1&amp;gt;;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
We said we only knew the fwd and up directions, but the third can always be&lt;br /&gt;
calculated from the other two with a cross product:&lt;br /&gt;
&lt;br /&gt;
 &#039;&#039;&#039;A_fwd_B  = A_left_B % A_up_B;&#039;&#039;&#039;&lt;br /&gt;
 &#039;&#039;&#039;A_left_B = A_up_B % A_fwd_B;&#039;&#039;&#039;&lt;br /&gt;
 &#039;&#039;&#039;A_up_B   = A_fwd_B % A_left_B;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Hence, the cross product of the other two in the order left to right where after &#039;up&#039; you start at &#039;fwd&#039; again; they rotate: ... left up fwd left up fwd ...&lt;br /&gt;
Put a &#039;=&#039; at any space in that sequence and a &#039;%&#039; at the next space and you have the right formula. Also note that x % y = - y % x, in case you were wondering.&lt;br /&gt;
&lt;br /&gt;
Now assume we have the target directions A_*_B, then we can find the rotation between&lt;br /&gt;
A and B with:&lt;br /&gt;
&lt;br /&gt;
 &#039;&#039;&#039;A_rot_B = [[llAxes2Rot]](A_fwd_B, A_left_B, A_up_B);&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Where A_rot_B is the rotation that turns A_*_A into A_*_B:&lt;br /&gt;
&lt;br /&gt;
 A_fwd_B  = A_fwd_A  * A_rot_B&lt;br /&gt;
 A_left_B = A_left_A * A_rot_B&lt;br /&gt;
 A_up_B   = A_up_A   * A_rot_B&lt;br /&gt;
&lt;br /&gt;
=== Finding coordinate systems ===&lt;br /&gt;
&lt;br /&gt;
Assume you already have a coordinate system B (for example, region or object coordinates, the functions for which you can find directly with [[#LSL functions]]).&lt;br /&gt;
&lt;br /&gt;
Finding coordinate system A means that you find A_rot_B (or B_rot_A which is just the inverse), and A_pos_B or B_pos_A.&lt;br /&gt;
&lt;br /&gt;
Finding the rotation is usually the easiest since it doesn&#039;t depend on the where the origin is and can most likely&lt;br /&gt;
be derived somehow. For example, in many cases you will have two orthogonal direction vectors in B that you know&lt;br /&gt;
of to be parallel with the x, y or z axes of A. Lets say that you have AsX_dir_B and a AsY_dir_B that make an angle&lt;br /&gt;
of 90 degrees and have a length of 1, where AsX_dir_B is known to be parallel with the X axis of A and AsY_dir_B&lt;br /&gt;
is known to be parallel with the Y axis of A. Note that in case we can also use the notation A_fwd_B for AsX_dir_B since&lt;br /&gt;
&#039;fwd&#039; is in the X direction (AsX_dir_B means &amp;quot;A&#039;s X-axis direction in coordinates of B&amp;quot;, and A_fwd_B means &amp;quot;A&#039;s&lt;br /&gt;
forwards direction in coordinates of B&amp;quot;, so they are the same thing). Then we find:&lt;br /&gt;
&lt;br /&gt;
 A_rot_B = [[llAxes2Rot]](AsX_dir_B, AsY_dir_B, AsX_dir_B % AsY_dir_B);&lt;br /&gt;
&lt;br /&gt;
as discussed in the previous paragraph.&lt;br /&gt;
&lt;br /&gt;
Next, if you have a vector from_B_to_A pointing from the origin of B to the origin of A, then you have&lt;br /&gt;
the translation between A and B too:&lt;br /&gt;
&lt;br /&gt;
If from_B_to_A is in coordinates of A, then&lt;br /&gt;
&lt;br /&gt;
 B_pos_A = -from_B_to_A&lt;br /&gt;
&lt;br /&gt;
while if from_B_to_A is in coordinates of B, then&lt;br /&gt;
&lt;br /&gt;
 A_pos_B = from_B_to_A&lt;br /&gt;
&lt;br /&gt;
Slight counter intuitive you have to read &#039;A_pos_B&#039; as &#039;The vector pointing from the origin of B to the origin of A&#039;,&lt;br /&gt;
but plausible since it is in the coordinates of B and thus you should expect the vector to start in the origin&lt;br /&gt;
of B.&lt;br /&gt;
&lt;br /&gt;
If you have a series of vectors that are stacked, all the way from B to A, then of course you just add them all up&lt;br /&gt;
to get A_pos_B. Likewise, if you have a series of vectors in the coordinates of A that are stacked to add up&lt;br /&gt;
to go from A to B, then add them all up to get B_pos_A.&lt;br /&gt;
&lt;br /&gt;
The interesting case therefore is where you have a vector C_pos_A that points from A to C and is in the coordinates&lt;br /&gt;
of A, and a vector C_pos_B that points from B to C and in the coordinates of B.&lt;br /&gt;
&lt;br /&gt;
To solve this puzzle, lets first write the vectors slightly different so we&#039;re not confused about&lt;br /&gt;
what they mean, even after converting between the coordinate systems A and B.&lt;br /&gt;
&lt;br /&gt;
Let AC_vec_A be C_pos_A: the vector (arrow) from the origin of A to C (in coordinates of A) and&lt;br /&gt;
let BC_vec_B be C_pos_B: the vector from the origin of B to C (in the coordinates of B).&lt;br /&gt;
Note how the notation of _vec_ is similar to that of _dir_, except that a direction vector has&lt;br /&gt;
a length of 1, and this vector has both a direction and a length: it describes how to get from&lt;br /&gt;
one point to another. Like directions, when converting between them between A and B you ONLY&lt;br /&gt;
apply the rotation A_rot_B! Also note that a vector with a minus sign just means &amp;quot;in the opposite direction&amp;quot;,&lt;br /&gt;
hence CA_vec_A = -AC_vec_A.&lt;br /&gt;
&lt;br /&gt;
Thus, we find that&lt;br /&gt;
&lt;br /&gt;
 AC_vec_B = AC_vec_A * A_rot_B&lt;br /&gt;
&lt;br /&gt;
and find&lt;br /&gt;
&lt;br /&gt;
 A_pos_B = BA_vec_B = BC_vec_B + CA_vec_B = BC_vec_B - AC_vec_B = BC_vec_B - AC_vec_A * A_rot_B&lt;br /&gt;
&lt;br /&gt;
then dropping the extra notation again&lt;br /&gt;
&lt;br /&gt;
 &#039;&#039;&#039;A_pos_B = C_pos_B - C_pos_A * A_rot_B&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Which is rather logical when you read it in English as &amp;quot;To go from B to A in coordinates of B (A_pos_B),&lt;br /&gt;
you first go from B to C in coordinates of B (C_pos_B) and then in the opposite direction (the minus sign)&lt;br /&gt;
of going from A to C (namely from C to A) converted to the coordinates of B.&lt;br /&gt;
&lt;br /&gt;
And oh wonder - if we write this result a little different we find:&lt;br /&gt;
&lt;br /&gt;
 C_pos_A = (C_pos_B - A_pos_B) / A_rot_B&lt;br /&gt;
&lt;br /&gt;
which is the normal conversion for the position of C from A to B coordinates!&lt;br /&gt;
&lt;br /&gt;
=== LSL functions ===&lt;br /&gt;
&lt;br /&gt;
What all of the above taught you is mainly a coding style: use prefixes and postfixes for your rotations (and translations)!&lt;br /&gt;
It&#039;s all in the &#039;&#039;&#039;&#039;&#039;names&#039;&#039;&#039;&#039;&#039; of your variables. A &#039;rotation&#039; type can be the rotation part of a transformation&lt;br /&gt;
(not tight to a particular coordinate system, but rather rotating around whatever coordinate system you apply it to),&lt;br /&gt;
it can be the representation of a unit vector, it can be the rotation part of the orientation of a prim relative to a&lt;br /&gt;
given coordinate system, or it can represent the rotation part of a coordinate system conversion.&lt;br /&gt;
If you don&#039;t use a consistent way to reflect all that in your variable names then you &#039;&#039;will&#039;&#039; get confused.&lt;br /&gt;
&lt;br /&gt;
The LSL functions mostly deal with two types: orientations (position + rotation) of prims relative to some coordinate system,&lt;br /&gt;
and simply transformations (rotation and/or translation).&lt;br /&gt;
&lt;br /&gt;
The table below shows the coordinate systems involved.&lt;br /&gt;
&lt;br /&gt;
{| rules=&amp;quot;all&amp;quot; style=&amp;quot;margin:2em 1em 2em 1em; border:none 2px #000000; background-color:#F9F9F9; font-size:120%; empty-cells:hide;&amp;quot;&lt;br /&gt;
 |-&lt;br /&gt;
 | colspan=2 |&lt;br /&gt;
 | style=&amp;quot;padding: 5px 10px 5px 10px; background-color: #ffdddd; text-align: center&amp;quot; colspan=2 | Coordinates of the prim containing the script (&#039;&#039;&#039;sc_&#039;&#039;&#039;)&lt;br /&gt;
 |- {{Hl2}}&lt;br /&gt;
 ! style=&amp;quot;padding: 5px 10px 5px 10px; color: blue; background-color: #eeeeb0&amp;quot; | Coordinate System&lt;br /&gt;
 ! style=&amp;quot;padding: 5px 10px 5px 10px; color: green; background-color: lightgray&amp;quot; | Abbreviation &lt;br /&gt;
 ! style=&amp;quot;padding: 5px 10px 5px 10px&amp;quot; | script in child prim&lt;br /&gt;
 ! style=&amp;quot;padding: 5px 10px 5px 10px&amp;quot; | script in root prim&lt;br /&gt;
 |-&lt;br /&gt;
 | style=&amp;quot;padding: 5px 10px 5px 10px; color: blue; background-color: #ffffa0&amp;quot; | World/Map Coordinates&lt;br /&gt;
 | style=&amp;quot;padding: 5px 10px 5px 10px&amp;quot;                                         | &#039;&#039;&#039;wc&#039;&#039;&#039;&lt;br /&gt;
 | style=&amp;quot;padding: 5px 10px 5px 10px&amp;quot; colspan=2                               | &amp;lt;span style=&amp;quot;font-family: mono; font-size: 90%&amp;quot;&amp;gt;sc_pos_&#039;&#039;&#039;wc&#039;&#039;&#039; = sc_pos_rc + [[llGetRegionCorner]]()&amp;lt;br&amp;gt;sc_rot_&#039;&#039;&#039;wc&#039;&#039;&#039; = sc_rot_rc&amp;lt;/span&amp;gt;&lt;br /&gt;
 |-&lt;br /&gt;
 | style=&amp;quot;padding: 5px 10px 5px 10px; color: blue; background-color: #ffffa0&amp;quot; | Region Coordinates&lt;br /&gt;
 | style=&amp;quot;padding: 5px 10px 5px 10px&amp;quot;                                         | &#039;&#039;&#039;rc&#039;&#039;&#039;&lt;br /&gt;
 | style=&amp;quot;padding: 5px 10px 5px 10px&amp;quot; colspan=2                               | &amp;lt;span style=&amp;quot;font-family: mono; font-size: 90%&amp;quot;&amp;gt;sc_pos_&#039;&#039;&#039;rc&#039;&#039;&#039; = [[llGetPos]]()&amp;lt;br&amp;gt;sc_rot_&#039;&#039;&#039;rc&#039;&#039;&#039; = [[llGetRot]]()&amp;lt;/span&amp;gt;&lt;br /&gt;
 |-&lt;br /&gt;
 | style=&amp;quot;padding: 5px 10px 5px 10px; color: blue; background-color: #ffffa0&amp;quot; | Object/Root Coordinates&lt;br /&gt;
 | style=&amp;quot;padding: 5px 10px 5px 10px&amp;quot;                                         | &#039;&#039;&#039;oc&#039;&#039;&#039;&lt;br /&gt;
 | style=&amp;quot;padding: 5px 10px 5px 10px&amp;quot;                                         | &amp;lt;span style=&amp;quot;font-family: mono; font-size: 90%&amp;quot;&amp;gt;sc_pos_&#039;&#039;&#039;oc&#039;&#039;&#039; = [[llGetLocalPos]]()&amp;lt;br&amp;gt;sc_rot_&#039;&#039;&#039;oc&#039;&#039;&#039; = [[llGetLocalRot]]()&amp;lt;/span&amp;gt;&lt;br /&gt;
 | style=&amp;quot;padding: 5px 10px 5px 10px&amp;quot;                                         | &amp;lt;span style=&amp;quot;font-family: mono; font-size: 90%&amp;quot;&amp;gt;sc_pos_&#039;&#039;&#039;oc&#039;&#039;&#039; = [[ZERO_VECTOR]]&amp;lt;br&amp;gt;sc_rot_&#039;&#039;&#039;oc&#039;&#039;&#039; = [[ZERO_ROTATION]]&amp;lt;/span&amp;gt;&lt;br /&gt;
 |-&lt;br /&gt;
 | style=&amp;quot;padding: 5px 10px 5px 10px; color: blue; background-color: #ffffa0&amp;quot; | Self Coordinates&lt;br /&gt;
 | style=&amp;quot;padding: 5px 10px 5px 10px&amp;quot;                                         | &#039;&#039;&#039;sc&#039;&#039;&#039;&lt;br /&gt;
 | style=&amp;quot;padding: 5px 10px 5px 10px&amp;quot; colspan=2                               | &amp;lt;span style=&amp;quot;font-family: mono; font-size: 90%&amp;quot;&amp;gt;sc_pos_&#039;&#039;&#039;sc&#039;&#039;&#039; = [[ZERO_VECTOR]]&amp;lt;br&amp;gt;sc_rot_&#039;&#039;&#039;sc&#039;&#039;&#039; = [[ZERO_ROTATION]]&amp;lt;/span&amp;gt;&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
Where &#039;in the root prim&#039; can be detect by testing that [[llGetLinkNumber]]() returns a value &amp;lt;= 1.&lt;br /&gt;
&lt;br /&gt;
Alternatively, you can set link = [[llGetLinkNumber]]() and use the following table which&lt;br /&gt;
shows how to obtain the coordinates of a prim with link number &#039;link&#039; from a script anywhere in the same object.&lt;br /&gt;
Note that this doesn&#039;t work when the object exist of a single prim: then [[llGetLinkNumber]]() returns 0,&lt;br /&gt;
while &#039;link&#039; must be larger than 0 here. If you need to get Object Coordinates (_oc) then do not use the&lt;br /&gt;
negative value [[LINK_THIS]]. You can use [[LINK_THIS]] for the other coordinate systems, provided&lt;br /&gt;
the object exists of at least two prims.&lt;br /&gt;
&lt;br /&gt;
{| rules=&amp;quot;all&amp;quot; style=&amp;quot;margin:2em 1em 2em 1em; border:none 2px #000000; background-color:#F9F9F9; font-size:120%; empty-cells:hide;&amp;quot;&lt;br /&gt;
 |-&lt;br /&gt;
 | colspan=2 |&lt;br /&gt;
 | style=&amp;quot;padding: 5px 10px 5px 10px; background-color: #ffdddd; text-align: center&amp;quot; colspan=2 | Coordinates of a linked prim (&#039;&#039;&#039;link_&#039;&#039;&#039;)&lt;br /&gt;
 |- {{Hl2}}&lt;br /&gt;
 ! style=&amp;quot;padding: 5px 10px 5px 10px; color: blue; background-color: #eeeeb0&amp;quot; | Coordinate System&lt;br /&gt;
 ! style=&amp;quot;padding: 5px 10px 5px 10px; color: green; background-color: lightgray&amp;quot; | Abbreviation &lt;br /&gt;
 ! style=&amp;quot;padding: 5px 10px 5px 10px&amp;quot; | link &amp;gt; 1&lt;br /&gt;
 ! style=&amp;quot;padding: 5px 10px 5px 10px&amp;quot; | link = 1&lt;br /&gt;
 |-&lt;br /&gt;
 | style=&amp;quot;padding: 5px 10px 5px 10px; color: blue; background-color: #ffffa0&amp;quot; | World/Map Coordinates&lt;br /&gt;
 | style=&amp;quot;padding: 5px 10px 5px 10px&amp;quot;                                         | &#039;&#039;&#039;wc&#039;&#039;&#039;&lt;br /&gt;
 | style=&amp;quot;padding: 5px 10px 5px 10px&amp;quot; colspan=2                               | &amp;lt;span style=&amp;quot;font-family: mono; font-size: 90%&amp;quot;&amp;gt;link_pos_&#039;&#039;&#039;wc&#039;&#039;&#039; = link_pos_rc + [[llGetRegionCorner]]()&amp;lt;br&amp;gt;link_rot_&#039;&#039;&#039;wc&#039;&#039;&#039; = link_rot_rc&amp;lt;/span&amp;gt;&lt;br /&gt;
 |-&lt;br /&gt;
 | style=&amp;quot;padding: 5px 10px 5px 10px; color: blue; background-color: #ffffa0&amp;quot; | Region Coordinates&lt;br /&gt;
 | style=&amp;quot;padding: 5px 10px 5px 10px&amp;quot;                                         | &#039;&#039;&#039;rc&#039;&#039;&#039;&lt;br /&gt;
 | style=&amp;quot;padding: 5px 10px 5px 10px&amp;quot; colspan=2                               | &amp;lt;span style=&amp;quot;font-family: mono; font-size: 90%&amp;quot;&amp;gt;link_pos_&#039;&#039;&#039;rc&#039;&#039;&#039; = [[llList2Vector]]([[llGetLinkPrimitiveParams]](&#039;&#039;&#039;link&#039;&#039;&#039;, [&amp;lt;span&amp;gt;&amp;lt;/span&amp;gt;[[PRIM_POSITION]]]), 0)&amp;lt;br&amp;gt;link_rot_&#039;&#039;&#039;rc&#039;&#039;&#039; = [[llList2Rot]]([[llGetLinkPrimitiveParams]](&#039;&#039;&#039;link&#039;&#039;&#039;, [&amp;lt;span&amp;gt;&amp;lt;/span&amp;gt;[[PRIM_ROTATION]]]), 0)&amp;lt;/span&amp;gt;&lt;br /&gt;
 |-&lt;br /&gt;
 | style=&amp;quot;padding: 5px 10px 5px 10px; color: blue; background-color: #ffffa0&amp;quot; | Object/Root Coordinates&lt;br /&gt;
 | style=&amp;quot;padding: 5px 10px 5px 10px&amp;quot;                                         | &#039;&#039;&#039;oc&#039;&#039;&#039;&lt;br /&gt;
 | style=&amp;quot;padding: 5px 10px 5px 10px&amp;quot;                                         | &amp;lt;span style=&amp;quot;font-family: mono; font-size: 90%&amp;quot;&amp;gt;link_pos_&#039;&#039;&#039;oc&#039;&#039;&#039; = [[llList2Vector]]([[llGetLinkPrimitiveParams]](&#039;&#039;&#039;link&#039;&#039;&#039;, [&amp;lt;span&amp;gt;&amp;lt;/span&amp;gt;[[PRIM_POS_LOCAL]]]), 0)&amp;lt;br&amp;gt;link_rot_&#039;&#039;&#039;oc&#039;&#039;&#039; = [[llList2Rot]]([[llGetLinkPrimitiveParams]](&#039;&#039;&#039;link&#039;&#039;&#039;, [&amp;lt;span&amp;gt;&amp;lt;/span&amp;gt;[[PRIM_ROT_LOCAL]]]), 0)&amp;lt;/span&amp;gt;&lt;br /&gt;
 | style=&amp;quot;padding: 5px 10px 5px 10px&amp;quot;                                         | &amp;lt;span style=&amp;quot;font-family: mono; font-size: 90%&amp;quot;&amp;gt;link_pos_&#039;&#039;&#039;oc&#039;&#039;&#039; = [[ZERO_VECTOR]]&amp;lt;br&amp;gt;link_rot_&#039;&#039;&#039;oc&#039;&#039;&#039; = [[ZERO_ROTATION]]&amp;lt;/span&amp;gt;&lt;br /&gt;
 |-&lt;br /&gt;
 | style=&amp;quot;padding: 5px 10px 5px 10px; color: blue; background-color: #ffffa0&amp;quot; | Self Coordinates&lt;br /&gt;
 | style=&amp;quot;padding: 5px 10px 5px 10px&amp;quot;                                         | &#039;&#039;&#039;sc&#039;&#039;&#039;&lt;br /&gt;
 | style=&amp;quot;padding: 5px 10px 5px 10px&amp;quot; colspan=2                               | &amp;lt;span style=&amp;quot;font-family: mono; font-size: 90%&amp;quot;&amp;gt;link_pos_&#039;&#039;&#039;sc&#039;&#039;&#039; = (link_pos_oc - sc_pos_oc) / sc_rot_oc&amp;lt;br&amp;gt;link_rot_&#039;&#039;&#039;sc&#039;&#039;&#039; = link_rot_oc / sc_rot_oc&amp;lt;/span&amp;gt;&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
While the above table works for link = [[LINK_ROOT]], it is probably more convenient to use the following table:&lt;br /&gt;
&lt;br /&gt;
{| rules=&amp;quot;all&amp;quot; style=&amp;quot;margin:2em 1em 2em 1em; border:none 2px #000000; background-color:#F9F9F9; font-size:120%; empty-cells:hide;&amp;quot;&lt;br /&gt;
 |-&lt;br /&gt;
 | colspan=2 |&lt;br /&gt;
 | style=&amp;quot;padding: 5px 10px 5px 10px; background-color: #ffdddd; text-align: center&amp;quot; colspan=2 | Coordinates of the root prim (&#039;&#039;&#039;oc_&#039;&#039;&#039;)&lt;br /&gt;
 |- {{Hl2}}&lt;br /&gt;
 ! style=&amp;quot;padding: 5px 10px 5px 10px; color: blue; background-color: #eeeeb0&amp;quot; | Coordinate System&lt;br /&gt;
 ! style=&amp;quot;padding: 5px 10px 5px 10px; color: green; background-color: lightgray&amp;quot; | Abbreviation &lt;br /&gt;
 ! style=&amp;quot;padding: 5px 10px 5px 10px&amp;quot; | script in any prim&lt;br /&gt;
 |-&lt;br /&gt;
 | style=&amp;quot;padding: 5px 10px 5px 10px; color: blue; background-color: #ffffa0&amp;quot; | World/Map Coordinates&lt;br /&gt;
 | style=&amp;quot;padding: 5px 10px 5px 10px&amp;quot;                                         | &#039;&#039;&#039;wc&#039;&#039;&#039;&lt;br /&gt;
 | style=&amp;quot;padding: 5px 10px 5px 10px&amp;quot;                                         | &amp;lt;span style=&amp;quot;font-family: mono; font-size: 90%&amp;quot;&amp;gt;oc_pos_&#039;&#039;&#039;wc&#039;&#039;&#039; = oc_pos_rc + [[llGetRegionCorner]]()&amp;lt;br&amp;gt;oc_rot_&#039;&#039;&#039;wc&#039;&#039;&#039; = oc_rot_rc&amp;lt;/span&amp;gt;&lt;br /&gt;
 |-&lt;br /&gt;
 | style=&amp;quot;padding: 5px 10px 5px 10px; color: blue; background-color: #ffffa0&amp;quot; | Region Coordinates&lt;br /&gt;
 | style=&amp;quot;padding: 5px 10px 5px 10px&amp;quot;                                         | &#039;&#039;&#039;rc&#039;&#039;&#039;&lt;br /&gt;
 | style=&amp;quot;padding: 5px 10px 5px 10px&amp;quot;                                         | &amp;lt;span style=&amp;quot;font-family: mono; font-size: 90%&amp;quot;&amp;gt;oc_pos_&#039;&#039;&#039;rc&#039;&#039;&#039; = [[llGetRootPosition]]()&amp;lt;br&amp;gt;oc_rot_&#039;&#039;&#039;rc&#039;&#039;&#039; = [[llGetRootRotation]]()&amp;lt;/span&amp;gt;&lt;br /&gt;
 |-&lt;br /&gt;
 | style=&amp;quot;padding: 5px 10px 5px 10px; color: blue; background-color: #ffffa0&amp;quot; | Object/Root Coordinates&lt;br /&gt;
 | style=&amp;quot;padding: 5px 10px 5px 10px&amp;quot;                                         | &#039;&#039;&#039;oc&#039;&#039;&#039;&lt;br /&gt;
 | style=&amp;quot;padding: 5px 10px 5px 10px&amp;quot;                                         | &amp;lt;span style=&amp;quot;font-family: mono; font-size: 90%&amp;quot;&amp;gt;oc_pos_&#039;&#039;&#039;oc&#039;&#039;&#039; = [[ZERO_VECTOR]]&amp;lt;br&amp;gt;oc_rot_&#039;&#039;&#039;oc&#039;&#039;&#039; = [[ZERO_ROTATION]]&amp;lt;/span&amp;gt;&lt;br /&gt;
 |-&lt;br /&gt;
 | style=&amp;quot;padding: 5px 10px 5px 10px; color: blue; background-color: #ffffa0&amp;quot; | Self Coordinates&lt;br /&gt;
 | style=&amp;quot;padding: 5px 10px 5px 10px&amp;quot;                                         | &#039;&#039;&#039;sc&#039;&#039;&#039;&lt;br /&gt;
 | style=&amp;quot;padding: 5px 10px 5px 10px&amp;quot;                                         | &amp;lt;span style=&amp;quot;font-family: mono; font-size: 90%&amp;quot;&amp;gt;oc_pos_&#039;&#039;&#039;sc&#039;&#039;&#039; = - sc_pos_oc / sc_rot_oc&amp;lt;br&amp;gt;oc_rot_&#039;&#039;&#039;sc&#039;&#039;&#039; = [[ZERO_ROTATION]] / sc_rot_oc&amp;lt;/span&amp;gt;&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
As shows from the above table, LSL does not directly support &#039;&#039;&#039;_sc&#039;&#039;&#039; coordinates,&lt;br /&gt;
and I used conversions to fill in the tables. All in all, we listed four coordinate systems (wc, rc, oc and sc; not including the &#039;link_&#039; stuff,&lt;br /&gt;
which isn&#039;t really a separate coordinate system)&lt;br /&gt;
and thus could write out four times four is sixteen ways to convert one into the other. Four of those would be trivial, and of the remaining&lt;br /&gt;
twelve we can express six as the inverse of the other six.&lt;br /&gt;
&lt;br /&gt;
However, lets ignore the World Coordinates for now, which are just the same as the Region Coordinates with an offset for the position.&lt;br /&gt;
Then we have three coordinate systems (rc, oc and sc), leading to nine conversion, three of which are trivial, and of the remaining&lt;br /&gt;
six three can be expressed as the inverse of the other three. Those three are: oc_*_rc, sc_*_rc and sc_*_oc, which are all listed above.&lt;br /&gt;
The trivial ones, rc_*_rc, oc_*_oc and sc_*_sc, are all ZERO_* (the latter two also are listed in the tables above).&lt;br /&gt;
Finally, the inverse values, rc_*_oc, rc_*_sc and oc_*_sc can be expressed with the inversion formula given in [[#Converting between coordinate systems]].&lt;br /&gt;
So this is really all there is.&lt;br /&gt;
&lt;br /&gt;
=== The fourth dimension ===&lt;br /&gt;
&lt;br /&gt;
Picture a coordinate system as three perpendicular lines, like an object in-world perhaps existing of&lt;br /&gt;
three really long prims in the colors red, green and blue. You can toss them into the region&lt;br /&gt;
where they randomly bounce around like dice &amp;amp;ndash; a whole bunch of them!&lt;br /&gt;
And then you freeze time - make a snapshot.&lt;br /&gt;
&lt;br /&gt;
With the knowledge so far you can now express the position and rotation of an object or prim relative&lt;br /&gt;
to any of those coordinate systems &amp;amp;ndash; and convert between them at will.&lt;br /&gt;
Apply rotations and translations relative to any chosen system.&lt;br /&gt;
All of the coordinate systems are virtually the same! But in practice isn&#039;t the case, why is that?&lt;br /&gt;
&lt;br /&gt;
The reason is that in practice coordinate systems change in time, in a way that you cannot predict.&lt;br /&gt;
It&#039;s like they are still tumbling and bouncing around and you have no idea where they are.&lt;br /&gt;
&lt;br /&gt;
This noise comes mainly from one thing: objects are being moved. Taken into repositories and rezzed back,&lt;br /&gt;
rotated and possibly even scaled! In fact, not just objects, but also prims inside objects can be changed&lt;br /&gt;
at will at any moment and a good script must take that into account.&lt;br /&gt;
&lt;br /&gt;
The art of programming therefore becomes &#039;&#039;design&#039;&#039;. You must choose which coordinate systems you&lt;br /&gt;
want to use; what your global variables store: relative to which coordinate system!&lt;br /&gt;
&lt;br /&gt;
Unfortunately, a script can &#039;&#039;not&#039;&#039; detect when this might have happened and only perform extra computations,&lt;br /&gt;
or re-computation, of otherwise constant variables when a prim or object has actually been changed.&lt;br /&gt;
There is an LSL event [[moving_start]] but that only works half on SL and not at all on opensim.&lt;br /&gt;
For rotation detection there is nothing.&lt;br /&gt;
&lt;br /&gt;
As such, it is necessary to call the LSL functions listed in the tables above every time you&lt;br /&gt;
want to do anything that depends on them; which hopefully won&#039;t be too often.&lt;br /&gt;
&lt;br /&gt;
The following example script can be put in the root prim of an object of any number of cubes&lt;br /&gt;
and allows one to sit on each cube, using [[llLinkSitTarget]], even if you move or rotate&lt;br /&gt;
child prims.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;lsl&amp;gt;&lt;br /&gt;
// An script written to show how to use coordinate systems in LSL.&lt;br /&gt;
//&lt;br /&gt;
// Copyright(c) Timmy Songbird, 2014 test 2&lt;br /&gt;
// &lt;br /&gt;
// This program is free software; you can redistribute it and/or modify&lt;br /&gt;
// it under the terms of the GNU General Public License as published by&lt;br /&gt;
// the Free Software Foundation; either version 2 of the License, or&lt;br /&gt;
// (at your option) any later version.&lt;br /&gt;
//&lt;br /&gt;
// This program is distributed in the hope that it will be useful,&lt;br /&gt;
// but WITHOUT ANY WARRANTY; without even the implied warranty of&lt;br /&gt;
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the&lt;br /&gt;
// GNU General Public License for more details.&lt;br /&gt;
//&lt;br /&gt;
// You should have received a copy of the GNU General Public License&lt;br /&gt;
// along with this program; if not, write to the Free Software&lt;br /&gt;
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307, USA.&lt;br /&gt;
&lt;br /&gt;
// GitLocation: tests/llLinkSitTarget_Test.lsl&lt;br /&gt;
&lt;br /&gt;
// This script uses the follow coordinate systems:&lt;br /&gt;
//&lt;br /&gt;
// rc     : Region Coordinates.&lt;br /&gt;
// oc     : Object, or root prim, Coordinates.&lt;br /&gt;
// link   : Coordinates of prim with link number &#039;link&#039;.&lt;br /&gt;
// STc    : Coordinates of the touched face (see llDetectedTouchST)&lt;br /&gt;
//          (x and y in the ranger [0, 1] with (0, 0) in the bottom-left corner).&lt;br /&gt;
// center : Coordinates of the touched face with the origin in the center,&lt;br /&gt;
//          the orientation is the same as STc (z is the normal of the surface),&lt;br /&gt;
//          but scaled to be in meters.&lt;br /&gt;
// stc    : Sit Target Coordinates. The origin is at the sit target, the x is&lt;br /&gt;
//          the fwd direction (the direction the avatar is facing), z is up.&lt;br /&gt;
// ac     : Avatar center Coordinates. This is really the same as stc, but&lt;br /&gt;
//          moved up an offset. Rotations passed to llLinkSitTarget are&lt;br /&gt;
//          relative to this coordinate system.&lt;br /&gt;
&lt;br /&gt;
// The sit position of the sit target.&lt;br /&gt;
// This value is *different* in SL and opensim, and even changed since opensim version 0.7.6.&lt;br /&gt;
// The currently measured values for the z component are:&lt;br /&gt;
// SL: 0.05, opensim 0.7.6: 0.0, opensim 0.8.x: -0.036834&lt;br /&gt;
// Use this in SL:&lt;br /&gt;
//vector sittarget_pos_ac = &amp;lt;0.0, 0.0, 0.05&amp;gt;;&lt;br /&gt;
// Use this on opensim 0.7.6:&lt;br /&gt;
vector sittarget_pos_ac = &amp;lt;0.0, 0.0, 0.0&amp;gt;;&lt;br /&gt;
// Use this on opensim &amp;gt;= 0.8:&lt;br /&gt;
//vector sittarget_pos_ac = &amp;lt;0.0, 0.0, -0.036834&amp;gt;;&lt;br /&gt;
&lt;br /&gt;
// face_link() returns a list of vectors in link coordinates.&lt;br /&gt;
//&lt;br /&gt;
// Returns: [bottomLeft_link, topRight_link].&lt;br /&gt;
//&lt;br /&gt;
// bottomLeft_link is the bottom left corner of the given face,&lt;br /&gt;
// that is - the corner where (S, T) = (0, 0).&lt;br /&gt;
// topRight_link is the top right corner of the given face,&lt;br /&gt;
// that is - the corner where (S, T) = (1, 1).&lt;br /&gt;
list face_link(integer link, integer face)&lt;br /&gt;
{&lt;br /&gt;
  list params = llGetLinkPrimitiveParams(link, [PRIM_TYPE, PRIM_SIZE]);&lt;br /&gt;
  vector bottomLeft_link;&lt;br /&gt;
  vector topRight_link;&lt;br /&gt;
  integer prim_type = llList2Integer(params, 0);&lt;br /&gt;
  if (prim_type == PRIM_TYPE_BOX)&lt;br /&gt;
  {&lt;br /&gt;
    topRight_link = llList2Vector(params, 7) * 0.5;&lt;br /&gt;
    if (face == 0)&lt;br /&gt;
    {&lt;br /&gt;
      bottomLeft_link = -topRight_link;&lt;br /&gt;
      bottomLeft_link.z = topRight_link.z;&lt;br /&gt;
    }&lt;br /&gt;
    else if (face == 1)&lt;br /&gt;
    {&lt;br /&gt;
      bottomLeft_link = -topRight_link;&lt;br /&gt;
      topRight_link.y = bottomLeft_link.y;&lt;br /&gt;
    }&lt;br /&gt;
    else if (face == 2)&lt;br /&gt;
    {&lt;br /&gt;
      bottomLeft_link = -topRight_link;&lt;br /&gt;
      bottomLeft_link.x = topRight_link.x;&lt;br /&gt;
    }&lt;br /&gt;
    else if (face == 3)&lt;br /&gt;
    {&lt;br /&gt;
      topRight_link.x = -topRight_link.x;&lt;br /&gt;
      bottomLeft_link = -topRight_link;&lt;br /&gt;
      bottomLeft_link.y = topRight_link.y;&lt;br /&gt;
    }&lt;br /&gt;
    else if (face == 4)&lt;br /&gt;
    {&lt;br /&gt;
      topRight_link.y = -topRight_link.y;&lt;br /&gt;
      bottomLeft_link = -topRight_link;&lt;br /&gt;
      topRight_link.x = bottomLeft_link.x;&lt;br /&gt;
    }&lt;br /&gt;
    else if (face == 5)&lt;br /&gt;
    {&lt;br /&gt;
      topRight_link.y = -topRight_link.y;&lt;br /&gt;
      topRight_link.z = -topRight_link.z;&lt;br /&gt;
      bottomLeft_link = -topRight_link;&lt;br /&gt;
      bottomLeft_link.z = topRight_link.z;&lt;br /&gt;
    }&lt;br /&gt;
    else&lt;br /&gt;
    {&lt;br /&gt;
      llWhisper(0, &amp;quot;This script only supports sitting on boxes without cuts or holes.&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
  else&lt;br /&gt;
  {&lt;br /&gt;
    llWhisper(0, &amp;quot;This script does not work for non-box prims.&amp;quot;);&lt;br /&gt;
  }&lt;br /&gt;
  return [bottomLeft_link, topRight_link];&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
default&lt;br /&gt;
{&lt;br /&gt;
  touch_start(integer num)&lt;br /&gt;
  {&lt;br /&gt;
    integer n;&lt;br /&gt;
    // Run over everyone that might have touch a prim (it could be more than one!)&lt;br /&gt;
    for (n = 0; n &amp;lt; num; ++n)&lt;br /&gt;
    {&lt;br /&gt;
      // Get the link number of the touch prim.&lt;br /&gt;
      integer link = llDetectedLinkNumber(n);&lt;br /&gt;
&lt;br /&gt;
      // Some conversion variables we need, copied directly from the table above.&lt;br /&gt;
      vector   link_pos_rc = llList2Vector(llGetLinkPrimitiveParams(link, [PRIM_POSITION]), 0);&lt;br /&gt;
      rotation link_rot_rc = llList2Rot(llGetLinkPrimitiveParams(link, [PRIM_ROTATION]), 0);&lt;br /&gt;
&lt;br /&gt;
      // Get the face of that prim that was touched.&lt;br /&gt;
      integer face = llDetectedTouchFace(n);&lt;br /&gt;
      if (face == TOUCH_INVALID_FACE)&lt;br /&gt;
      {&lt;br /&gt;
        llInstantMessage(llDetectedKey(n), &amp;quot;Sorry, your viewer does not support touched faces.&amp;quot;);&lt;br /&gt;
      }&lt;br /&gt;
      else&lt;br /&gt;
      {&lt;br /&gt;
        // llDetectedTouchPos returns the position where an object was touched in Region Coordinates.&lt;br /&gt;
        vector touch_pos_rc = llDetectedTouchPos(n);&lt;br /&gt;
        // Convert that into link coordinates.&lt;br /&gt;
        vector touch_pos_link = (touch_pos_rc - link_pos_rc) / link_rot_rc;&lt;br /&gt;
&lt;br /&gt;
        // llDetectedTouchBinormal returns a normalized, directional vector in Region Coordinates.&lt;br /&gt;
        // So, it&#039;s not a position; it is a direction (dir), really representing a rotation.&lt;br /&gt;
        vector binormal_dir_rc = llDetectedTouchBinormal(n);&lt;br /&gt;
&lt;br /&gt;
        // In general a direction vector can not be converted to a rotation (when the&lt;br /&gt;
        // starting reference vector is (almost) the same as the direction vector, which&lt;br /&gt;
        // might be the case here since we have no idea where the vector is pointing to).&lt;br /&gt;
        // Therefore we just leave it as a vector, but we treat it the same as a rotation:&lt;br /&gt;
        // leave the origin alone and just correct the rotation when converting to the&lt;br /&gt;
        // local coordinate system of the link prim.&lt;br /&gt;
        vector binormal_dir_link = binormal_dir_rc / link_rot_rc; // binormal_dir_rc * rc_rot_link&lt;br /&gt;
&lt;br /&gt;
        // llDetectedTouchNormal returns a normalized, directional vector in Region Coordinates.&lt;br /&gt;
        // It is perpendicular to the surface (pointing outwards) and makes an angle of 90 degrees&lt;br /&gt;
        // with binormal_dir. Here we immediately convert it to _link coordinates.&lt;br /&gt;
        vector normal_dir_link = llDetectedTouchNormal(n) / link_rot_rc;&lt;br /&gt;
&lt;br /&gt;
        // Calculate the tangent vector.&lt;br /&gt;
        vector tangent_dir_link = binormal_dir_link % normal_dir_link;&lt;br /&gt;
&lt;br /&gt;
        // Get the [bottomLeft_link, topRight_link] positions of the surface &#039;face&#039;, in link coordinates.&lt;br /&gt;
        list surface_link = face_link(link, face);&lt;br /&gt;
        vector bottomLeft_pos_link = llList2Vector(surface_link, 0);&lt;br /&gt;
        vector topRight_pos_link = llList2Vector(surface_link, 1);&lt;br /&gt;
&lt;br /&gt;
        // Calculate the center of the surface.&lt;br /&gt;
        vector center_pos_link = (bottomLeft_pos_link + topRight_pos_link) * 0.5;&lt;br /&gt;
&lt;br /&gt;
        // The unit x vector in link coordinates is obviously &amp;lt;1, 0, 0&amp;gt;, center_rot_link is&lt;br /&gt;
        // therefore the rotation that is needed to rotate that to tangent_dir_link, which&lt;br /&gt;
        // represents &amp;lt;1, 0, 0&amp;gt; in center coordinates (the positive S direction).&lt;br /&gt;
        // The positive T direction, or &amp;lt;0, 1, 0&amp;gt; in center coordinates, is the binormal vector.&lt;br /&gt;
        // llAxes2Rot(fwd, left, up) returns the rotation needed to rotate &amp;lt;1, 0, 0&amp;gt; to fwd,&lt;br /&gt;
        // and &amp;lt;0, 1, 0&amp;gt; to left (and thus &amp;lt;0, 0, 1&amp;gt; to up).&lt;br /&gt;
        rotation center_rot_link = llAxes2Rot(tangent_dir_link, binormal_dir_link, normal_dir_link);&lt;br /&gt;
&lt;br /&gt;
        // llDetectedTouchST returns a vector in the plane of the touched surface,&lt;br /&gt;
        // with x and y ranging from 0,0 in the &amp;quot;bottom left&amp;quot; corner till 1,1 for&lt;br /&gt;
        // opposite corner. The value is thus in ST Coordinates.&lt;br /&gt;
        vector touch_pos_STc = llDetectedTouchST(n);&lt;br /&gt;
&lt;br /&gt;
        // Caluclate the size of the surface and rotate it in the plane of the center coordinates.&lt;br /&gt;
        vector center_link_scale = (topRight_pos_link - bottomLeft_pos_link) / center_rot_link;&lt;br /&gt;
&lt;br /&gt;
        // Convert touch_pos to center coordinates.&lt;br /&gt;
        vector touch_pos_center = &amp;lt;(touch_pos_STc.x - 0.5) * center_link_scale.x, (touch_pos_STc.y - 0.5) * center_link_scale.y, 0.0&amp;gt;;&lt;br /&gt;
&lt;br /&gt;
        // Calculate a unit vector from the touch position to the edge.&lt;br /&gt;
        vector edge_dir_center;&lt;br /&gt;
        // Find the nearest edge.&lt;br /&gt;
        vector edge_pos_center = touch_pos_center;&lt;br /&gt;
        if (center_link_scale.x * 0.5 - llFabs(edge_pos_center.x) &amp;gt; center_link_scale.y * 0.5 - llFabs(edge_pos_center.y))&lt;br /&gt;
        {&lt;br /&gt;
          integer positive = llRound(touch_pos_STc.y);&lt;br /&gt;
          edge_pos_center.y = (positive - 0.5) * center_link_scale.y;&lt;br /&gt;
          edge_dir_center = &amp;lt;0, positive * 2 - 1, 0&amp;gt;;&lt;br /&gt;
        }&lt;br /&gt;
        else&lt;br /&gt;
        {&lt;br /&gt;
          integer positive = llRound(touch_pos_STc.x);&lt;br /&gt;
          edge_pos_center.x = (positive - 0.5) * center_link_scale.x;&lt;br /&gt;
          edge_dir_center = &amp;lt;positive * 2 - 1, 0, 0&amp;gt;;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        // Convert edge_dir_center to link coordinates (because llLinkSitTarget takes link coordinates).&lt;br /&gt;
        vector edge_dir_link = edge_dir_center * center_rot_link;&lt;br /&gt;
&lt;br /&gt;
        llOwnerSay(&amp;quot;edge_dir_link = &amp;quot; + (string)edge_dir_link);&lt;br /&gt;
&lt;br /&gt;
        // Calculate the rotation of the seated avatar from this direction, using the fact that we still have normal_dir_link.&lt;br /&gt;
        // This puts the fwd direction of the avatar in the direction edge_dir (from touch point to nearest edge)&lt;br /&gt;
        // and the up direction of the avatar perpendicular to the touched surface.&lt;br /&gt;
        rotation ac_rot_link = llAxes2Rot(edge_dir_link, normal_dir_link % edge_dir_link, normal_dir_link);&lt;br /&gt;
&lt;br /&gt;
        // Where do we want to sit?&lt;br /&gt;
        // Currently lets just sit where the user clicked, without limits or corrections.&lt;br /&gt;
        vector sit_pos_center = touch_pos_center;&lt;br /&gt;
&lt;br /&gt;
        // Convert the sit position to link coordinates (because llLinkSitTarget takes link coordinates).&lt;br /&gt;
        vector sit_pos_link = sit_pos_center * center_rot_link + center_pos_link;&lt;br /&gt;
&lt;br /&gt;
        // This vector is really a function of avatar shape and what looks&lt;br /&gt;
        // aesthetically pleasing. However, it is only minimal a function&lt;br /&gt;
        // avatar height (the only thing we can roughly know from a script)&lt;br /&gt;
        // and much more a function of shape values that we can&#039;t know.&lt;br /&gt;
        // So for now, just leave this as a constant.&lt;br /&gt;
        //&lt;br /&gt;
        // In ascii art, a sitting avatar looks more or less like this:&lt;br /&gt;
        //                ^&lt;br /&gt;
        //                |z&lt;br /&gt;
        //            ac_ |&lt;br /&gt;
        //               \| &lt;br /&gt;
        //         &amp;lt;--x---O   ()      &#039;O&#039; is the Origin of ac (Avatar center (attach point) Coordinates).&lt;br /&gt;
        //                |   /|      &#039;*&#039; is the sittarget (passed to llSitTarget) and is 0.4m below O.&lt;br /&gt;
        //    sittarget--&amp;gt;*__/_/&lt;br /&gt;
        //               _/   ^__ sit_pos_ac, 0.62 below O, and 0.34 backwards.&lt;br /&gt;
        //                |&lt;br /&gt;
        vector sit_pos_ac = &amp;lt;-0.34, 0.0, -0.62&amp;gt;;&lt;br /&gt;
&lt;br /&gt;
        // Find the translation of the ac coordinate system.&lt;br /&gt;
        vector ac_pos_link = sit_pos_link - sit_pos_ac * ac_rot_link;&lt;br /&gt;
&lt;br /&gt;
        // Convert the sittarget from ac coordinates to link coordinates.&lt;br /&gt;
        vector sittarget_pos_link = sittarget_pos_ac * ac_rot_link + ac_pos_link;&lt;br /&gt;
&lt;br /&gt;
        // Grid dependent vertical offset.&lt;br /&gt;
        //&lt;br /&gt;
        // This is a historical offset introduced by Linden Lab from the beginning.&lt;br /&gt;
        // It is actually a mistake because when the avatar is rotated this causes&lt;br /&gt;
        // the avatar to move sideways! Apparently also Philips Linden found rotations&lt;br /&gt;
        // hard to understand.&lt;br /&gt;
        if (llFabs(sittarget_pos_ac.z) &amp;lt; 0.01)&lt;br /&gt;
        {&lt;br /&gt;
          // opensim version 0.7.6&lt;br /&gt;
          // Obviously, this should have been the same as on SL.&lt;br /&gt;
          // Later it got &amp;quot;corrected&amp;quot;, but in a wrong way (sittarget_pos_ac still differs with SL).&lt;br /&gt;
          sittarget_pos_link.z -= 0.418;&lt;br /&gt;
        }&lt;br /&gt;
        else&lt;br /&gt;
        {&lt;br /&gt;
          // SL and opensim &amp;gt;= 0.8.&lt;br /&gt;
          sittarget_pos_link.z -= 0.4;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        // Set the sit target.&lt;br /&gt;
        llLinkSitTarget(link, sittarget_pos_link, ac_rot_link);&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/lsl&amp;gt;&lt;/div&gt;</summary>
		<author><name>Timmy Foxclaw</name></author>
	</entry>
</feed>