I used to sleep a lot in math class... For this question https://groups.google.com/forum/m/#!topic/comp.lang.tcl/iOedyEIUC4E%|%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:
======
#
# 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
======