tcl中浮点数比较
当我计算点和线之间的距离时遇到问题。 存在浮点数计算(比较表达式)问题。因此,我无法知道 $onextensionFlag 的完美值。请看以下... 我可以知道出了什么问题吗?
proc calculateDistanceToLinefrompoint {P line} {
# solution based on FAQ 1.02 on comp.graphics.algorithms
# L = sqrt( (Bx-Ax)^2 + (By-Ay)^2 )
# (Ay-Cy)(Bx-Ax)-(Ax-Cx)(By-Ay)
# s = -----------------------------
# L^2
# dist = |s|*L # =>
# | (Ay-Cy)(Bx-Ax)-(Ax-Cx)(By-Ay) |
# dist = ---------------------------------
# L
# (Ay-Cy)(Ay-By)-(Ax-Cx)(Bx-Ax)
# r = -----------------------------
# L^2
# r=0 P = A
# r=1 P = B
# r<0 P is on the backward extension of AB
# r>1 P is on the forward extension of AB
# 0<=r<=1 P is interior to AB
set ret 0
set Ax [lindex $line 0 0]
set Ay [lindex $line 0 1]
set Az [lindex $line 0 2]
set Bx [lindex $line 1 0]
set By [lindex $line 1 1]
set Bz [lindex $line 1 2]
set Cx [lindex $P 0]
set Cy [lindex $P 1]
set Cz [lindex $P 2]
if {$Ax==$Bx && $Ay==$By && $Az==$Bz} {
set ret [list [GetDistanceBetweenTwoPoints $P [lindex $line 0]] 1]
} else {
set L [expr {sqrt(pow($Bx-$Ax,2) + pow($By-$Ay,2) + pow($Bz-$Az,2))}]
#puts "L=$L"
set d_val [expr {($Ay-$Cy)*($Bx-$Ax)-($Ax-$Cx)*($By-$Ay)-($Az-$Bz)*($Az-$Cz)}]
set n_rval [expr {$d_val / pow($L,2)}]
set n_rval [format "%0.3f" $n_rval]
if { 0 < $n_rval && $n_rval < 1} {
set onextensionFlag 0;# inside clipping area
} elseif {$n_rval == 0 || $n_rval == 1} {
set onextensionFlag 1 ;# inside clipping area (but on point)
} elseif { $n_rval > 1 || $n_rval < 0 } {
set onextensionFlag 2 ;# outside clipping area
} else {
set onextensionFlag 3 ;# consider inside clipping area
}
set ret [list [expr {abs($d_val) / $L}] $onextensionFlag $n_rval]
}
}
I am getting problems when I calculating distance between point and line.
There is floating point number calculation (compare expression) problem. Due to this I not able to know perfect value of $onextensionFlag. please see following...
May I know what is wrong?
proc calculateDistanceToLinefrompoint {P line} {
# solution based on FAQ 1.02 on comp.graphics.algorithms
# L = sqrt( (Bx-Ax)^2 + (By-Ay)^2 )
# (Ay-Cy)(Bx-Ax)-(Ax-Cx)(By-Ay)
# s = -----------------------------
# L^2
# dist = |s|*L # =>
# | (Ay-Cy)(Bx-Ax)-(Ax-Cx)(By-Ay) |
# dist = ---------------------------------
# L
# (Ay-Cy)(Ay-By)-(Ax-Cx)(Bx-Ax)
# r = -----------------------------
# L^2
# r=0 P = A
# r=1 P = B
# r<0 P is on the backward extension of AB
# r>1 P is on the forward extension of AB
# 0<=r<=1 P is interior to AB
set ret 0
set Ax [lindex $line 0 0]
set Ay [lindex $line 0 1]
set Az [lindex $line 0 2]
set Bx [lindex $line 1 0]
set By [lindex $line 1 1]
set Bz [lindex $line 1 2]
set Cx [lindex $P 0]
set Cy [lindex $P 1]
set Cz [lindex $P 2]
if {$Ax==$Bx && $Ay==$By && $Az==$Bz} {
set ret [list [GetDistanceBetweenTwoPoints $P [lindex $line 0]] 1]
} else {
set L [expr {sqrt(pow($Bx-$Ax,2) + pow($By-$Ay,2) + pow($Bz-$Az,2))}]
#puts "L=$L"
set d_val [expr {($Ay-$Cy)*($Bx-$Ax)-($Ax-$Cx)*($By-$Ay)-($Az-$Bz)*($Az-$Cz)}]
set n_rval [expr {$d_val / pow($L,2)}]
set n_rval [format "%0.3f" $n_rval]
if { 0 < $n_rval && $n_rval < 1} {
set onextensionFlag 0;# inside clipping area
} elseif {$n_rval == 0 || $n_rval == 1} {
set onextensionFlag 1 ;# inside clipping area (but on point)
} elseif { $n_rval > 1 || $n_rval < 0 } {
set onextensionFlag 2 ;# outside clipping area
} else {
set onextensionFlag 3 ;# consider inside clipping area
}
set ret [list [expr {abs($d_val) / $L}] $onextensionFlag $n_rval]
}
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
浮点数(在所有语言中,不仅仅是 Tcl)表示大多数数字有些不精确。因此,通常不应该对它们进行平等比较,因为这实际上不太可能。相反,您应该检查两个值是否在一定范围内(该值称为epsilon,并考虑到浮点计算中存在小错误)。
在您的代码中,您可能会这样写:
基本上,按照将点更改为小间隔的数轴进行思考:
如何
检查您所在的范围,然后从中进行跟踪。
Floating point numbers (in all languages, not just Tcl) represent most numbers somewhat inexactly. As such, they should not normally be compared for equality as that's really rather unlikely. Instead, you should check to see if the two values are within a certain amount of each other (the amount is known as epsilon and takes into account that there are small errors in floating point calculations).
In your code, you might write this:
Basically, think in terms of a number line where you change points to small intervals:
to
How to do the checks for which range you're in then follow from that.