Find the intersection of a line with a plane: Difference between revisions

m
→‎{{header|Wren}}: Added libheader.
(→‎{{header|J}}: simplify)
m (→‎{{header|Wren}}: Added libheader.)
 
(68 intermediate revisions by 28 users not shown)
Line 1:
[[Category:Geometry]]
[[Category:Collision detection]]
{{task}}
{{task}}Finding the intersection of an infinite ray with a plane in 3D is an important topic in collision detection.
Finding the intersection of an infinite ray with a plane in 3D is an important topic in collision detection.
 
 
;Task:
Find the point of intersection for the infinite ray with direction   (0, -1, -1)   passing through position   (0, 0, 10)   with the infinite plane with a normal vector of   (0, 0, 1)   and which passes through [0, 0, 5].
<br><br>
 
=={{header|11l}}==
Find the point of intersection for the infinite ray with direction (0,-1,-1) passing through position (0, 0, 10) with the infinite plane with a normal vector of (0, 0, 1) and which passes through [0, 0, 5].
 
<syntaxhighlight lang="11l">F intersection_point(ray_direction, ray_point, plane_normal, plane_point)
R ray_point - ray_direction * dot(ray_point - plane_point, plane_normal) / dot(ray_direction, plane_normal)
 
print(‘The ray intersects the plane at ’intersection_point((0.0, -1.0, -1.0), (0.0, 0.0, 10.0), (0.0, 0.0, 1.0), (0.0, 0.0, 5.0)))</syntaxhighlight>
 
{{out}}
<pre>
The ray intersects the plane at (0, -5, 5)
</pre>
 
=={{header|Action!}}==
{{libheader|Action! Tool Kit}}
<syntaxhighlight lang="action!">INCLUDE "D2:REAL.ACT" ;from the Action! Tool Kit
 
DEFINE REALPTR="CARD"
TYPE VectorR=[REALPTR x,y,z]
 
PROC PrintVector(VectorR POINTER v)
Print("(") PrintR(v.x)
Print(",") PrintR(v.y)
Print(",") PrintR(v.z)
Print(")")
RETURN
 
PROC Vector(REAL POINTER vx,vy,vz VectorR POINTER v)
v.x=vx v.y=vy v.z=vz
RETURN
 
PROC VectorSub(VectorR POINTER a,b,res)
RealSub(a.x,b.x,res.x)
RealSub(a.y,b.y,res.y)
RealSub(a.z,b.z,res.z)
RETURN
 
PROC VectorDot(VectorR POINTER a,b REAL POINTER res)
REAL tmp1,tmp2
 
RealMult(a.x,b.x,res)
RealMult(a.y,b.y,tmp1)
RealAdd(res,tmp1,tmp2)
RealMult(a.z,b.z,tmp1)
RealAdd(tmp1,tmp2,res)
RETURN
 
PROC VectorMul(VectorR POINTER a REAL POINTER b VectorR POINTER res)
RealMult(a.x,b,res.x)
RealMult(a.y,b,res.y)
RealMult(a.z,b,res.z)
RETURN
 
BYTE FUNC IsZero(REAL POINTER a)
CHAR ARRAY s(10)
 
StrR(a,s)
IF s(0)=1 AND s(1)='0 THEN
RETURN (1)
FI
RETURN (0)
 
BYTE FUNC Intersection(VectorR POINTER
rayVector,rayPoint,planeNormal,planePoint,result)
REAL tmpx,tmpy,tmpz,prod1,prod2,prod3
VectorR tmp
 
Vector(tmpx,tmpy,tmpz,tmp)
 
VectorSub(rayPoint,planePoint,tmp)
VectorDot(tmp,planeNormal,prod1)
VectorDot(rayVector,planeNormal,prod2)
 
IF IsZero(prod2) THEN
RETURN (1)
FI
 
RealDiv(prod1,prod2,prod3)
VectorMul(rayVector,prod3,tmp)
VectorSub(rayPoint,tmp,result)
RETURN (0)
 
PROC Test(VectorR POINTER rayVector,rayPoint,planeNormal,planePoint)
BYTE res
REAL px,py,pz
VectorR p
 
Vector(px,py,pz,p)
res=Intersection(rayVector,rayPoint,planeNormal,planePoint,p)
 
Print("Ray vector: ")
PrintVector(rayVector) PutE()
Print("Ray point: ")
PrintVector(rayPoint) PutE()
Print("Plane normal: ")
PrintVector(planeNormal) PutE()
Print("Plane point: ")
PrintVector(planePoint) PutE()
 
IF res=0 THEN
Print("Intersection point: ")
PrintVector(p) PutE()
ELSEIF res=1 THEN
PrintE("There is no intersection")
FI
PutE()
RETURN
 
PROC Main()
REAL r0,r1,r5,r10,rm1
VectorR rayVector,rayPoint,planeNormal,planePoint
 
Put(125) PutE() ;clear screen
 
ValR("0",r0) ValR("1",r1) ValR("5",r5)
ValR("10",r10) ValR("-1",rm1)
 
Vector(r0,rm1,rm1,rayVector)
Vector(r0,r0,r10,rayPoint)
Vector(r0,r0,r1,planeNormal)
Vector(r0,r0,r5,planePoint)
Test(rayVector,rayPoint,planeNormal,planePoint)
 
Vector(r1,r1,r0,rayVector)
Vector(r1,r1,r0,rayPoint)
Vector(r0,r0,r1,planeNormal)
Vector(r5,r1,r0,planePoint)
Test(rayVector,rayPoint,planeNormal,planePoint)
RETURN</syntaxhighlight>
{{out}}
[https://gitlab.com/amarok8bit/action-rosetta-code/-/raw/master/images/Find_the_intersection_of_a_line_with_a_plane.png Screenshot from Atari 8-bit computer]
<pre>
Ray vector: (0,-1,-1)
Ray point: (0,0,10)
Plane normal: (0,0,1)
Plane point: (0,0,5)
Intersection point: (0,-5,5)
 
Ray vector: (1,1,0)
Ray point: (1,1,0)
Plane normal: (0,0,1)
Plane point: (5,1,0)
There is no intersection
</pre>
 
=={{header|Ada}}==
<syntaxhighlight lang="ada">with Ada.Numerics.Generic_Real_Arrays;
with Ada.Text_IO;
 
procedure Intersection is
 
type Real is new Long_Float;
 
package Real_Arrays is
new Ada.Numerics.Generic_Real_Arrays (Real => Real);
use Real_Arrays;
 
package Real_IO is
new Ada.Text_IO.Float_IO (Num => Real);
 
subtype Vector_3D is Real_Vector (1 .. 3);
 
function Line_Plane_Intersection (Line_Vector : in Vector_3D;
Line_Point : in Vector_3D;
Plane_Normal : in Vector_3D;
Plane_Point : in Vector_3D)
return Vector_3D
is
Diff : constant Vector_3D := Line_Point - Plane_Point;
Denom : constant Real := Line_Vector * Plane_Normal;
begin
if Denom = 0.0 then
raise Constraint_Error with "Line does not intersect plane";
end if;
declare
Scale : constant Real :=
-Real'(Diff * Plane_Normal) / Denom;
Point : constant Vector_3D :=
Diff + Plane_Point + Scale * Line_Vector;
begin
return Point;
end;
end Line_Plane_Intersection;
 
procedure Put (V : in Vector_3D) is
use Ada.Text_IO, Real_IO;
begin
Put ("(");
Put (V (1)); Put (",");
Put (V (2)); Put (",");
Put (V (3)); Put (")");
end Put;
 
begin
Real_IO.Default_Exp := 0;
Real_IO.Default_Aft := 3;
 
Put (Line_Plane_Intersection (Line_Vector => (0.0, -1.0, -1.0),
Line_Point => (0.0, 0.0, 10.0),
Plane_Normal => (0.0, 0.0, 1.0),
Plane_Point => (0.0, 0.0, 5.0)));
end Intersection;</syntaxhighlight>
{{out}}
<pre>( 0.000,-5.000, 5.000)</pre>
 
=={{header|APL}}==
<syntaxhighlight lang="apl">⍝ Find the intersection of a line with a plane
⍝ The intersection I belongs to a line defined by point L and vector V, translates to:
⍝ A real parameter t exists, that satisfies I = L + tV
⍝ I belongs to the plan defined by point P and normal vector N. This means that any two points of the plane make a vector
⍝ normal to vector N. As I and P belong to the plane, the vector IP is normal to N.
⍝ This translates to: The scalar product IP.N = 0.
⍝ (P - I).N = 0 <=> (P - L - tV).N = 0
⍝ Using distributivity, then associativity, the following equations are established:
⍝ (P - L - tV).N = (P - L).N - (tV).N = (P - L).N - t(V.N) = 0
⍝ Which allows to resolve t: t = ((P - L).N) ÷ (V.N)
⍝ In APL, A.B is coded +/A x B
V ← 0 ¯1 ¯1
L ← 0 0 10
N ← 0 0 1
P ← 0 0 5
dot ← { +/ ⍺ × ⍵ }
t ← ((P - L) dot N) ÷ V dot N
I ← L + t × V
</syntaxhighlight>
{{out}}
<pre>
I
0 ¯5 5
</pre>
 
=={{header|Arturo}}==
{{trans|Nim}}
<syntaxhighlight lang="rebol">define :vector [x, y, z][]
 
addv: function [v1 :vector, v2 :vector]->
to :vector @[v1\x+v2\x, v1\y+v2\y, v1\z+v2\z]
 
subv: function [v1 :vector, v2 :vector]->
to :vector @[v1\x-v2\x, v1\y-v2\y, v1\z-v2\z]
 
mulv: function [v1 :vector, v2 :vector :floating][
if? is? :vector v2
-> return sum @[v1\x*v2\x v1\y*v2\y v1\z*v2\z]
else
-> return to :vector @[v1\x*v2, v1\y*v2, v1\z*v2]
]
 
intersect: function [lV, lP, pV, pP][
tdenom: mulv pV lV
if zero? tdenom -> return to :vector @[∞, ∞, ∞]
t: (mulv pV subv pP lP) / tdenom
return addv mulv lV t lP
]
 
coords: intersect to :vector @[0.0, neg 1.0, neg 1.0]
to :vector @[0.0, 0.0, 10.0]
to :vector @[0.0, 0.0, 1.0]
to :vector @[0.0, 0.0, 5.0]
 
print ["Intersection at:" coords]</syntaxhighlight>
 
{{out}}
 
<pre>Intersection at: [x:0.0 y:-5.0 z:5.0]</pre>
 
=={{header|AutoHotkey}}==
<syntaxhighlight lang="autohotkey">/*
; https://en.wikipedia.org/wiki/Line%E2%80%93plane_intersection#Algebraic_form
l = line vector
lo = point on the line
n = plane normal vector
Po = point on the plane
 
if (l . n) = 0 ; line and plane are parallel.
if (Po - lo) . n = 0 ; line is contained in the plane.
 
(P - Po) . n = 0 ; vector equation of plane.
P = lo + l * d ; vector equation of line.
((lo + l * d) - Po) . n = 0 ; Substitute line into plane equation.
(l . n) * d + (lo - Po) . n = 0 ; Expanding.
d = ((Po - lo) . n) / (l . n) ; solving for d.
P = lo + l * ((Po - lo) . n) / (l . n) ; solving P.
*/
 
intersectPoint(l, lo, n, Pn ){
if (Vector_dot(Vector_sub(Pn, lo), n) = 0) ; line is contained in the plane
return [1]
if (Vector_dot(l, n) = 0) ; line and plane are parallel
return [0]
diff := Vector_Sub(Pn, lo) ; (Po - lo)
prod1 := Vector_Dot(diff, n) ; ((Po - lo) . n)
prod2 := Vector_Dot(l, n) ; (l . n)
d := prod1 / prod2 ; d = ((Po - lo) . n) / (l . n)
return Vector_Add(lo, Vector_Mul(l, d)) ; P = lo + l * d
}
 
Vector_Add(v, w){
return [v.1+w.1, v.2+w.2, v.3+w.3]
}
Vector_Sub(v, w){
return [v.1-w.1, v.2-w.2, v.3-w.3]
}
Vector_Mul(v, s){
return [s*v.1, s*v.2, s*v.3]
}
Vector_Dot(v, w){
return v.1*w.1 + v.2*w.2 + v.3*w.3
}</syntaxhighlight>
Examples:<syntaxhighlight lang="autohotkey">; task
l1 := [0, -1, -1]
lo1 := [0, 0, 10]
n1 := [0, 0, 1]
Po1 := [0, 0, 5]
 
; line on plane
l2 := [1, 1, 0]
lo2 := [1, 1, 0]
n2 := [0, 0, 1]
Po2 := [5, 1, 0]
 
; line parallel to plane
l3 := [1, 1, 0]
lo3 := [1, 1, 1]
n3 := [0, 0, 1]
Po3 := [5, 1, 0]
 
output := ""
loop 3
{
result := ""
ip := intersectPoint(l%A_Index%, lo%A_Index%, n%A_Index%, Po%A_Index%)
for i, v in ip
result .= v ", "
output .= Trim(result, ", ") "`n"
}
MsgBox % output
return</syntaxhighlight>
{{out}}
<pre>0.000000, -5.000000, 5.000000
1 ; line on plane
0 ; line parallel to plane
</pre>
 
=={{header|C}}==
Straightforward application of the intersection formula, prints usage on incorrect invocation.
<syntaxhighlight lang="c">
<lang C>
/*Abhishek Ghosh, 12th October 2017*/
 
#include<stdio.h>
 
Line 64 ⟶ 408:
return 0;
}
</syntaxhighlight>
</lang>
Invocation and output:
<pre>
Line 70 ⟶ 414:
Intersection point is (0.000000,-5.000000,5.000000)
</pre>
 
=={{header|C sharp|C#}}==
<syntaxhighlight lang="csharp">using System;
 
namespace FindIntersection {
class Vector3D {
private double x, y, z;
 
public Vector3D(double x, double y, double z) {
this.x = x;
this.y = y;
this.z = z;
}
 
public static Vector3D operator +(Vector3D lhs, Vector3D rhs) {
return new Vector3D(lhs.x + rhs.x, lhs.y + rhs.y, lhs.z + rhs.z);
}
 
public static Vector3D operator -(Vector3D lhs, Vector3D rhs) {
return new Vector3D(lhs.x - rhs.x, lhs.y - rhs.y, lhs.z - rhs.z);
}
 
public static Vector3D operator *(Vector3D lhs, double rhs) {
return new Vector3D(lhs.x * rhs, lhs.y * rhs, lhs.z * rhs);
}
 
public double Dot(Vector3D rhs) {
return x * rhs.x + y * rhs.y + z * rhs.z;
}
 
public override string ToString() {
return string.Format("({0:F}, {1:F}, {2:F})", x, y, z);
}
}
 
class Program {
static Vector3D IntersectPoint(Vector3D rayVector, Vector3D rayPoint, Vector3D planeNormal, Vector3D planePoint) {
var diff = rayPoint - planePoint;
var prod1 = diff.Dot(planeNormal);
var prod2 = rayVector.Dot(planeNormal);
var prod3 = prod1 / prod2;
return rayPoint - rayVector * prod3;
}
 
static void Main(string[] args) {
var rv = new Vector3D(0.0, -1.0, -1.0);
var rp = new Vector3D(0.0, 0.0, 10.0);
var pn = new Vector3D(0.0, 0.0, 1.0);
var pp = new Vector3D(0.0, 0.0, 5.0);
var ip = IntersectPoint(rv, rp, pn, pp);
Console.WriteLine("The ray intersects the plane at {0}", ip);
}
}
}</syntaxhighlight>
{{out}}
<pre>The ray intersects the plane at (0.00, -5.00, 5.00)</pre>
 
=={{header|C++}}==
{{trans|Java}}
<syntaxhighlight lang="cpp">#include <iostream>
#include <sstream>
 
class Vector3D {
public:
Vector3D(double x, double y, double z) {
this->x = x;
this->y = y;
this->z = z;
}
 
double dot(const Vector3D& rhs) const {
return x * rhs.x + y * rhs.y + z * rhs.z;
}
 
Vector3D operator-(const Vector3D& rhs) const {
return Vector3D(x - rhs.x, y - rhs.y, z - rhs.z);
}
 
Vector3D operator*(double rhs) const {
return Vector3D(rhs*x, rhs*y, rhs*z);
}
 
friend std::ostream& operator<<(std::ostream&, const Vector3D&);
 
private:
double x, y, z;
};
 
std::ostream & operator<<(std::ostream & os, const Vector3D &f) {
std::stringstream ss;
ss << "(" << f.x << ", " << f.y << ", " << f.z << ")";
return os << ss.str();
}
 
Vector3D intersectPoint(Vector3D rayVector, Vector3D rayPoint, Vector3D planeNormal, Vector3D planePoint) {
Vector3D diff = rayPoint - planePoint;
double prod1 = diff.dot(planeNormal);
double prod2 = rayVector.dot(planeNormal);
double prod3 = prod1 / prod2;
return rayPoint - rayVector * prod3;
}
 
int main() {
Vector3D rv = Vector3D(0.0, -1.0, -1.0);
Vector3D rp = Vector3D(0.0, 0.0, 10.0);
Vector3D pn = Vector3D(0.0, 0.0, 1.0);
Vector3D pp = Vector3D(0.0, 0.0, 5.0);
Vector3D ip = intersectPoint(rv, rp, pn, pp);
 
std::cout << "The ray intersects the plane at " << ip << std::endl;
 
return 0;
}</syntaxhighlight>
{{out}}
<pre>The ray intersects the plane at (0, -5, 5)</pre>
 
=={{header|D}}==
{{trans|Kotlin}}
<langsyntaxhighlight Dlang="d">import std.stdio;
 
struct Vector3D {
Line 128 ⟶ 587:
auto ip = intersectPoint(rv, rp, pn, pp);
writeln("The ray intersects the plane at ", ip);
}</langsyntaxhighlight>
 
{{out}}
<pre>The ray intersects the plane at (0.000000,-5.000000,5.000000)</pre>
 
=={{header|EasyLang}}==
{{trans|Lua}}
<syntaxhighlight lang=easylang>
proc minus . l[] r[] res[] .
len res[] 3
for i to 3
res[i] = l[i] - r[i]
.
.
func dot l[] r[] .
for i to 3
res += l[i] * r[i]
.
return res
.
proc scale f . l[] .
for i to 3
l[i] = l[i] * f
.
.
proc inter_point rv[] rp[] pn[] pp[] . res[] .
minus rp[] pp[] dif[]
prd1 = dot dif[] pn[]
prd2 = dot rv[] pn[]
scale (prd1 / prd2) rv[]
minus rp[] rv[] res[]
.
rv[] = [ 0.0 -1.0 -1.0 ]
rp[] = [ 0.0 0.0 10.0 ]
pn[] = [ 0.0 0.0 1.0 ]
pp[] = [ 0.0 0.0 5.0 ]
inter_point rv[] rp[] pn[] pp[] res[]
print res[]
</syntaxhighlight>
 
=={{header|Evaldraw}}==
{{trans|C}}
 
Makes use of the intersectionPoint function to intersect 9 lines with 1 moving plane in a realtime demo.
[[File:Evaldraw line vs plane.png|thumb|alt=Grid of 3x3 3d points intersecting a 3D plane|Shows 3x3 grid of lines intersecting a plane. Gridlines drawn between intersection points. Intersection "time" value projected from 3d intersection point to 2d screen rendering.]]
<syntaxhighlight lang="c">
struct vec{x,y,z;};
enum{GRIDRES=3} // Keep a NxN grid of intersection results.
static vec intersections[GRIDRES][GRIDRES];
static vec ipos = {0,5,-15};
static vec ileft = {-1,0,0};
static vec iup = {0,-1,0};
static vec ifor = {0,0,1};
()
{
cls(0); clz(1e32);
setcam( ipos.x, ipos.y, ipos.z,
ileft.x, ileft.y, ileft.z, // flip right basis to left
iup.x, iup.y, iup.z, // flip down basis to up
ifor.x, ifor.y, ifor.z);
t=klock(0);
vec planePoint = {0,5,0}; // Plane Position
vec pN = {cos(t),1,sin(t)}; // PlaneNormal, un-normalized
normalize(pN);
 
for(x=0; x<GRIDRES; x++)
for(z=0; z<GRIDRES; z++)
{
scale = 4.5; halfgrid = scale*(GRIDRES-1)/2;
vec lineVector = {0,1,0}; // Direction of line
vec linePoint ={-halfgrid+scale*x, 5, -halfgrid+scale*z};
if (vecdot( lineVector, pN ) == 0 )
{
moveto(0,0); printf("Line and Plane dont intersect.");
} else {
vec isect;
isect_time = intersectionPoint(lineVector, linePoint, pN, planePoint, isect);
intersections[x][z] = isect; // Store for drawing grid
//setcol(255,255,0); drawsph(isect.x, isect.y, isect.z, .1);
setcol(255,0,0); line(linePoint, isect);
unproject(isect);
setfont(8,12); setcol(255,255,255); printf("t=%2.1f", isect_time);
}
}
// drawgridPlane
setcol(255,0,255);
for(i=0; i<GRIDRES; i++)
for(j=0; j<GRIDRES; j++) {
vec p00 = intersections[i][j];
vec p10 = intersections[(i+1)%GRIDRES][j];
vec p01 = intersections[i][(j+1)%GRIDRES]; // oob wraps to 0 anyhow
line(p00,p10);
line(p00,p01);
}
setcol(192,192,192); moveto(0,0); printf("Line vs Plane intersection");
}
intersectionPoint(vec lineVector, vec linePoint, vec planeNormal, vec planePoint, vec isect){
vec diff; vecsub(diff,linePoint,planePoint);
vec pd; vecadd(pd, diff,planePoint);
t = -vecdot(diff,planeNormal) / vecdot(lineVector,planeNormal);
vec scaledVec; vecscalar(scaledVec, lineVector, t);
vecadd(isect, pd, scaledVec);
return t;
}
line(vec a, vec b) { moveto(a.x,a.y,a.z); lineto(b.x,b.y,b.z); }
// -------------------------------------- VECTOR MATH
vecScalar( vec out, vec a, s ) {
out.x = a.x * s;
out.y = a.y * s;
out.z = a.z * s;
}
vecAdd( vec out, vec a, vec b) {
out.x = a.x + b.x;
out.y = a.y + b.y;
out.z = a.z + b.z;
}
vecAdd( vec out, vec b) {
out.x += b.x;
out.y += b.y;
out.z += b.z;
}
vecSub( vec out, vec a, vec b) {
out.x = a.x - b.x;
out.y = a.y - b.y;
out.z = a.z - b.z;
}
vecCross( vec out, vec a, vec b) {
out.x = a.y*b.z - a.z*b.y;
out.y = a.z*b.x - a.x*b.z;
out.z = a.x*b.y - a.y*b.x;
}
vecDot( vec a, vec b) {
return a.x*b.x + a.y*b.y + a.z*b.z;
}
length( vec v ) {
return sqrt( vecdot(v,v) );
}
normalize( vec v ) {
len = length(v);
if ( len ) { v.x /= len; v.y /= len; v.z /= len; }
}
unproject(vec pt) { // unproject a 3D screenpoint
vec from_eye; vecsub(from_eye, pt, ipos);
nx = vecdot(from_eye, ileft);
ny = vecdot(from_eye, iup);
nz = vecdot(from_eye, ifor);
if (nz <= 0.5) return; // behind eye
f = xres/2/nz; // 90 degree projection
moveto(nx*f + xres/2, ny*f + yres/2 );
}</syntaxhighlight>
 
=={{header|F Sharp|F#}}==
{{trans|C#}}
<syntaxhighlight lang="fsharp">open System
 
type Vector(x : double, y : double, z : double) =
member this.x = x
member this.y = y
member this.z = z
static member (-) (lhs : Vector, rhs : Vector) =
Vector(lhs.x - rhs.x, lhs.y - rhs.y, lhs.z - rhs.z)
static member (*) (lhs : Vector, rhs : double) =
Vector(lhs.x * rhs, lhs.y * rhs, lhs.z * rhs)
override this.ToString() =
String.Format("({0:F}, {1:F}, {2:F})", x, y, z)
 
let Dot (lhs:Vector) (rhs:Vector) =
lhs.x * rhs.x + lhs.y * rhs.y + lhs.z * rhs.z
 
let IntersectPoint rayVector rayPoint planeNormal planePoint =
let diff = rayPoint - planePoint
let prod1 = Dot diff planeNormal
let prod2 = Dot rayVector planeNormal
let prod3 = prod1 / prod2
rayPoint - rayVector * prod3
 
[<EntryPoint>]
let main _ =
let rv = Vector(0.0, -1.0, -1.0)
let rp = Vector(0.0, 0.0, 10.0)
let pn = Vector(0.0, 0.0, 1.0)
let pp = Vector(0.0, 0.0, 5.0)
let ip = IntersectPoint rv rp pn pp
Console.WriteLine("The ray intersects the plane at {0}", ip)
 
0 // return an integer exit code</syntaxhighlight>
{{out}}
<pre>The ray intersects the plane at (0.00, -5.00, 5.00)</pre>
 
=={{header|Factor}}==
{{trans|11l}}
<syntaxhighlight lang="factor">USING: io locals math.vectors prettyprint ;
 
:: intersection-point ( rdir rpt pnorm ppt -- loc )
rpt rdir pnorm rpt ppt v- v. v*n rdir pnorm v. v/n v- ;
 
"The ray intersects the plane at " write
{ 0 -1 -1 } { 0 0 10 } { 0 0 1 } { 0 0 5 } intersection-point .</syntaxhighlight>
{{out}}
<pre>
The ray intersects the plane at { 0 -5 5 }
</pre>
 
=={{header|FreeBASIC}}==
<syntaxhighlight lang="freebasic">' version 11-07-2018
' compile with: fbc -s console
 
Type vector3d
Dim As Double x, y ,z
Declare Constructor ()
Declare Constructor (ByVal x As Double, ByVal y As Double, ByVal z As Double)
End Type
 
Constructor vector3d()
This.x = 0
This.y = 0
This.z = 0
End Constructor
 
Constructor vector3d(ByVal x As Double, ByVal y As Double, ByVal z As Double)
This.x = x
This.y = y
This.z = z
End Constructor
 
Operator + (lhs As vector3d, rhs As vector3d) As vector3d
Return Type(lhs.x + rhs.x, lhs.y + rhs.y, lhs.z + rhs.z)
End Operator
 
Operator - (lhs As vector3d, rhs As vector3d) As vector3d
Return Type(lhs.x - rhs.x, lhs.y - rhs.y, lhs.z - rhs.z)
End Operator
 
Operator * (lhs As vector3d, d As Double) As vector3d
Return Type(lhs.x * d, lhs.y * d, lhs.z * d)
End Operator
 
Function dot(lhs As vector3d, rhs As vector3d) As Double
Return lhs.x * rhs.x + lhs.y * rhs.y + lhs.z * rhs.z
End Function
 
Function tostring(vec As vector3d) As String
Return "(" + Str(vec.x) + ", " + Str(vec.y) + ", " + Str(vec.z) + ")"
End Function
 
Function intersectpoint(rayvector As vector3d, raypoint As vector3d, _
planenormal As vector3d, planepoint As vector3d) As vector3d
 
Dim As vector3d diff = raypoint - planepoint
Dim As Double prod1 = dot(diff, planenormal)
Dim As double prod2 = dot(rayvector, planenormal)
Return raypoint - rayvector * (prod1 / prod2)
 
End Function
 
' ------=< MAIN >=------
 
Dim As vector3d rv = Type(0, -1, -1)
Dim As vector3d rp = Type(0, 0, 10)
Dim As vector3d pn = Type(0, 0, 1)
Dim As vector3d pp = Type(0, 0, 5)
Dim As vector3d ip = intersectpoint(rv, rp, pn, pp)
 
print
Print "line intersects the plane at "; tostring(ip)
 
' empty keyboard buffer
While InKey <> "" : Wend
Print : Print "hit any key to end program"
Sleep
End</syntaxhighlight>
{{out}}
<pre>line intersects the plane at (0, -5, 5)</pre>
 
=={{header|Go}}==
{{trans|Kotlin}}
<syntaxhighlight lang="go">package main
 
import "fmt"
 
type Vector3D struct{ x, y, z float64 }
 
func (v *Vector3D) Add(w *Vector3D) *Vector3D {
return &Vector3D{v.x + w.x, v.y + w.y, v.z + w.z}
}
 
func (v *Vector3D) Sub(w *Vector3D) *Vector3D {
return &Vector3D{v.x - w.x, v.y - w.y, v.z - w.z}
}
 
func (v *Vector3D) Mul(s float64) *Vector3D {
return &Vector3D{s * v.x, s * v.y, s * v.z}
}
 
func (v *Vector3D) Dot(w *Vector3D) float64 {
return v.x*w.x + v.y*w.y + v.z*w.z
}
 
func (v *Vector3D) String() string {
return fmt.Sprintf("(%v, %v, %v)", v.x, v.y, v.z)
}
 
func intersectPoint(rayVector, rayPoint, planeNormal, planePoint *Vector3D) *Vector3D {
diff := rayPoint.Sub(planePoint)
prod1 := diff.Dot(planeNormal)
prod2 := rayVector.Dot(planeNormal)
prod3 := prod1 / prod2
return rayPoint.Sub(rayVector.Mul(prod3))
}
 
func main() {
rv := &Vector3D{0.0, -1.0, -1.0}
rp := &Vector3D{0.0, 0.0, 10.0}
pn := &Vector3D{0.0, 0.0, 1.0}
pp := &Vector3D{0.0, 0.0, 5.0}
ip := intersectPoint(rv, rp, pn, pp)
fmt.Println("The ray intersects the plane at", ip)
}</syntaxhighlight>
 
{{out}}
<pre>
The ray intersects the plane at (0, -5, 5)
</pre>
 
=={{header|Groovy}}==
{{trans|Java}}
<syntaxhighlight lang="groovy">class LinePlaneIntersection {
private static class Vector3D {
private double x, y, z
 
Vector3D(double x, double y, double z) {
this.x = x
this.y = y
this.z = z
}
 
Vector3D plus(Vector3D v) {
return new Vector3D(x + v.x, y + v.y, z + v.z)
}
 
Vector3D minus(Vector3D v) {
return new Vector3D(x - v.x, y - v.y, z - v.z)
}
 
Vector3D multiply(double s) {
return new Vector3D(s * x, s * y, s * z)
}
 
double dot(Vector3D v) {
return x * v.x + y * v.y + z * v.z
}
 
@Override
String toString() {
return "($x, $y, $z)"
}
}
 
private static Vector3D intersectPoint(Vector3D rayVector, Vector3D rayPoint, Vector3D planeNormal, Vector3D planePoint) {
Vector3D diff = rayPoint - planePoint
double prod1 = diff.dot(planeNormal)
double prod2 = rayVector.dot(planeNormal)
double prod3 = prod1 / prod2
return rayPoint - rayVector * prod3
}
 
static void main(String[] args) {
Vector3D rv = new Vector3D(0.0, -1.0, -1.0)
Vector3D rp = new Vector3D(0.0, 0.0, 10.0)
Vector3D pn = new Vector3D(0.0, 0.0, 1.0)
Vector3D pp = new Vector3D(0.0, 0.0, 5.0)
Vector3D ip = intersectPoint(rv, rp, pn, pp)
println("The ray intersects the plane at $ip")
}
}</syntaxhighlight>
{{out}}
<pre>The ray intersects the plane at (0.0, -5.0, 5.0)</pre>
 
=={{header|Haskell}}==
{{trans|Kotlin}}
Note that V3 is implemented similarly in the external library [https://hackage.haskell.org/package/linear-1.20.7/docs/Linear-V3.html linear].
<langsyntaxhighlight Haskelllang="haskell">import Control.Applicative (liftA2)
import Text.Printf (printf)
 
Line 178 ⟶ 1,014:
rp = V3 0 0 10
pn = V3 0 0 1
pp = V3 0 0 5</langsyntaxhighlight>
{{out}}
<pre>The ray intersects the plane at (0.0, -5.0, 5.0)</pre>
 
 
=={{header|J}}==
'''Solution:'''
<langsyntaxhighlight lang="j">mp=: +/ .* NB. matrix product
p=: mp&{: %~ -~&{. mp {:@] NB. solve
intersectLinePlane=: [ +/@:* 1 , p NB. substitute</langsyntaxhighlight>
'''Example Usage:'''
<langsyntaxhighlight lang="j"> Line=: 0 0 10 ,: 0 _1 _1 NB. Point, Ray
Plane=: 0 0 5 ,: 0 0 1 NB. Point, Normal
Line intersectLinePlane Plane
0 _5 5</langsyntaxhighlight>
 
=={{header|Java}}==
{{trans|Kotlin}}
<langsyntaxhighlight Javalang="java">public class LinePLaneIntersectionLinePlaneIntersection {
private static class Vector3D {
private double x, y, z;
Line 244 ⟶ 1,079:
System.out.println("The ray intersects the plane at " + ip);
}
}</langsyntaxhighlight>
{{out}}
<pre>The ray intersects the plane at (0.000000, -5.000000, 5.000000)</pre>
 
=={{header|jq}}==
{{works with|jq}}
'''Works with gojq, the Go implementation of jq'''
 
In the following, a 3d vector is represented by a JSON array: [x, y, z]
<syntaxhighlight lang="jq"># add as many as you please
def addVector:
transpose | add;
 
# . - y
def minusVector(y):
[.[0] - y[0], .[1] - y[1], .[2] - y[2]];
 
# scalar multiplication: . * s
def multVector(s):
map(. * s);
 
def dot(y):
.[0] * y[0] + .[1] * y[1] + .[2] * y[2];
 
def intersectPoint($rayVector; $rayPoint; $planeNormal; $planePoint):
($rayPoint | minusVector($planePoint)) as $diff
| ($diff|dot($planeNormal)) as $prod1
| ($rayVector|dot($planeNormal)) as $prod2
| $rayPoint | minusVector($rayVector | multVector(($prod1 / $prod2) )) ;
 
def rv : [0, -1, -1];
def rp : [0, 0, 10];
def pn : [0, 0, 1];
def pp : [0, 0, 5];
 
"The ray intersects the plane at:",
intersectPoint(rv; rp; pn; pp)</syntaxhighlight>
{{out}}
<pre>
The ray intersects the plane at:
[0,-5,5]
</pre>
 
 
=={{header|Julia}}==
Line 252 ⟶ 1,128:
{{trans|Python}}
 
<langsyntaxhighlight lang="julia">function lineplanecollision(planenorm::Vector, planepnt::Vector, raydir::Vector, raypnt::Vector)
ndotu = dot(planenorm, raydir)
if ndotu ≈ 0 error("no intersection or line is within plane") end
Line 271 ⟶ 1,147:
 
ψ = lineplanecollision(planenorm, planepnt, raydir, raypnt)
println("Intersection at $ψ")</langsyntaxhighlight>
 
{{out}}
Line 277 ⟶ 1,153:
 
=={{header|Kotlin}}==
<langsyntaxhighlight lang="scala">// version 1.1.51
 
class Vector3D(val x: Double, val y: Double, val z: Double) {
Line 312 ⟶ 1,188:
val ip = intersectPoint(rv, rp, pn, pp)
println("The ray intersects the plane at $ip")
}</langsyntaxhighlight>
 
{{out}}
Line 318 ⟶ 1,194:
The ray intersects the plane at (0.0, -5.0, 5.0)
</pre>
 
=={{header|Lua}}==
<syntaxhighlight lang="lua">function make(xval, yval, zval)
return {x=xval, y=yval, z=zval}
end
 
function plus(lhs, rhs)
return make(lhs.x + rhs.x, lhs.y + rhs.y, lhs.z + rhs.z)
end
 
function minus(lhs, rhs)
return make(lhs.x - rhs.x, lhs.y - rhs.y, lhs.z - rhs.z)
end
 
function times(lhs, scale)
return make(scale * lhs.x, scale * lhs.y, scale * lhs.z)
end
 
function dot(lhs, rhs)
return lhs.x * rhs.x + lhs.y * rhs.y + lhs.z * rhs.z
end
 
function tostr(val)
return "(" .. val.x .. ", " .. val.y .. ", " .. val.z .. ")"
end
 
function intersectPoint(rayVector, rayPoint, planeNormal, planePoint)
diff = minus(rayPoint, planePoint)
prod1 = dot(diff, planeNormal)
prod2 = dot(rayVector, planeNormal)
prod3 = prod1 / prod2
return minus(rayPoint, times(rayVector, prod3))
end
 
rv = make(0.0, -1.0, -1.0)
rp = make(0.0, 0.0, 10.0)
pn = make(0.0, 0.0, 1.0)
pp = make(0.0, 0.0, 5.0)
ip = intersectPoint(rv, rp, pn, pp)
print("The ray intersects the plane at " .. tostr(ip))</syntaxhighlight>
{{out}}
<pre>The ray intersects the plane at (0, -5, 5)</pre>
 
=={{header|Maple}}==
<syntaxhighlight lang="maple">geom3d:-plane(P, [geom3d:-point(p1,0,0,5), [0,0,1]]);
geom3d:-line(L, [geom3d:-point(p2,0,0,10), [0,-1,-1]]);
geom3d:-intersection(px,L,P);
geom3d:-detail(px);</syntaxhighlight>
{{Out}}
<pre>[["name of the object",px],["form of the object",point3d],["coordinates of the point",[0,-5,5]]]</pre>
 
=={{header|Mathematica}} / {{header|Wolfram Language}}==
<syntaxhighlight lang="mathematica">RegionIntersection[InfiniteLine[{0, 0, 10}, {0, -1, -1}], InfinitePlane[{0, 0, 5}, {{0, 1, 0}, {1, 0, 0}}]]</syntaxhighlight>
{{out}}
<pre>Point[{0, -5, 5}]</pre>
 
 
=={{header|MATLAB}}==
{{trans|Kotlin}}
<langsyntaxhighlight MATLABlang="matlab">function point = intersectPoint(rayVector, rayPoint, planeNormal, planePoint)
 
pdiff = rayPoint - planePoint;
Line 328 ⟶ 1,260:
prod3 = prod1 / prod2;
 
point = rayPoint - rayVector * prod3;</langsyntaxhighlight>
{{out}}
<langsyntaxhighlight MATLABlang="matlab">>> intersectPoint([0 -1 -1], [0 0 10], [0 0 1], [0 0 5])
 
ans =
 
0 -5 5
</syntaxhighlight>
</lang>
 
=={{header|Modula-2}}==
<langsyntaxhighlight lang="modula2">MODULE LinePlane;
FROM RealStr IMPORT RealToStr;
FROM Terminal IMPORT WriteString,WriteLn,ReadChar;
Line 399 ⟶ 1,331:
 
ReadChar;
END LinePlane.</langsyntaxhighlight>
 
=={{header|Perl 6Nim}}==
<syntaxhighlight lang="nim">
{{works with|Rakudo|2016.11}}
type Vector = tuple[x, y, z: float]
{{trans|Python}}
 
 
<lang perl6>class Line {
func `+`(v1, v2: Vector): Vector =
has $.P0; # point
## Add two vectors.
has $.u⃗; # ray
(v1.x + v2.x, v1.y + v2.y, v1.z + v2.z)
}
 
class Plane {
func `-`(v1, v2: Vector): Vector =
has $.V0; # point
## Subtract a vector to another one.
has $.n⃗; # normal
(v1.x - v2.x, v1.y - v2.y, v1.z - v2.z)
 
func `*`(v1, v2: Vector): float =
## Compute the dot product of two vectors.
v1.x * v2.x + v1.y * v2.y + v1.z * v2.z
 
func `*`(v: Vector; k: float): Vector =
## Multiply a vector by a scalar.
(v.x * k, v.y * k, v.z * k)
 
 
func intersection(lineVector, linePoint, planeVector, planePoint: Vector): Vector =
## Return the coordinates of the intersection of two vectors.
 
let tnum = planeVector * (planePoint - linePoint)
let tdenom = planeVector * lineVector
if tdenom == 0: return (Inf, Inf, Inf) # No intersection.
let t = tnum / tdenom
result = lineVector * t + linePoint
 
let coords = intersection(lineVector = (0.0, -1.0, -1.0),
linePoint = (0.0, 0.0, 10.0),
planeVector = (0.0, 0.0, 1.0),
planePoint = (0.0, 0.0, 5.0))
echo "Intersection at ", coords</syntaxhighlight>
 
{{out}}
<pre>Intersection at (x: 0.0, y: -5.0, z: 5.0)</pre>
 
=={{header|Perl}}==
{{trans|Raku}}
<syntaxhighlight lang="perl">package Line; sub new { my ($c, $a) = @_; my $self = { P0 => $a->{P0}, u => $a->{u} } } # point / ray
package Plane; sub new { my ($c, $a) = @_; my $self = { V0 => $a->{V0}, n => $a->{n} } } # point / normal
 
package main;
 
sub dot { my $p; $p += $_[0][$_] * $_[1][$_] for 0..@{$_[0]}-1; $p } # dot product
sub vd { my @v; $v[$_] = $_[0][$_] - $_[1][$_] for 0..@{$_[0]}-1; @v } # vector difference
sub va { my @v; $v[$_] = $_[0][$_] + $_[1][$_] for 0..@{$_[0]}-1; @v } # vector addition
sub vp { my @v; $v[$_] = $_[0][$_] * $_[1][$_] for 0..@{$_[0]}-1; @v } # vector product
 
sub line_plane_intersection {
my($L, $P) = @_;
 
my $cos = dot($L->{u}, $P->{n}); # cosine between normal & ray
return 'Vectors are orthogonol; no intersection or line within plane' if $cos == 0;
 
my @W = vd($L->{P0},$P->{V0}); # difference between P0 and V0
my $SI = -dot($P->{n}, \@W) / $cos; # line segment where it intersets the plane
 
my @a = vp($L->{u},[($SI)x3]);
my @b = va($P->{V0},\@a);
va(\@W,\@b);
}
 
my $L = Line->new({ P0=>[0,0,10], u=>[0,-1,-1]});
sub infix:<∙> ( @a, @b where +@a == +@b ) { [+] @a «*» @b } # dot product
my $P = Plane->new({ V0=>[0,0,5 ], n=>[0, 0, 1]});
print 'Intersection at point: ', join(' ', line_plane_intersection($L, $P)) . "\n";
</syntaxhighlight>
{{out}}
<pre>Intersection at point: 0 -5 5</pre>
 
=={{header|Phix}}==
sub line-plane-intersection ($𝑳, $𝑷) {
<!--<syntaxhighlight lang="phix">(phixonline)-->
my $cos = $𝑷.n⃗ ∙ $𝑳.u⃗; # cosine between normal & ray
<span style="color: #008080;">with</span> <span style="color: #008080;">javascript_semantics</span>
return 'Vectors are orthogonal; no intersection or line within plane'
<span style="color: #008080;">function</span> <span style="color: #000000;">dot</span><span style="color: #0000FF;">(</span><span style="color: #004080;">sequence</span> <span style="color: #000000;">a</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">b</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">return</span> <span style="color: #7060A8;">sum</span><span style="color: #0000FF;">(</span><span style="color: #7060A8;">sq_mul</span><span style="color: #0000FF;">(</span><span style="color: #000000;">a</span><span style="color: #0000FF;">,</span><span style="color: #000000;">b</span><span style="color: #0000FF;">))</span> <span style="color: #008080;">end</span> <span style="color: #008080;">function</span>
if $cos == 0;
my $𝑊 = $𝑳.P0 «-» $𝑷.V0; # difference between P0 and V0
<span style="color: #008080;">function</span> <span style="color: #000000;">intersection_point</span><span style="color: #0000FF;">(</span><span style="color: #004080;">sequence</span> <span style="color: #000000;">line_vector</span><span style="color: #0000FF;">,</span><span style="color: #000000;">line_point</span><span style="color: #0000FF;">,</span><span style="color: #000000;">plane_normal</span><span style="color: #0000FF;">,</span><span style="color: #000000;">plane_point</span><span style="color: #0000FF;">)</span>
my $S𝐼 = -($𝑷.n⃗ ∙ $𝑊) / $cos; # line segment where it intersects the plane
<span style="color: #004080;">atom</span> <span style="color: #000000;">a</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">dot</span><span style="color: #0000FF;">(</span><span style="color: #000000;">line_vector</span><span style="color: #0000FF;">,</span><span style="color: #000000;">plane_normal</span><span style="color: #0000FF;">)</span>
$𝑊 «+» $S𝐼 «*» $𝑳.u⃗ «+» $𝑷.V0; # point where line intersects the plane
<span style="color: #008080;">if</span> <span style="color: #000000;">a</span><span style="color: #0000FF;">=</span><span style="color: #000000;">0</span> <span style="color: #008080;">then</span> <span style="color: #008080;">return</span> <span style="color: #008000;">"no intersection"</span> <span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
}
<span style="color: #004080;">sequence</span> <span style="color: #000000;">diff</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">sq_sub</span><span style="color: #0000FF;">(</span><span style="color: #000000;">line_point</span><span style="color: #0000FF;">,</span><span style="color: #000000;">plane_point</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">return</span> <span style="color: #7060A8;">sq_add</span><span style="color: #0000FF;">(</span><span style="color: #7060A8;">sq_add</span><span style="color: #0000FF;">(</span><span style="color: #000000;">diff</span><span style="color: #0000FF;">,</span><span style="color: #000000;">plane_point</span><span style="color: #0000FF;">),</span><span style="color: #7060A8;">sq_mul</span><span style="color: #0000FF;">(-</span><span style="color: #000000;">dot</span><span style="color: #0000FF;">(</span><span style="color: #000000;">diff</span><span style="color: #0000FF;">,</span><span style="color: #000000;">plane_normal</span><span style="color: #0000FF;">)/</span><span style="color: #000000;">a</span><span style="color: #0000FF;">,</span><span style="color: #000000;">line_vector</span><span style="color: #0000FF;">))</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">function</span>
<span style="color: #0000FF;">?</span><span style="color: #000000;">intersection_point</span><span style="color: #0000FF;">({</span><span style="color: #000000;">0</span><span style="color: #0000FF;">,-</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,-</span><span style="color: #000000;">1</span><span style="color: #0000FF;">},{</span><span style="color: #000000;">0</span><span style="color: #0000FF;">,</span><span style="color: #000000;">0</span><span style="color: #0000FF;">,</span><span style="color: #000000;">10</span><span style="color: #0000FF;">},{</span><span style="color: #000000;">0</span><span style="color: #0000FF;">,</span><span style="color: #000000;">0</span><span style="color: #0000FF;">,</span><span style="color: #000000;">1</span><span style="color: #0000FF;">},{</span><span style="color: #000000;">0</span><span style="color: #0000FF;">,</span><span style="color: #000000;">0</span><span style="color: #0000FF;">,</span><span style="color: #000000;">5</span><span style="color: #0000FF;">})</span>
<span style="color: #0000FF;">?</span><span style="color: #000000;">intersection_point</span><span style="color: #0000FF;">({</span><span style="color: #000000;">3</span><span style="color: #0000FF;">,</span><span style="color: #000000;">2</span><span style="color: #0000FF;">,</span><span style="color: #000000;">1</span><span style="color: #0000FF;">},{</span><span style="color: #000000;">0</span><span style="color: #0000FF;">,</span><span style="color: #000000;">2</span><span style="color: #0000FF;">,</span><span style="color: #000000;">4</span><span style="color: #0000FF;">},{</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #000000;">2</span><span style="color: #0000FF;">,</span><span style="color: #000000;">3</span><span style="color: #0000FF;">},{</span><span style="color: #000000;">3</span><span style="color: #0000FF;">,</span><span style="color: #000000;">3</span><span style="color: #0000FF;">,</span><span style="color: #000000;">3</span><span style="color: #0000FF;">})</span>
<span style="color: #0000FF;">?</span><span style="color: #000000;">intersection_point</span><span style="color: #0000FF;">({</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #000000;">0</span><span style="color: #0000FF;">},{</span><span style="color: #000000;">0</span><span style="color: #0000FF;">,</span><span style="color: #000000;">0</span><span style="color: #0000FF;">,</span><span style="color: #000000;">1</span><span style="color: #0000FF;">},{</span><span style="color: #000000;">0</span><span style="color: #0000FF;">,</span><span style="color: #000000;">0</span><span style="color: #0000FF;">,</span><span style="color: #000000;">3</span><span style="color: #0000FF;">},{</span><span style="color: #000000;">0</span><span style="color: #0000FF;">,</span><span style="color: #000000;">0</span><span style="color: #0000FF;">,</span><span style="color: #000000;">0</span><span style="color: #0000FF;">})</span> <span style="color: #000080;font-style:italic;">-- (parallel to plane)</span>
<span style="color: #0000FF;">?</span><span style="color: #000000;">intersection_point</span><span style="color: #0000FF;">({</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #000000;">0</span><span style="color: #0000FF;">},{</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #000000;">0</span><span style="color: #0000FF;">},{</span><span style="color: #000000;">0</span><span style="color: #0000FF;">,</span><span style="color: #000000;">0</span><span style="color: #0000FF;">,</span><span style="color: #000000;">3</span><span style="color: #0000FF;">},{</span><span style="color: #000000;">0</span><span style="color: #0000FF;">,</span><span style="color: #000000;">0</span><span style="color: #0000FF;">,</span><span style="color: #000000;">0</span><span style="color: #0000FF;">})</span> <span style="color: #000080;font-style:italic;">-- (line within plane)</span>
<!--</syntaxhighlight>-->
{{out}}
<pre>
{0,-5,5}
{0.6,2.4,4.2}
"no intersection"
"no intersection"
</pre>
 
=={{header|Picat}}==
say 'Intersection at point: ', line-plane-intersection(
{{trans|Java}}
Line.new( :P0(0,0,10), :u⃗(0,-1,-1) ),
{{works with|Picat}}
Plane.new( :V0(0,0, 5), :n⃗(0, 0, 1) )
<syntaxhighlight lang="picat">
);</lang>
plus(U, V) = {U[1] + V[1], U[2] + V[2], U[3] + V[3]}.
 
minus(U, V) = {U[1] - V[1], U[2] - V[2], U[3] - V[3]}.
 
times(U, S) = {U[1] * S, U[2] * S, U[3] * S}.
 
dot(U, V) = U[1] * V[1] + U[2] * V[2] + U[3] * V[3].
 
intersect_point(RayVector, RayPoint, PlaneNormal, PlanePoint) = IntersectPoint =>
Diff = minus(RayPoint, PlanePoint),
Prod1 = dot(Diff, PlaneNormal),
Prod2 = dot(RayVector, PlaneNormal),
Prod3 = Prod1 / Prod2,
IntersectPoint = minus(RayPoint, times(RayVector, Prod3)).
 
main =>
RayVector = {0.0, -1.0, -1.0},
RayPoint = {0.0, 0.0, 10.0},
PlaneNormal = {0.0, 0.0, 1.0},
PlanePoint = {0.0, 0.0, 5.0},
IntersectPoint = intersect_point(RayVector, RayPoint, PlaneNormal, PlanePoint),
printf("The ray intersects the plane at (%f, %f, %f)\n",
IntersectPoint[1],
IntersectPoint[2],
IntersectPoint[3]
).
</syntaxhighlight>
{{out}}
<pre>
<pre>Intersection at point: (0 -5 5)</pre>
The ray intersects the plane at (0.000000, -5.000000, 5.000000)
</pre>
 
 
=={{header|Prolog}}==
{{trans|Picat}}
{{works with|GNU Prolog}}
{{works with|SWI Prolog}}
<syntaxhighlight lang="prolog">
:- initialization(main).
 
vector_plus(U, V, W) :-
U = p(X1, Y1, Z1),
V = p(X2, Y2, Z2),
X3 is X1 + X2,
Y3 is Y1 + Y2,
Z3 is Z1 + Z2,
W = p(X3, Y3, Z3).
 
vector_minus(U, V, W) :-
U = p(X1, Y1, Z1),
V = p(X2, Y2, Z2),
X3 is X1 - X2,
Y3 is Y1 - Y2,
Z3 is Z1 - Z2,
W = p(X3, Y3, Z3).
 
vector_times(U, S, V) :-
U = p(X1, Y1, Z1),
X2 is X1 * S,
Y2 is Y1 * S,
Z2 is Z1 * S,
V = p(X2, Y2, Z2).
 
vector_dot(U, V, S) :-
U = p(X1, Y1, Z1),
V = p(X2, Y2, Z2),
S is X1 * X2 + Y1 * Y2 + Z1 * Z2.
 
intersect_point(RayVector, RayPoint, PlaneNormal, PlanePoint, IntersectPoint) :-
vector_minus(RayPoint, PlanePoint, Diff),
vector_dot(Diff, PlaneNormal, Prod1),
vector_dot(RayVector, PlaneNormal, Prod2),
Prod3 is Prod1 / Prod2,
vector_times(RayVector, Prod3, Times),
vector_minus(RayPoint, Times, IntersectPoint).
 
main :-
RayVector = p(0.0, -1.0, -1.0),
RayPoint = p(0.0, 0.0, 10.0),
PlaneNormal = p(0.0, 0.0, 1.0),
PlanePoint = p(0.0, 0.0, 5.0),
intersect_point(RayVector, RayPoint, PlaneNormal, PlanePoint, p(X, Y, Z)),
format("The ray intersects the plane at (~f, ~f, ~f)\n", [X, Y, Z]).
</syntaxhighlight>
{{out}}
<pre>
 
The ray intersects the plane at (0.000000, -5.000000, 5.000000)
</pre>
 
=={{header|Python}}==
Based on the approach at geomalgorithms.com<ref>http://geomalgorithms.com/a05-_intersect-1.html</ref>
 
<langsyntaxhighlight lang="python">#!/bin/python
from __future__ import print_function
import numpy as np
Line 461 ⟶ 1,554:
 
Psi = LinePlaneCollision(planeNormal, planePoint, rayDirection, rayPoint)
print ("intersection at", Psi)</langsyntaxhighlight>
 
{{out}}
<pre>intersection at [ 0 -5 5]</pre>
 
=={{header|R}}==
{{trans|MATLAB}}
<syntaxhighlight lang="r">intersect_point <- function(ray_vec, ray_point, plane_normal, plane_point) {
 
pdiff <- ray_point - plane_point
prod1 <- pdiff %*% plane_normal
prod2 <- ray_vec %*% plane_normal
prod3 <- prod1 / prod2
point <- ray_point - ray_vec * as.numeric(prod3)
 
return(point)
}</syntaxhighlight>
{{out}}
<syntaxhighlight lang="r">>>intersect_point(c(0, -1, -1), c(0, 0, 10), c(0, 0, 1), c(0, 0, 5))
[1] 0 -5 5</syntaxhighlight>
 
=={{header|Racket}}==
{{trans|Sidef}}
<langsyntaxhighlight lang="racket">#lang racket
;; {{trans|Sidef}}
;; vectors are represented by lists
Line 491 ⟶ 1,600:
(line-plane-intersection (Line '(0 0 10) '(0 -1 -1))
(Plane '(0 0 5) '(0 0 1)))
'(0 -5 5)))</langsyntaxhighlight>
 
{{out}}
No output -- all tests passed!
 
=={{header|Raku}}==
(formerly Perl 6)
{{works with|Rakudo|2016.11}}
{{trans|Python}}
 
<syntaxhighlight lang="raku" line>class Line {
has $.P0; # point
has $.u⃗; # ray
}
class Plane {
has $.V0; # point
has $.n⃗; # normal
}
 
sub infix:<∙> ( @a, @b where +@a == +@b ) { [+] @a «*» @b } # dot product
 
sub line-plane-intersection ($𝑳, $𝑷) {
my $cos = $𝑷.n⃗ ∙ $𝑳.u⃗; # cosine between normal & ray
return 'Vectors are orthogonal; no intersection or line within plane'
if $cos == 0;
my $𝑊 = $𝑳.P0 «-» $𝑷.V0; # difference between P0 and V0
my $S𝐼 = -($𝑷.n⃗ ∙ $𝑊) / $cos; # line segment where it intersects the plane
$𝑊 «+» $S𝐼 «*» $𝑳.u⃗ «+» $𝑷.V0; # point where line intersects the plane
}
 
say 'Intersection at point: ', line-plane-intersection(
Line.new( :P0(0,0,10), :u⃗(0,-1,-1) ),
Plane.new( :V0(0,0, 5), :n⃗(0, 0, 1) )
);</syntaxhighlight>
{{out}}
<pre>Intersection at point: (0 -5 5)</pre>
 
===With a geometric algebra library===
 
See task [[geometric algebra]]
 
<syntaxhighlight lang=raku>use Clifford:ver<6.2.1>;
 
# We pick a (non-degenerate) projective basis and
# we define the dual and meet operators.
my $I = [∧] my ($i, $j, $k, $l) = @e;
sub prefix:<∗>($M) { $M/$I }
sub infix:<∨>($A, $B) { ∗((∗$B)∧(∗$A)) }
 
my $direction = -$j - $k;
 
# Homogeneous coordinates of (X, Y, Z) are (X, Y, Z, 1)
my $point = 10*$k + $l;
 
# A projective line is a bivector
my $line = $direction ∧ $point;
 
# A projective plane is a trivector
my $plane = (5*$k + $l) ∧ ($k*-$i∧$j∧$k);
 
# The intersection is the meet
my $m = $line ∨ $plane;
 
# Affine coordinates of (X, Y, Z, W) are (X/W, Y/W, Z/W)
say $m/($m·$l) X· ($i, $j, $k);</syntaxhighlight>
{{out}}
<pre>(0 -5 5)</pre>
 
=={{header|REXX}}==
===version 1===
This program does NOT handle the case when the line is parallel to or within the plane.
<langsyntaxhighlight lang="rexx">/* REXX */
Parse Value '0 0 1' With n.1 n.2 n.3 /* Normal Vector of the plane */
Parse Value '0 0 5' With p.1 p.2 p.3 /* Point in the plane */
Line 517 ⟶ 1,689:
z=a.3+t*v.3
 
Say 'Intersection: P('||x','y','z')'</langsyntaxhighlight>
 
{{out}}
Line 525 ⟶ 1,697:
===version 2===
handle the case that the line is parallel to the plane or lies within it.
<langsyntaxhighlight lang="rexx">/*REXX*/
Parse Value '1 2 3' With n.1 n.2 n.3
Parse Value '3 3 3' With p.1 p.2 p.3
Line 647 ⟶ 1,819:
End
End
Return res </langsyntaxhighlight>
{{out}}
<pre>Plane definition: x+2*y+3*z=18
Line definition: x=3*t ; y=2+2*t ; z=4+t
Intersection: P(0.6,2.4,4.2)</pre>
 
=={{header|RPL}}==
≪ → rd rp pn pp
≪ rd rp pp - pn DOT * rd pn DOT /
≫ ≫ '<span style="color:blue">INTLP</span>' STO
 
[ 0 -1 -1 ] [ 0 0 0 ] [ 0 0 1 ] [ 0 0 5 ] <span style="color:blue">INTLP</span>
{{out}}
<pre>
1: [ 0 -5 -5 ]
</pre>
 
=={{header|Ruby}}==
{{trans|C#}}
<syntaxhighlight lang="ruby">require "matrix"
 
def intersectPoint(rayVector, rayPoint, planeNormal, planePoint)
diff = rayPoint - planePoint
prod1 = diff.dot planeNormal
prod2 = rayVector.dot planeNormal
prod3 = prod1 / prod2
return rayPoint - rayVector * prod3
end
 
def main
rv = Vector[0.0, -1.0, -1.0]
rp = Vector[0.0, 0.0, 10.0]
pn = Vector[0.0, 0.0, 1.0]
pp = Vector[0.0, 0.0, 5.0]
ip = intersectPoint(rv, rp, pn, pp)
puts "The ray intersects the plane at %s" % [ip]
end
 
main()</syntaxhighlight>
{{out}}
<pre>The ray intersects the plane at Vector[0.0, -5.0, 5.0]</pre>
 
=={{header|Rust}}==
{{trans|Kotlin}}
 
<syntaxhighlight lang="rust">use std::ops::{Add, Div, Mul, Sub};
 
#[derive(Copy, Clone, Debug, PartialEq)]
struct V3<T> {
x: T,
y: T,
z: T,
}
 
impl<T> V3<T> {
fn new(x: T, y: T, z: T) -> Self {
V3 { x, y, z }
}
}
 
fn zip_with<F, T, U>(f: F, a: V3<T>, b: V3<T>) -> V3<U>
where
F: Fn(T, T) -> U,
{
V3 {
x: f(a.x, b.x),
y: f(a.y, b.y),
z: f(a.z, b.z),
}
}
 
impl<T> Add for V3<T>
where
T: Add<Output = T>,
{
type Output = Self;
 
fn add(self, other: Self) -> Self {
zip_with(<T>::add, self, other)
}
}
 
impl<T> Sub for V3<T>
where
T: Sub<Output = T>,
{
type Output = Self;
 
fn sub(self, other: Self) -> Self {
zip_with(<T>::sub, self, other)
}
}
 
impl<T> Mul for V3<T>
where
T: Mul<Output = T>,
{
type Output = Self;
 
fn mul(self, other: Self) -> Self {
zip_with(<T>::mul, self, other)
}
}
 
impl<T> V3<T>
where
T: Mul<Output = T> + Add<Output = T>,
{
fn dot(self, other: Self) -> T {
let V3 { x, y, z } = self * other;
x + y + z
}
}
 
impl<T> V3<T>
where
T: Mul<Output = T> + Copy,
{
fn scale(self, scalar: T) -> Self {
self * V3 {
x: scalar,
y: scalar,
z: scalar,
}
}
}
 
fn intersect<T>(
ray_vector: V3<T>,
ray_point: V3<T>,
plane_normal: V3<T>,
plane_point: V3<T>,
) -> V3<T>
where
T: Add<Output = T> + Sub<Output = T> + Mul<Output = T> + Div<Output = T> + Copy,
{
let diff = ray_point - plane_point;
let prod1 = diff.dot(plane_normal);
let prod2 = ray_vector.dot(plane_normal);
let prod3 = prod1 / prod2;
ray_point - ray_vector.scale(prod3)
}
 
fn main() {
let rv = V3::new(0.0, -1.0, -1.0);
let rp = V3::new(0.0, 0.0, 10.0);
let pn = V3::new(0.0, 0.0, 1.0);
let pp = V3::new(0.0, 0.0, 5.0);
println!("{:?}", intersect(rv, rp, pn, pp));
}
</syntaxhighlight>
 
=={{header|Scala}}==
<syntaxhighlight lang="scala">object LinePLaneIntersection extends App {
val (rv, rp, pn, pp) =
(Vector3D(0.0, -1.0, -1.0), Vector3D(0.0, 0.0, 10.0), Vector3D(0.0, 0.0, 1.0), Vector3D(0.0, 0.0, 5.0))
val ip = intersectPoint(rv, rp, pn, pp)
 
def intersectPoint(rayVector: Vector3D,
rayPoint: Vector3D,
planeNormal: Vector3D,
planePoint: Vector3D): Vector3D = {
val diff = rayPoint - planePoint
val prod1 = diff dot planeNormal
val prod2 = rayVector dot planeNormal
val prod3 = prod1 / prod2
rayPoint - rayVector * prod3
}
 
case class Vector3D(x: Double, y: Double, z: Double) {
def +(v: Vector3D) = Vector3D(x + v.x, y + v.y, z + v.z)
def -(v: Vector3D) = Vector3D(x - v.x, y - v.y, z - v.z)
def *(s: Double) = Vector3D(s * x, s * y, s * z)
def dot(v: Vector3D): Double = x * v.x + y * v.y + z * v.z
override def toString = s"($x, $y, $z)"
}
println(s"The ray intersects the plane at $ip")
}</syntaxhighlight>
{{Out}}See it in running in your browser by [https://scalafiddle.io/sf/oLTlNZk/0 ScalaFiddle (JavaScript)].
 
=={{header|Sidef}}==
{{trans|Perl 6Raku}}
<langsyntaxhighlight lang="ruby">struct Line {
P0, # point
u⃗, # ray
Line 678 ⟶ 2,025:
Line(P0: [0,0,10], u⃗: [0,-1,-1]),
Plane(V0: [0,0, 5], n⃗: [0, 0, 1]),
))</langsyntaxhighlight>
{{out}}
<pre>Intersection at point: [0, -5, 5]</pre>
 
=={{header|Visual Basic .NET}}==
{{trans|C#}}
<syntaxhighlight lang="vbnet">Module Module1
 
Class Vector3D
Private ReadOnly x As Double
Private ReadOnly y As Double
Private ReadOnly z As Double
 
Sub New(nx As Double, ny As Double, nz As Double)
x = nx
y = ny
z = nz
End Sub
 
Public Function Dot(rhs As Vector3D) As Double
Return x * rhs.x + y * rhs.y + z * rhs.z
End Function
 
Public Shared Operator +(ByVal a As Vector3D, ByVal b As Vector3D) As Vector3D
Return New Vector3D(a.x + b.x, a.y + b.y, a.z + b.z)
End Operator
 
Public Shared Operator -(ByVal a As Vector3D, ByVal b As Vector3D) As Vector3D
Return New Vector3D(a.x - b.x, a.y - b.y, a.z - b.z)
End Operator
 
Public Shared Operator *(ByVal a As Vector3D, ByVal b As Double) As Vector3D
Return New Vector3D(a.x * b, a.y * b, a.z * b)
End Operator
 
Public Overrides Function ToString() As String
Return String.Format("({0:F}, {1:F}, {2:F})", x, y, z)
End Function
End Class
 
Function IntersectPoint(rayVector As Vector3D, rayPoint As Vector3D, planeNormal As Vector3D, planePoint As Vector3D) As Vector3D
Dim diff = rayPoint - planePoint
Dim prod1 = diff.Dot(planeNormal)
Dim prod2 = rayVector.Dot(planeNormal)
Dim prod3 = prod1 / prod2
Return rayPoint - rayVector * prod3
End Function
 
Sub Main()
Dim rv = New Vector3D(0.0, -1.0, -1.0)
Dim rp = New Vector3D(0.0, 0.0, 10.0)
Dim pn = New Vector3D(0.0, 0.0, 1.0)
Dim pp = New Vector3D(0.0, 0.0, 5.0)
Dim ip = IntersectPoint(rv, rp, pn, pp)
Console.WriteLine("The ray intersects the plane at {0}", ip)
End Sub
 
End Module</syntaxhighlight>
{{out}}
<pre>The ray intersects the plane at (0.00, -5.00, 5.00)</pre>
 
=={{header|Wren}}==
{{trans|Kotlin}}
{{libheader|Wren-vector}}
<syntaxhighlight lang="wren">import "./vector" for Vector3
 
var intersectPoint = Fn.new { |rayVector, rayPoint, planeNormal, planePoint|
var diff = rayPoint - planePoint
var prod1 = diff.dot(planeNormal)
var prod2 = rayVector.dot(planeNormal)
var prod3 = prod1 / prod2
return rayPoint - rayVector*prod3
}
 
var rv = Vector3.new(0, -1, -1)
var rp = Vector3.new(0, 0, 10)
var pn = Vector3.new(0, 0, 1)
var pp = Vector3.new(0, 0, 5)
var ip = intersectPoint.call(rv, rp, pn, pp)
System.print("The ray intersects the plane at %(ip).")</syntaxhighlight>
 
{{out}}
<pre>
The ray intersects the plane at (0, -5, 5).
</pre>
 
=={{header|XPL0}}==
{{trans|Wren}}
<syntaxhighlight lang "XPL0">include xpllib;
 
func real IntersectPoint; real RayVector, RayPoint, PlaneNormal, PlanePoint;
real Diff(3), Prod1, Prod2, Prod3, Prod(3);
[VSub(Diff, RayPoint, PlanePoint);
Prod1:= VDot(Diff, PlaneNormal);
Prod2:= VDot(RayVector, PlaneNormal);
Prod3:= Prod1 / Prod2;
return VSub(Diff, RayPoint, VMul(Prod, RayVector, Prod3));
];
 
real RV, RP, PN, PP, IP;
[RV:= [0., -1., -1.];
RP:= [0., 0., 10.];
PN:= [0., 0., 1.];
PP:= [0., 0., 5.];
IP:= IntersectPoint(RV, RP, PN, PP);
Print("The ray intersects the plane at %1.1f, %1.1f, %1.1f\n", IP(0), IP(1), IP(2));
]</syntaxhighlight>
{{out}}
<pre>
The ray intersects the plane at 0.0, -5.0, 5.0
Intersection at point: [0, -5, 5]
</pre>
 
=={{header|zkl}}==
{{trans|Perl 6Raku}}{{trans|Python}}
<langsyntaxhighlight lang="zkl">class Line { fcn init(pxyz, ray_xyz) { var pt=pxyz, ray=ray_xyz; } }
class Plane{ fcn init(pxyz, normal_xyz){ var pt=pxyz, normal=normal_xyz; } }
 
Line 693 ⟶ 2,146:
cos:=dotP(plane.normal,line.ray); # cosine between normal & ray
_assert_((not cos.closeTo(0,1e-6)),
"Vectors are orthoganolorthogonol; no intersection or line within plane");
w:=line.pt.zipWith('-,plane.pt); # difference between P0 and V0
si:=-dotP(plane.normal,w)/cos; # line segment where it intersets the plane
Line 699 ⟶ 2,152:
//w.zipWith('+,line.ray.apply('*,si)).zipWith('+,plane.pt); // or
w.zipWith('wrap(w,r,pt){ w + r*si + pt },line.ray,plane.pt);
}</langsyntaxhighlight>
<langsyntaxhighlight lang="zkl">println("Intersection at point: ", linePlaneIntersection(
Line( T(0.0, 0.0, 10.0), T(0.0, -1.0, -1.0) ),
Plane(T(0.0, 0.0, 5.0), T(0.0, 0.0, 1.0) ))
);</langsyntaxhighlight>
{{out}}
<pre>
9,492

edits