03-30-2008 07:10
These functions generate series of position/rotation pairs using the Hermit curve third degree polynom (a.k.a the Bezier Curve) in order to simulate smooth, accelerating/decelerating, curved trajectory between pairs of position/rotation/speeds.

CODE

// Bezier curve trajectory generator
//
// outputs series of position/rotation pairs describing a smooth, accelerating/decelerating trajectory between two positions

integer running;

vector va;
vector vb;
vector vta;
vector vtb;
rotation ra;
rotation rb;
vector vt;
rotation rt;
float dist;
float angle;
vector axis;
integer steps;
integer mul = 0;
integer max = 8;

float off;
float offa;
float offb;
float speed;
float next_speed;
float t;
float u;
float rate = 0.05;
float rad = 0.425;
float corr = 1.9;
float banking = -3.14159;
float tilting = 3.0; // one fourth the vertical tilt of the trajectory, set to 0.0 for full tilt, -2.0 for reverse

move()
{
llSetTimerEvent(rate);
va = llGetRootPosition() + llGetRegionCorner();
ra = llGetRootRotation();
vta = llRot2Fwd(ra);
vtb = llRot2Fwd(rb);
off = llSqrt(speed / next_speed);
dist = rad * llVecMag(vb - va);

vta = (dist * off * vta);
vtb = (dist * vtb / off);

dist = corr * (llVecMag(vta) + llVecMag(vta - vtb) + llVecMag(vtb));
vta = va + vta;
vtb = vb - vtb;

steps = llCeil(dist / (speed + next_speed));
float f = 1.0 / steps;
offa = f * off;
offb = f / off;

t = 0.0;
u = 1.0;
}

flat()
{
rt = llGetRootRotation();
vt = llRot2Fwd(rt);
va = <vt.x, vt.y, .0>;
rt = llRotBetween(<1,0,0>, va) * llRotBetween(va, vt);
mul = (mul + 1) % max;
vt = llGetRootPosition();
// now t and rt contain the upright static position and rotation for stopping
}

next_move()
{
vector v;
vector vh;
vector vo;
t = t + (t * offb + u * offa);
u = 1.0 - t;
mul = (mul + 1) % max;

vector corner = llGetRegionCorner();
v = vt;
vo = llRot2Left(rt);
vt = (u*u*u*(va - corner) + 3*t*u*u*(vta - corner) + 3*t*t*u*(vtb - corner) + t*t*t*(vb - corner));
v = (vt - v);
vh = <v.x, v.y, .0>;
float f = v * vo;
if (llFabs(f) > 0.0078125)
rt = llEuler2Rot(<banking * (v * vo), .0, .0>) * llRotBetween(<1,0,0>, vh) * llRotBetween(vh, v + (tilting * vh));
else rt = llRotBetween(<1,0,0>, vh) * llRotBetween(vh, v + (tilting * vh));
}

init(vector target_position, rotation target_orientation, float target_velocity)
{
rb = target_orientation;
vb = target_position + llGetRegionCorner();

next_speed = llFabs(target_velocity);
if (next_speed < 0.003125) next_speed = 0.003125;
move();
}

default
{
state_entry()
{
speed = 0.003125;
next_speed = 0.003125;
running = TRUE;
}

timer()
{
next_move();
// now your next position and rotation to move to are recorded in vt (in region coords) and rt
// PUT YOU MOVEMENT CODE HERE (llSetPos or anything else)

if (t > 1.0)
{
// done with the current step
llSetTimerEvent(0.0);
speed = next_speed;
// call flat() to get the static position and rotation (= upright) in vt and rt if you are stopping
}
}
}


To use, call the init() function with your desired next position, rotation and speed to attain smoothly. It will set the parameters (va, ra and vta for the starting position/rotation/speed, vb, rb and vtb for the targetted position/rotation/speed, and a few more parameters) by calling the move() function, then will run the timer which will call next_move(), the function that generates the interpolated steps. Add your own code in the timer to do whatever needs be done with the generated position/rotation pairs.

I have a version of this that interfaces with Multimove and reads from notecards so you can make automated vehicles, if needed.
_____________________
Either Man can enjoy universal freedom, or Man cannot. If it is possible then everyone can act freely if they don't stop anyone else from doing same. If it is not possible, then conflict will arise anyway so punch those that try to stop you. In conclusion the only strategy that wins in all cases is that of doing what you want against all adversity, as long as you respect that right in others.