tcl中浮点数比较

发布于 2024-10-21 02:23:50 字数 1881 浏览 1 评论 0原文

当我计算点和线之间的距离时遇到问题。 存在浮点数计算(比较表达式)问题。因此,我无法知道 $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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

貪欢 2024-10-28 02:23:50

浮点数(在所有语言中,不仅仅是 Tcl)表示大多数数字有些不精确。因此,通常不应该对它们进行平等比较,因为这实际上不太可能。相反,您应该检查两个值是否在一定范围内(该值称为epsilon,并考虑到浮点计算中存在小错误)。

在您的代码中,您可能会这样写:

set epsilon 0.001; # Small, but non-zero
if { $epsilon < $n_rval && $n_rval < 1-$epsilon} {
    set onextensionFlag 0;# inside clipping area
} elseif {abs($n_rval) < $epsilon || abs(1-$n_rval) < $epsilon} {
    set onextensionFlag 1 ;# inside clipping area (but on point)
} elseif { $n_rval >= 1+$epsilon || $n_rval <= -$epsilon } {
    set onextensionFlag 2 ;# outside clipping area
} else {
    set onextensionFlag 3 ;# consider inside clipping area
}

基本上,按照将点更改为小间隔的数轴进行思考:

                0                1
————————————————|————————————————|————————————————

如何

             0-ε 0+ε          1-ε 1+ε
———————————————(—)——————————————(—)———————————————

检查您所在的范围,然后从中进行跟踪。

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:

set epsilon 0.001; # Small, but non-zero
if { $epsilon < $n_rval && $n_rval < 1-$epsilon} {
    set onextensionFlag 0;# inside clipping area
} elseif {abs($n_rval) < $epsilon || abs(1-$n_rval) < $epsilon} {
    set onextensionFlag 1 ;# inside clipping area (but on point)
} elseif { $n_rval >= 1+$epsilon || $n_rval <= -$epsilon } {
    set onextensionFlag 2 ;# outside clipping area
} else {
    set onextensionFlag 3 ;# consider inside clipping area
}

Basically, think in terms of a number line where you change points to small intervals:

                0                1
————————————————|————————————————|————————————————

to

             0-ε 0+ε          1-ε 1+ε
———————————————(—)——————————————(—)———————————————

How to do the checks for which range you're in then follow from that.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文