在tcl中找到平面和直线之间的交点?

时间:2009-10-08 12:41:21

标签: math tcl

下面的代码有什么问题? 我的结果很奇怪。我错过了什么吗?

proc Dot {vec1 vec2} {
set ret [expr ([lindex $vec1 0]*[lindex $vec2 0])+([lindex $vec1 1]*[lindex $vec2 1])+([lindex $vec1 2]*[lindex $vec2 2])]
}

proc FindInterSectPoint_LineAndPlane {normalVectorPlane basePoint refPoint topoint} {

foreach {norm1 norm2 norm3} $normalVectorPlane {break}

foreach {xB yB zB} $basePoint {break}

foreach {xb yb zb} $refPoint {break}

foreach {xa ya za} $topoint {break}

set vecL1 [expr $xb-$xa]
set vecL2 [expr $yb-$ya]
set vecL3 [expr $zb-$za]

set direction [expr -($norm1*$xB)+($norm2*$yB)+($norm3*$zB)]
set d [expr -(($vecL1*$xb)+($vecL2*$yb)+($vecL3*$zb)+$direction)]
set n [Dot $normalVectorPlane [list $vecL1 $vecL2 $vecL3] ]

if {$n == 0} {
    return "line on parallel to plane"; # line on plane
} 

set s [expr $d/($n*1.000)]

if {$s > 0 && $s < 1} {
    set ret "intersection occurs between the two end points"
} elseif {$s == 0} {
    set ret "intersection falls on the first end point"
} elseif {$s == 1} {
    set ret "intersection falls on the second end point"
} elseif {$s > 1} {
    set ret "intersection occurs beyond second end Point"
} elseif {$s < 0} {
    set ret "intersection happens before 1st end point"
} else {
    set ret "error"
}


set x [expr [lindex $refPoint 0]+($s*$vecL1)]
set y [expr [lindex $refPoint 1]+($s*$vecL2)]
set z [expr [lindex $refPoint 2]+($s*$vecL3)]
lappend ret "$x $y $z n=$n d=$d s=$s"
 }

输出:

%FindInterSectPoint_LineAndPlane {0 0 1} {0 0 0} {0 0 0} {1 2 3}

交叉点落在第一个终点{0.0 0.0 0.0 n = -3 d = 0 s = -0.0}

%FindInterSectPoint_LineAndPlane {1 0 0} {0 0 0} {0 0 1} {0 0 0}

与平面平行的线

%FindInterSectPoint_LineAndPlane {1 0 0} {0 0 0} {0 0 1} {0 0 5}

与平面平行的线

%FindInterSectPoint_LineAndPlane {0 0 1} {0 0 0} {1 1 1} {2 2 2}

交叉发生在第一个终点之前{4.0 4.0 4.0 n = -1 d = 3 s = -3.0}

%FindInterSectPoint_LineAndPlane {0 0 1} {0 0 0} {-1 -1 -1} {2 2 2}

交叉点超出第二个终点{-10.0 -10.0 -10.0 n = -3 d = -9 s = 3.0}

2 个答案:

答案 0 :(得分:2)

这是什么?

if {$s < 0 | $s > 1} {
   return 0; # no intersection
}

我猜这应该是:

if {$s < 0 || $s > 1} {
   return 0
}

(注意“|”和“||”的区别。

另外,关于上述代码的一些评论:

  • 除非你有理由不(没有多少),否则总是支持你的表达 - &gt; [expr {$ xb- $ xa}]。它们会更安全,而且很多更快。
  • 您可以通过执行以下任一操作来大大缩短[lindex]代码:
    • foreach {xb yb zb} $ refPoint {break}(tcl的任何版本)
    • lassign $ refPoint xb yb zb(Tcl 8.5 and newer)

由于我们没有“Dot”和“UnitVector”的来源,我想也可能存在问题。

答案 1 :(得分:1)

该行

set direction [expr -($norm1*$xB)+($norm2*$yB)+($norm3*$zB)]

看起来并不正确,但由于basePoint是起源,因此无法导致结果。它应该不是

set direction [expr -(($norm1*$xB)+($norm2*$yB)+($norm3*$zB))]

编辑:

我又看了一眼,我可以看到一些问题。首先,您对d的定义不正确。您已使用线方向而不是平面法线和线的topoint而不是refPoint。我想指出前者可能已经发生了,因为你使用了一个奇怪的命名方案并调用了行方向组件norm11norm12norm13!那行代码应该是

set d [expr -(($norm1*$xb)+($norm1*$yb)+($norm1*$zb)+$direction)]

我可以看到的第二个问题是s应该是d / n而不是n / d

EDIT2:

好的,现在尝试删除d上的测试,因为我看不到它的重点。你仍然需要在n上进行测试,因为现在它是你的分母,如果那是零,那么这就意味着这条线与飞机平行。这是唯一没有交叉的情况(假设该线被视为无限长)。