Welcome to the Second Life Forums Archive

These forums are CLOSED. Please visit the new forums HERE

Plane / vector intersection.

James Dayton
Registered User
Join date: 14 Nov 2003
Posts: 2
05-31-2005 19:52

Autopilot woes. I need someone who took linear algebra more recently than me.

I would like my autonomous vehicle, upon approaching an edgeofworld (or other, arbitrary vertical plane), to bank to the left or right, depending on which turn will be shallower.

I need to puzzle out, based on my current vector pos and curent vector vel:

1. Which wall (plane, edgeOfWorld) am I slated to hit first:

Wall, Position, Line normal (like perpendicular, but 2D) to plane.
N,<0,128,0>,<0,1,0>
S,<0,0,0>,<0,1,0>

E,<128,128,0>,<1,0,0>
W,<0,0,0>,<1,0,0>


2. How far away is the intersection of my direction from my position pos?

3. What angle does it make with the plane? Turn towards the side that makes an obtuse angle.

I know there is some nifty cross-product-and-rotation-using way to do this in a few lines. Otherwise I am going to have to drop the z coord, make this a line-intersection problem and do plain old systems of two equations.

Does anyone have any elegant solutions for this?

James Dayton

Jeffrey Gomez
Cubed™
Join date: 11 Jun 2004
Posts: 3,522
05-31-2005 21:07
Interestingly, this is not all that different from my "touch position" script. Let me pull that up, with some minor revisions.

This should give where you are in a sim in a -1 to 1 format. Face numbers correspond to those on a cube prim.

/15/ee/38717/1.html

CODE
list spawns = [];

vector start = llGetPos();
vector diff = llRot2Fwd(llGetRot());

vector mypos = <128,128,384>; // Works for any sim
rotation myrot = <0,0,0,1>; // Sims can't rotate, but leave this anyway.
vector size = <128,128,384>; // Assume normal sim dimensions: <256,256,768>

// Unrotate our vectors...
diff /= myrot;
start = mypos + ((start - mypos) / myrot);

if(diff.x == 0) diff.x = 0.01;
if(diff.y == 0) diff.y = 0.01;
if(diff.z == 0) diff.z = 0.01;

vector zero_x = start + ((mypos.x - start.x) * diff / diff.x) - mypos; // When X = 0
vector zero_y = start + ((mypos.y - start.y) * diff / diff.y) - mypos; // When Y = 0
vector zero_z = start + ((mypos.z - start.z) * diff / diff.z) - mypos; // When Z = 0

vector temp;
// Plane: Face 0
temp = zero_z + (size.z * diff / diff.z);
if(llSqrt(llPow(temp.x,2)) <= size.x && llSqrt(llPow(temp.y,2)) <= size.y)
{
spawns += temp;
spawns += 0;
}


// Plane: Face 1
temp = zero_y - (size.y * diff / diff.y);
if(llSqrt(llPow(temp.x,2)) <= size.x && llSqrt(llPow(temp.z,2)) <= size.z)
{
spawns += temp;
spawns += 1;
}

// Plane: Face 2
temp = zero_x + (size.x * diff / diff.x);
if(llSqrt(llPow(temp.y,2)) <= size.y && llSqrt(llPow(temp.z,2)) <= size.z)
{
spawns += temp;
spawns += 2;
}

// Plane: Face 3
temp = zero_y + (size.y * diff / diff.y);
if(llSqrt(llPow(temp.x,2)) <= size.x && llSqrt(llPow(temp.z,2)) <= size.z)
{
spawns += temp;
spawns += 3;
}

// Plane: Face 4
temp = zero_x - (size.x * diff / diff.x);
if(llSqrt(llPow(temp.y,2)) <= size.y && llSqrt(llPow(temp.z,2)) <= size.z)
{
spawns += temp;
spawns += 4;
}

// Plane: Face 5
temp = zero_z - (size.z * diff / diff.z);
if(llSqrt(llPow(temp.x,2)) <= size.x && llSqrt(llPow(temp.y,2)) <= size.y)
{
spawns += temp;
spawns += 5;
}

integer i;
integer count = llGetListLength(spawns);


count = llGetListLength(spawns);
for(i = 0; i < count; i += 2)
{
temp = llList2Vector(spawns,i);
temp = <temp.x / size.x,temp.y / size.y, temp.z / size.z>;

llSay(0,"Intersection at Face " + (string)llList2Integer(spawns,i + 1) + " at " + (string)temp);
}



Now, let's analyze what this does for you:

From: James Dayton
1. Which wall (plane, edgeOfWorld) am I slated to hit first.

See above.

From: James Dayton
2. How far away is the intersection of my direction from my position pos?

Just multiply this script return by the size vector given at the top. Subtract out llGetPos().

From: James Dayton
3. What angle does it make with the plane? Turn towards the side that makes an obtuse angle.

My guess is you mean an acute angle, and this is easyish - try this.

Since the script above returns the intersection point, you can use it to determine two candidate directions to go. Say, for argument, <1,0,0> and <-1,0,0> in normalized form.

Just use something like llRot2Fwd (which is really just <1,0,0> * llGetRot()) to get the direction you're going.

Once you have that, you can just add your two candidate vectors and find which magnitude is greater.

As an addendum, you can view the cheap, beta autopilot script I wrote here. It banks corners surprisingly well, but due to a glitch in how llRotBetween is formatted, it suffers some minor bugs.

It'll probably see a major rewrite before/if I post it officially.
_____________________
---
Adam Zaius
Deus
Join date: 9 Jan 2004
Posts: 1,483
05-31-2005 21:52
I did something similar recently, intersection of a line and triangle based on some code in a 3D programming snippets book I have; this works well with complex surfaces as well (since you can just divide it into triangles, and test each)

I apologise in advance for not commenting this, I didnt actually anticipate anyone else touching it. This quick example searches for 4 nearby objects named 'vertex' and forms a quad between them.

Touching the object starts a sensor which hunts for the 'ray' coming from the avatar's eyes , but it should be fairly easy to work with. The function triIntersect, returns the result into the vector 'triPoint' if it returns a success (the function itself returns a status code on whether it managed to get a result or not)

ray = [vector,vector]
tri = [vector,vector,vector]

CODE
float dot(vector u, vector v) {
// return (u.x * v.x + u.y * v.y * v.z);
return (u.x * v.x + u.y * v.y + u.z * v.z);
}

vector triPoint;
integer triIntersect(list ray, list tri) {

vector u;
vector v;
vector n;

vector dir;
vector w0;
vector w;

float r;
float a;
float b;

u = llList2Vector(tri,1) - llList2Vector(tri,0);
v = llList2Vector(tri,2) - llList2Vector(tri,0);
n = u % v;

if(n == ZERO_VECTOR) {
return -1;
}

dir = llList2Vector(ray,1) - llList2Vector(ray,0);
w0 = llList2Vector(ray,0) - llList2Vector(tri,0);

a = -dot(n,w0);
b = dot(n,dir);

if(llFabs(b) < 0.00001) {
if(a == 0) {
return 2;
}
return 0;
}

r = a / b;

if(r < 0.0) return 0;

triPoint = llList2Vector(ray,0) + r * dir;

float uu;
float uv;
float vv;
float wu;
float wv;
float D;

uu = dot(u,u);
uv = dot(u,v);
vv = dot(v,v);
w = triPoint - llList2Vector(tri,0);
wu = dot(w,u);
wv = dot(w,v);
D = uv * uv - uu * vv;

float s;
float t;

s = (uv * wv - vv * wu) / D;
if(s < 0.0 || s > 1.0)
return 0;

t = (uv * wu - uu * wv) / D;
if(t < 0.0 || (s + t) > 1.0)
return 0;

return 1;
}

debug(list d) {
llSay(0,llDumpList2String(d,","));
}

list tri1;
list tri2;
list ray;

vector A;
vector B;
vector C;
vector D;
default {
state_entry() {
llSensor("vertex","",PASSIVE,15,PI);
}

sensor(integer i) {
A = llDetectedPos(0);
B = llDetectedPos(1);
C = llDetectedPos(2);
D = llDetectedPos(3);
state found;
}
}

state found {
state_entry() {

// vector A = <238,13,26>;
// vector B = <238,9,26>;
// vector C = <238,13,23>;
// vector D = <238,9,23>;

tri1 = [A,B,C];
tri2 = [B,C,D];

//
// list ray = [<0,0,1>,<0,1,1.5>];
// list tri = [<-100,100,10>,<100,-100,10>,<0,-400,10>];
// debug(["Ray"] + ray);
// debug(["Tri"] + tri);
// debug(["Result",triIntersect(ray,tri),"(-1) Impossible to determine, (0) Ray parallel or not through, (1) Found, (2) Ray lies within triangle"]);
// debug(["Point",triPoint]);
llSensorRepeat("",llGetOwner(),AGENT,96,PI,0.1);
}

touch(integer i) {
llSensorRemove();
llSensorRepeat("",llDetectedKey(0),AGENT,96,PI,0.1);
}

sensor(integer i) {
vector pos = <1000,0,0> * llDetectedRot(0);

list bb = llGetBoundingBox(llDetectedKey(0));
vector zoff = llList2Vector(bb,0);
vector zoff2 = llList2Vector(bb,1);
vector z = <0,0,(zoff2.z - zoff.z) / 2>;


ray = [llDetectedPos(0) + z,(pos) + llDetectedPos(0) + z];
if(triIntersect(ray,tri1) == 1) llSay(0,(string)triPoint);
if(triIntersect(ray,tri2) == 1) llSay(0,(string)triPoint);

}

}


-Adam
_____________________
Co-Founder / Lead Developer
GigasSecondServer
SuezanneC Baskerville
Forums Rock!
Join date: 22 Dec 2003
Posts: 14,229
Hi James, don't see you in the forums enough.
06-01-2005 04:08
I found this on google using the seach terms "line and plane intersect"
and "high school".

The following is taken rom Dr. Math:

From: someone
"Let us say the plane is defined by a point A in the plane and a normal
vector N, and the line is defined by point P on the line and vector V
(= Q - P) in the direction of the line. "

"... math ... "

"So the point of intersection is

(A-P)*N
X = P + ------- V
V*N"


I believe the asterisks in the result are dot product symbols rather than normal multiplication symbols.

LSL uses the asterisk for the dot product when it occurs between two vectors, and uses the percent symbol for the cross product when that is used between two vectors.
_____________________
-

So long to these forums, the vBulletin forums that used to be at forums.secondlife.com. I will miss them.

I can be found on the web by searching for "SuezanneC Baskerville", or go to

http://www.google.com/profiles/suezanne

-

http://lindenlab.tribe.net/ created on 11/19/03.

Members: Ben, Catherine, Colin, Cory, Dan, Doug, Jim, Philip, Phoenix, Richard,
Robin, and Ryan

-