# LlRotBetween

(Redirected from LSL llRotBetween)

 LSL Portal
Function: rotation llRotBetween( vector start, vector end );
 21 Function ID 0 Forced Delay 10 Energy

Returns a rotation that is the shortest rotation between the direction start and the direction end

 • vector start • vector end

## Specification

start and end are directions and are relative to the origin <0.0, 0.0, 0.0>. If you have coordinates relative to a different origin, subtract that origin from the input vectors.

## Caveats

• `start * llRotBetween(start, end) == end` is only true if start and end have the same magnitude and neither have a magnitude of zero (see #Useful Snippets for a workaround).
• This of course is ignoring floating point precision errors.
• The above is true because of vector magnitudes and not a shortcoming of this function. The rotation returned is correct regardless of magnitudes
• Rotations are from -PI to +PI around each axis.

#### Important Issues

 SCR-309 llRotBetween has issues, give us something better

## Examples

```llRotBetween(<1.0, 0.0, 0.0>, <0.0, -1.0, 0.0>)
// will return <0.00000, 0.00000, -0.70711, 0.70711> (which represents -90 degrees on the z axis)

llRotBetween(<0.0, 0.0, 0.0>, <0.0, -1.0, 0.0>)
// will return <0.00000, 0.00000, 0.00000, 1.00000> (which represents a zero angle on all axis)
// because <0.0, 0.0, 0.0> does not convey a direction.```

## Useful Snippets

This function adjusts the magnitude of the quaternion so `start * llRotBetween(start, end) == end` is true as long as neither have a magnitude really close to zero. They do not have to have the same magnitude. (If either is too close to zero than this will return an unadjusted quaternion). While this is mathematically correct, it won't help with floating point rounding errors, so it's more accurate to say `start * return ≈ end`.

```rotation RotBetween(vector start, vector end) //adjusts quaternion magnitude so (start * return == end)
{//Authors note: I have never had a use for this but it's good to know how to do it if I did.
rotation rot = llRotBetween(start, end);
float d = start * start;
if(d)//is 'start' zero?
if((d = llPow(end * end / d, 0.25)))//is 'end' zero?
return <rot.x * d, rot.y * d, rot.z * d, rot.s * d>;
return rot;
}//Strife Onizuka```

## Notes

Vectors that are near opposite each other in direction may lead to erroneous results.

```// First Vector is due north second vector is ALMOST due south.
rotation lRotation = llRotBetween( <0., 1., 0.>, <-0.001, -.1, 0.> );
llSay(0, lRotation );
// Provides a result of <1.00000, 0.00000, 0.00000, 0.00000>.```

### Functions

 • llAngleBetween

## Deep Notes

### Replacement

Due to the annoying quirks of this function Moon Metty wrote a drop in replacement. - SCR-309. The maximum error is reported to be 2.7e-7 @ 2.2 radians.

```rotation RotBetween(vector a, vector b)
{
float aabb = llSqrt((a * a) * (b * b)); // product of the lengths of the arguments
if (aabb)
{
float ab = (a * b) / aabb; // normalized dotproduct of the arguments (cosine)
vector c = <(a.y * b.z - a.z * b.y) / aabb,
(a.z * b.x - a.x * b.z) / aabb,
(a.x * b.y - a.y * b.x) / aabb >; // normalized crossproduct of the arguments
float cc = c * c; // squared length of the normalized crossproduct (sine)
if (cc) // test if the arguments are not (anti)parallel
{
float s;
if (ab > -0.707107)
s = 1 + ab; // use the cosine to adjust the s-element
else
s = cc / (1 + llSqrt(1 - cc)); // use the sine to adjust the s-element
float m = llSqrt(cc + s * s); // the magnitude of the quaternion
return <c.x / m, c.y / m, c.z / m, s / m>; // return the normalized quaternion
}
if (ab > 0)
return ZERO_ROTATION; // the arguments are parallel, or anti-parallel if not true:
float m = llSqrt(a.x * a.x + a.y * a.y); // the length of one argument projected on the XY-plane
if (m)
return <a.y / m, -a.x / m, 0, 0>; // return a rotation with the axis in the XY-plane
return <1, 0, 0, 0>; // the arguments are parallel to the Z-axis, rotate around the X-axis
}
return ZERO_ROTATION; // the arguments are too small, return zero rotation
}//Written by Moon Metty, optimized by Strife Onizuka

// This version keeps the axis in the XY-plane, in case of anti-parallel vectors (unlike the current LL implementation). -- Moon Metty```

### Bad Reference Implementation

```//Loosely based on SL source code, like SL's version, it's not very accurate. You want to use the above version.
rotation llRotBetween(vector start, vector end) {
vector v1 = llVecNorm(start);
vector v2 = llVecNorm(end);
float dot = v1 * v2;
vector axis = v1 % v2;
if (dot < -0.9999999) {
// 180 degrees or there abouts
vector ortho_axis = llVecNorm(<1.f, 0.f, 0.f> - (v1 * (v1.x / (v1 * v1))));
if (ortho_axis)
return < ortho_axis.x, ortho_axis.y, ortho_axis.z, 0.f>;
return <0.0, 0.0, 1.0, 0.0>;
}
else if(dot > 0.9999999) {
//parallel
return ZERO_ROTATION;
}
dot = dot + 1.0;
float m = llPow((axis * axis) + (dot * dot), -0.5);
return <axis.x * m, axis.y * m, axis.z * m, dot * m>;
}```

### llRotBetween alternatives

#### All Issues

 SVC-4415 llRotBetween sometimes gives erroneous results. SCR-309 llRotBetween has issues, give us something better

#### Signature

```function rotation llRotBetween( vector start, vector end );
```