## Distance from a Point to a Plane (3D)

I used to sleep a lot in math class... For this question Calculating Distance from a Point to a Plane I can answer... Maybe there’s a faster way to calculate...

```namespace eval Vector3D {

namespace export *

proc sub_v3v3 {v0 v1} {

lassign \$v0 v0x v0y v0z
lassign \$v1 v1x v1y v1z

return [list [expr {\$v0x - \$v1x}] \
[expr {\$v0y - \$v1y}] \
[expr {\$v0z - \$v1z}]]

}

proc dot_v3v3 {v0 v1} {

lassign \$v0 v0x v0y v0z
lassign \$v1 v1x v1y v1z

return [expr {(\$v0x * \$v1x) + (\$v0y * \$v1y) +  (\$v0z * \$v1z)}]

}

proc cross_v3v3 {v0 v1} {

lassign \$v0 vx0 vy0 vz0
lassign \$v1 vx1 vy1 vz1

return [list [expr {(\$vy0 * \$vz1) - (\$vy1 * \$vz0)}] \
[expr {(\$vz0 * \$vx1) - (\$vx0 * \$vz1)}] \
[expr {(\$vx0 * \$vy1) - (\$vy0 * \$vx1)}]]

}

proc norm {v} {

lassign \$v vx vy vz

return [expr {sqrt(\$vx**2 + \$vy**2 + \$vz**2)}]

}

proc unit {v} {

set n [norm \$v]

if {\$n == 0} {
error "Must be greatest than 0..."
}

lassign \$v x y z

return [list [expr {\$x / double(\$n)}] \
[expr {\$y / double(\$n)}] \
[expr {\$z / double(\$n)}]]

}

}```
• Utilisation :
```namespace import Vector3D::*

set plan {{-10 -10 10} {10 -10 10} {0 10 10}} ; # 3 points on plan (3d)
set point {0 0 12} ; # point (3d)

lassign \$plan v0 v1 v2

set u [sub_v3v3 \$v1 \$v0]
set v [sub_v3v3 \$v2 \$v0]
set normal [unit [cross_v3v3 \$u \$v]] ; # normal to plane

set sub [sub_v3v3 \$point \$v0]
set dist [dot_v3v3 \$normal \$sub]

puts "Distance 3D = \$dist"
# Distance 3D = 2.0```

Here is my pure Tcl implementation of the task to compute the distance of a point to a plane in 3D. The procedures are optimized for maximum performance. I did not compare to above implementation.

```## Get the distance of a point p to a plane given by origin point a and normal vector u.
proc DistPoint2Plane {p a u {abskey 1}} {
# Normalize vector u to the length of one
set u [VectorNormalize \$u]
# Get vector from a to p
set ap [VectorsDifference \$p \$a]
# Return the distance as scalar product of u and ap
if {\$abskey} {
return [expr {abs([VectorsDotProduct \$u \$ap])}]
} else {
return [expr {[VectorsDotProduct \$u \$ap]}]
}
}
## Normalize vector a to length 1
proc VectorNormalize {a} {
set norm [VectorNorm \$a]
if {\$norm!=0} {
return [list [expr {[lindex \$a 0]/double(\$norm)}] [expr {[lindex \$a 1]/double(\$norm)}] [expr {[lindex \$a 2]/double(\$norm)}]]
} else {
return \$a
}
}
## Compute the length of vector a
proc VectorNorm {a} {
lassign \$a a1 a2 a3
return [expr {sqrt(pow(\$a1,2)+pow(\$a2,2)+pow(\$a3,2))}]
}
## compute the difference of vector a and b (a-b)
proc VectorsDifference {a b} {
if {[lindex \$a 3]=="" || [lindex \$b 3]==""} {
return [list [expr {[lindex \$a 0]-[lindex \$b 0]}] [expr {[lindex \$a 1]-[lindex \$b 1]}] [expr {[lindex \$a 2]-[lindex \$b 2]}]]
} else {
return [list [expr {[lindex \$a 0]-[lindex \$b 0]}] [expr {[lindex \$a 1]-[lindex \$b 1]}] [expr {[lindex \$a 2]-[lindex \$b 2]}] [expr {[lindex \$a 3]-[lindex \$b 3]}] [expr {[lindex \$a 4]-[lindex \$b 4]}] [expr {[lindex \$a 5]-[lindex \$b 5]}]]
}
}
## Compute the dot product of vectors a and b
proc VectorsDotProduct {a b} {
lassign \$a a1 a2 a3
lassign \$b b1 b2 b3
return [expr {\$a1*\$b1+\$a2*\$b2+\$a3*\$b3}]
}```

Usage:

`DistPoint2Plane {0 0 10} {0 0 0} {0 0 1}`

kch - An alternate approach. For details see explanation

```#
# This code presumes all parameters are pre-validated.
#
proc defPoint {x y z} {
return [list \$x \$y \$z]
}; # defPoint {}

proc defVector {Pa Pb} {
set dx [expr {[lindex \$Pb 0] - [lindex \$Pa 0]}]
set dy [expr {[lindex \$Pb 1] - [lindex \$Pa 1]}]
set dz [expr {[lindex \$Pb 2] - [lindex \$Pa 2]}]

return [list \$dx \$dy \$dz]
}; # defVector {}

proc crossProduct {Va Vb} {
set A [expr { [lindex \$Va 1] * [lindex \$Vb 2]
- [lindex \$Va 2] * [lindex \$Vb 1]
}]
set B [expr { [lindex \$Va 2] * [lindex \$Vb 0]
- [lindex \$Va 0] * [lindex \$Vb 2]
}]
set C [expr { [lindex \$Va 0] * [lindex \$Vb 1]
- [lindex \$Va 1] * [lindex \$Vb 0]
}]
return [list \$A \$B \$C]
}; # crossProduct {}

proc vecLen {V} {
set accum 0
foreach element \$V {
incr accum [expr {\$element * \$element}]
}
return [expr {sqrt(\$accum)}]
}; # vecLen {}

proc normalize {V} {
set len [vecLen \$V]
set normVec {}
foreach element \$V {
lappend normVec [expr {\$element / \$len}]
}
return \$normVec
}; # normalize {}

proc defPlane {NormVec P0} {
set D 0
foreach vElement \$NormVec pElement \$P0 {
set D [expr {\$D - \$vElement * \$pElement}]
}
return [list {*}\$NormVec \$D]
}; # defPlane {}

proc distToPlane {plane point} {
set D [lindex \$plane 3]
foreach vElement [lrange \$plane 0 2] pElement \$point {
set D [expr {\$D + \$vElement * \$pElement}]
}
return \$D
}; # distToPlane {}```

Usage:

``` % set P0 [defPoint 1 0 0]
1 0 0
% set P1 [defPoint 0 1 0]
0 1 0
% set P2 [defPoint 0 0 1]
0 0 1

% set Va [defVector \$P0 \$P1]
-1 1 0
% set Vb [defVector \$P0 \$P2]
-1 0 1

% set NormalA [crossProduct \$Va \$Vb]
1 1 1

% set nVecA [normalize \$NormalA]
0.5773502691896258 0.5773502691896258 0.5773502691896258

% set planeA [defPlane \$nVecA \$P0]
0.5773502691896258 0.5773502691896258 0.5773502691896258 -0.5773502691896258

% distToPlane \$PA \$P0
0.0
% distToPlane \$PA {1 1 1}
1.1547005383792517
% distToPlane \$PA {0 0 0}
-0.5773502691896258
```