Floating point number in tcl

I am having problems calculating the distance between a point and a line. There is a problem calculating a floating point number (comparing an expression). In this regard, I can not know the ideal value of $ onextensionFlag. see below ... Can I find out 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] } } 
+4
source share
1 answer

Floating point numbers (in all languages, not just Tcl) represent most numbers somewhat inaccurate. Thus, they should usually not be compared for equality, since this is really unlikely. Instead, you should check if the two values ​​are in a certain amount from 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 can 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+Ξ΅ β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”(β€”)β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”(β€”)β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€” 

To check what range you are in, follow it.

+6
source

Source: https://habr.com/ru/post/1343139/


All Articles