2011-03-10 11 views
4

점과 선 간의 거리를 계산할 때 문제가 발생합니다. 부동 소수점 계산 (표현 비교) 문제가 있습니다. 이것 때문에 나는 $ onextensionFlag의 완벽한 가치를 알 수 없었다. 다음을 참조하십시오 ... 무엇이 잘못되었는지 알 수 있습니까?tcl에서 부동 소수점 비교

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] 


    } 
    } 

답변

6

부동 소수점 숫자 (Tcl뿐 아니라 모든 언어로 표시)는 대부분 숫자를 정확하지 않게 나타냅니다. 그렇기 때문에 평등을 위해 비교되어서는 안됩니다. 실제로는 그렇지 않을 것입니다. 대신, 두 값이 일정한 양 (서로의 양은 엡실론으로 알려져 있으며 부동 소수점 계산에 작은 오류가 있음을 고려함) 내에 있는지 확인해야합니다. 코드에서

, 당신은이를 작성할 수 있습니다

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

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

에 : 당신은 작은 간격으로 포인트를 변경할 경우

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

감사합니다. 이것이 제가 찾고 있던 것입니다. 나를위한 아주 좋은 교훈. – OliveOne

+0

또한, IEEE 부동 소수점 (Tcl에서 사용)에서 * 정확한 숫자는 합리적인 크기까지의 정수입니다. 그러나 무한히하지 말라. 배정도 부동 소수점은 고정 된 비트 수를가집니다. –