# Geometrical calculations : points, lines, planes : intersections, distances, angles

#1

I am trying to collect the most usual functions for the geometrical calculations :
Intersection point, projection, distance, angle, …

I start by giving the formulas which I know already.
If you know other formulas do not hesitate to add them.

Let’s say that you have 4 points:
pA=[ax,ay,az]
pB=[bx,by,bz]
pC=[cx,cy,cz]
pD=[dx,dy,dz]
With these points you can define a vector, a line, a plane.

Vector:

vAB=pB-pA
vAC=pC-pA
vCD=pD-pC

Vector Normalization : length vector = 1.0

``````normalize vAB
``````

http://mathworld.wolfram.com/NormalizedVector.html

Cross Product :

``````cross vAB vAC
``````

http://mathworld.wolfram.com/CrossProduct.html

Dot Product :

``````dot vAB vAC
dot (normalize vAB) (normalize vAC)
``````

http://mathworld.wolfram.com/DotProduct.html

line:

A line can be defined :

• by 2 points
• or by 1 point and 1 vector

Middle Point M of AB:

``````fn middlePoint pA pB = ((pA+pB)/2.0)
``````

Point along AB : the point at 25% between A and B:

``````fn alongPoint pA pB prop = (pA+((pB-pA)*prop))
``````

plane:

A plane can be defined :

• by 3 points
• or by 1 point and 2 vectors
• or by 1 point and 1 vector (the normal vector)

Normal Vector : the vector perpendicular to the plane:

``````normalVector=normalize (cross vAB vAC)
``````

http://mathworld.wolfram.com/NormalVector.html

line and point:

Point-Line Projection : find the point on the line AB which is the projection of the point C:

``````fn pointLineProj pA pB pC = (
local vAB=pB-pA
local vAC=pC-pA
local d=dot (normalize vAB) (normalize vAC)
(pA+(vAB*(d*(length vAC/length vAB))))
)
``````

Point-Line Distance : the distance between the line AB and the point C:

``````fn pointLineDist2 pA pB pC = (
local vAB=pB-pA
local vAC=pC-pA
(length (cross vAB vAC))/(length vAB)
)
``````

or

``````d=distance pC (pointLineProj pA pB pC)
``````

http://mathworld.wolfram.com/Point-LineDistance3-Dimensional.html

Point-Line Inclusion : is this point on the line ?

``````fn isPointLine pA pB pC tol = (
local vAB=pB-pA
local vAC=pC-pA
local d=1.0-abs(dot (normalize vAB) (normalize vAC))
if d<=tol then true else false
)
``````

or Point-Line Distance <= tolerance distance

(to be continued)

Help with Maxscript to find where a line segment would intersect another if extended
#2

nice stuff

takes me back to highschool math days…

Help with Maxscript to find where a line segment would intersect another if extended
#3

line and line:

Line-Line Intersection : intersection of two lines AB and CD:

``````fn lineLineIntersect pA pB pC pD = (
local a=pB-pA
local b=pD-pC
local c=pC-pA
local cross1 = cross a b
local cross2 = cross c b
pA + ( a*( (dot cross2 cross1)/((length cross1)^2) ) )
)
``````

or by using vectors:

``````fn lineLineIntersect pA a pB b = (
local c=pB-pA
local cross1 = cross a b
local cross2 = cross c b
pA + ( a*( (dot cross2 cross1)/((length cross1)^2) ) )
)
``````

http://mathworld.wolfram.com/Line-LineIntersection.html

Line-Line Distance : distance between two skew lines

``````fn lineLineDist pA a pB b = (
local c=pB-pA
local crossAB=cross a b
abs (dot c crossAB) / (length crossAB)
)
``````

http://mathworld.wolfram.com/Line-LineDistance.html

Line-Line // Distance : distance between two parallel lines
use “Point-Line Distance” : pA-pB is the first line and pC is a point of the second line

Line-Line Angle : angle between two lines:

``````fn getVectorsAngle vAB vCD = (
acos (dot (normalize vAB) (normalize vCD))
)
``````

or

``````fn lineLineAngle pA pB pC pD = (
local vAB=pB-pA
local vCD=pD-pC
local angle=acos (dot (normalize vAB) (normalize vCD))
if angle<90.0 then angle else (180.0-angle)
)
``````

http://mathworld.wolfram.com/Line-LineAngle.html

#4

plane and point:

Point-Plane Projection : find the point on the plane ABC which is the projection of the point D

``````fn pointPlaneProj pA pB pC pD = (
local nABC=normalize (cross (pB-pA) (pC-pA))
pD+((dot (pA-pD) nABC)*nABC)
)
``````

Point-Plane Distance : find the distance between a plane and a point

``````fn pointPlaneDist pA pB pC pD = (
local nABC=normalize (cross (pB-pA) (pC-pA))
length ((dot (pA-pD) nABC)*nABC)
)
``````

http://mathworld.wolfram.com/Point-PlaneDistance.html

#5

plane and line:

Line-Plane Intersection : intersection between a line and a plane

``````fn planeLineIntersect planePoint planeNormal linePoint lineVector = (
local lineVector=normalize lineVector
local d1=dot (planePoint-linePoint) planeNormal
local d2=dot lineVector planeNormal
if abs(d2)<.0000000754 then ( if abs(d1)>.0000000754 then 0 else -1 )
else ( linePoint + ( (d1/d2)*lineVector ) )
)
``````

This script is based on an original script of Joshua Newman.
return 0 for parrallel (no intersections) results
and -1 for co-incident (infinate) results

http://mathworld.wolfram.com/Line-PlaneIntersection.html

Line-Plane Distance : distance between a plane and a line //
use “Point-Plane Distance” : where ‘point’ is a point of the line

Vector perpendicular to a line into a Plane : the perpendicular of AB into the plane ABC

``````vectorPerp=cross vectorAB (cross vectorAB vectorAC)
-- or
vectorPerp=cross (cross vectorAB vectorAC) vectorAB
``````

http://mathworld.wolfram.com/Perpendicular.html

#6

Thanks for the aknowelgement PP.

Still can’t get around using the tolerence then eh?

Great resource BTW, keep up the good work!

#7

This is great, thanks.

#8

This should be a sticky!

#9

Thanks guys

jman: The tolerance seems to work for me, but I use rather the function in cases where the line is not parallel to the plan. Can you give an example where the tolerance is an issue?

Well, the continuation:

#10

plane and plane:

Plane-Plane Intersection : find the line which is the intersection of 2 planes
p1 : a point of the plane 1
n1 : the normal of the plane 1

``````fn planePlaneIntersect p1 n1 p2 n2 = (
-- n1, n2 are normalized
local lineVector = cross n1 n2
local proj1=(dot n1 p1)*n1
local proj2=(dot n2 p2)*n2
local perp1=cross n1 (normalize lineVector)
local perp2=cross n2 (normalize lineVector)
local cr = cross (proj2-proj1) perp2
local intersectionPoint = proj1 + (perp1*( (dot cr lineVector) / ((length lineVector)^2)) )
ray intersectionPoint lineVector
)
``````

I think that it is not the easiest solution. If you know a better means…
http://mathworld.wolfram.com/Plane-PlaneIntersection.html

Plane perpendicular to a Plane and a Line : find the plane which is perpendicular to the plane n and to the line AB
It’s the plane ABC where C=A+n
http://mathworld.wolfram.com/ParallelPlanes.html

Plane-Plane Angle : find the angle between two planes n1 and n2 (normals)

``````fn getVectorsAngle n1 n2 = ( acos (dot (normalize n1) (normalize n2)) )
``````

#11

Yes, if the results are parrallel or co-incident the rounding error tells the function from telling which!

#12

Hey PP, just wondering if you’re done adding to this thread. I want to put together a word doc containing all these functions, but wanted to wait until you were fiinished.

#13

I’ve got a math question, and this seems like a good place to ask. I tried digging through Mathworld, but it’s way over my head.

I’d like to be able to find a point on an arc defined by the end point of an object rotated around it’s pivot, along a specific axis. For example, let’s say there’s a bone object with a end bone as it’s child. If I rotate the parent bone around it’s Y axis 10 degrees, the end bone is now at a new position. What’s the formula for finding that position?

#14

That should be a straight trig calculation where (skeleton code):

``````
r = \$bone01.length
theta = (rotation of your bone)
phi = 90 - theta
y = sin(theta) * r
x = cos(theta) * r
z = sin(theta) * r * cos(phi)

``````

I’m a little hazy on the Z phi stuff, so somebody correct me if i’m wrong!

#15

I think that the essential formulae are there but anyone can add some more. The possibilities are illimited.
Here is an example: this script discovers if a line intersects a sphere.
It returns true or false.

``````fn lineSphereIntersection sphereCenter sphereRadius linePoint lineVector = (
local nLineVector= normalize lineVector
local projPoint=linePoint+((dot (sphereCenter-linePoint) nLineVector)*nLineVector)
local dist=distance sphereCenter projPoint
if dist>sphereRadius then false else true
)
``````

I use the projection of a point on a plane which passes by the sphere center. If the distance between this point and the center is lower or equal to the sphere radius then the line intersects the sphere. It’s based on the function ‘Point-Plane Projection’ .

Another way of going farther is to write the same functions but on objects like triangular faces or segments. For example find the position of a line that intersects a mesh face (not a plane). The case is more restricted.

#16

Thanks Martin. That got me going in the right direction, along with this site: http://www.kirupa.com/developer/actionscript/trigonometry.htm

Here’s what I came up with to illustrate what I wanted to do:

``````global polylinePosArr = #()

fn drawCircle = (
gw.setColor #line green
gw.setTransform(Matrix3 1)
gw.Polyline polylinePosArr true
gw.enlargeUpdateRect #whole
)

fn drawObjectCirle obj radius step:36 axis:1 = (
polylinePosArr = #()
-- get the object's position
local p = obj.pos
for i = 0 to (360 - step) by step do (
-- make a point helper
-- define the current angle around the circle
local angle = i
-- calculate the X and Y coordinates of the point on the circle using the current angle
local x = cos(angle) * radius
local y = sin(angle) * radius
-- 1 = X axis
-- 2 = Y axis
-- 3 = Z axis
global p3 = case axis of (
1:[0,x,y]
2:[x,0,y]
3:[x,y,0]
)
-- using the coordinate system of the object, define the coordinates of the current point
newP = ( (matrix3 [1,0,0] [0,1,0] [0,0,1] p3) * (obj.transform) ).translationPart
append polylinePosArr newP
)
)

-- create a box
b = box length:1 width:1 height:10 pos:(random [-10,-10,-10] [10,10,10])
b.rotation = quat (random -1 1) (random -1 1) (random -1 1) 1
-- get the length of the box, which will be used as the radius for the circle calculations
l = b.height

-- be careful with the "steps" parameter, too low (around 10) and Max will crash
drawObjectCirle b l step:18 axis:2

-- draw the circle
registerRedrawViewsCallback drawCircle
redrawViews()

/* stop drawing the circle
unregisterRedrawViewsCallback drawCircle
*/
``````

#17

The quaternion is easy to use to rotate a position in 3D space. You know:
1- the axis of rotation (it must be normalized)
2- the center of the rotation
3- the angle
4- the position of the point to be moved

``````rotAxis = [0,0,2]
rotCenter = [0,2,0]
rotAngle = 90
thePoint = [1,2,3]

q = quat rotAngle (normalize rotAxis)
pointAfterRotation = (((thePoint - rotCenter ) * q) + rotCenter)
--> [0,1,3]
``````

The direction of the rotation can be modified by changing the direction of the axis.
if you use rotAxis = -[0,0,2], the rotation will be reversed.

Here is a variation of your function:

`````` fn drawObjectCirle obj radius step:36 axis:1 = (
polylinePosArr = #()
local rotCenter = obj.pos
local rotAxis = obj.dir
local p
case axis of (
)
q = quat step rotAxis
for i = 0 to (360 - step) by step do (
p = ((p-rotCenter)*q) + rotCenter
append polylinePosArr p
)
)
``````

#18

hi all

i am trying to make a sort of “one axis lookat” scriptcontroller.
object_a is flying around in 3d space and object_b is located at position [0,0,0]
object_b has a script_contoller at the z-rotation so that it looks at object_a.

## this is what i have so far as scriptcontroller for object_b z-rotation:

``````
dependson \$object_a
v1t = at time currenttime \$object_a.position
a = normalize [v1t.x,v1t.y,0]-- set z to 0 because it is not needed
upv = [0,1,0] --defining a 2d "up vector"

cosine = a.x * upv.x + a.y * upv.y
if cosine > 1 then cosine1 = 1
if cosine < -1 then cosine1 = -1
if (a.x * upv.y - a.y * upv.x) < 0 then
(
result = -cosine
)
else
(
result = cosine
)
result

``````

it does not work
any ideas???

thanks

#19

this seems to work:

``````
dependson \$object_a
v1t = at time currenttime \$object_a.position
a = normalize [v1t.x,v1t.y,0]
ndir = normalize a

upvector = [0,0,1]
rightvector = normalize (cross upvector ndir )
thematrix = matrix3 ndir rightvector upvector ndir

pitch = ((thematrix.rotation as eulerangles).z +180)*pi/180

``````

But is there a way not to use the matrix3 calculations?
any ideas???

#20

that is great topic . espacially the math website , thanks .