Why does not work using while for looping process - tcl

Why my script does not work. I am using while for looping process.
Hope anyone could help me for my case. The script as below;
Set global
global xmin xmax ymin ymax xVer yVer x1 y1 Count
Set paramaters
set xmin 0
set xmax 51
set ymin 0
set ymax 51
set x1 2
set y1 2
set xVer 2
set yVer 2
set Count 1
set goToVer "n"
Do looping process
while {$x1 > $xmin && $x1 < $xmax && $y1 > $ymin && $y1 < $ymax} {
# For horizontal axis
while {$x1 > $xmin && $x1 < $xmax} {
set azi [expr (45+90)]
set dip 0
set length 2
set dist [expr (cos($dip) * $length)]
set x1 [expr ($x1 + (sin($azimuth) * $dist))]
set y1 [expr ($y1 + (cos($azimuth) * $dist))]
set goToVer "y"
incr Count
}
# For vertical axis
if {$goToVer == "y"} {
set azi 45
set dip 0
set length 5
set dist [expr (cos($dip) * $length)]
set x1 [expr ($xVer + (sin($azimuth) * $dist))]
set y1 [expr ($yVer + (cos($azimuth) * $dist))]
set xVer $x1
set yVer $y1
incr Count
}
}
Thanks in advance!

I don't know what the problem is, but there are some things that we can do to make everything better. First step: let's ry factoring out the coordinate conversion code itself into a little procedure (I've fixed the braces around the expressions too):
proc convert {x y length azimuth dip} {
set dist [expr {cos($dip) * $length}]
set x1 [expr {$x + sin($azimuth) * $dist}]
set y1 [expr {$y + cos($azimuth) * $dist}]
return [list $x1 $y1]
}
while {$x1 > $xmin && $x1 < $xmax && $y1 > $ymin && $y1 < $ymax} {
# For horizontal axis
while {$x1 > $xmin && $x1 < $xmax} {
set azi [expr (45+90)]
set dip 0
set length 2
lassign [convert $x1 $y1 $length $azi $dip] x1 y1
set goToVer "y"
incr Count
}
# For vertical axis
if {$goToVer == "y"} {
set azi 45
set dip 0
set length 5
lassign [convert $xVer $yVer $length $azi $dip] x1 y1
incr Count
}
}
Next, the value of azi in the inner loop is suspicious; it looks like it is in degrees but Tcl's trigonometry functions (like those in most other programming languages) take their argument in radians. Multiply it by π/180°.
Finally, the logic of the loops is weird. I'm not saying it is wrong… but I really find it hard to comprehend what you'd use looping like that for. To loop a pair of coordinates over some space using equal steps on the axes, you use for loops with integer iterator variables and then apply a conversion to get your floating point coordinates (this is best because it limits cumulative errors):
set azi [expr {(45 + 90) * 3.1415927/180}]
set dip 0
set length 2
for {set x $xmin} {$x <= $xmax} {incr x} {
for {set y $ymin} {$y <= $ymax} {incr y} {
set dist [expr {cos($dip) * $length}]
set x1 [expr {$x + sin($azimuth) * $dist}]
set y1 [expr {$y + cos($azimuth) * $dist}]
# I assume you want to do something with $x1,$y1 here…
}
}
Alternatively, you could use regular spacing in polar coordinates, or any other regular scheme; it's just that good code exploits regularity and you're strongly recommended to work that way if you can. But that might not be what you were trying to do at all. Your code is confusing in its intent.
Which brings me to your actual bugs, which appear to revolve around state management. The logic with the goToVer was confused, BTW, and that might've been the problem you were having. You were setting it in the inner loop, but from that point on it was always set. I recommend not doing things like that as it is quite difficult to debug (there are cases where it can make sense, but it doesn't look like you're doing them) and instead sticking to regular grids, but they can work. I'm guessing that you are missing a reset of the variable to 0 at some point in the outer loop, probably just before the inner loop starts.

Related

Does TCL containg built in functions of type get_bits and set_bits?

The get_bits will return specific bits of a value and set_bits will set specific bits of a value to a specified value. Does TCL contain such functions built in or should they be written by the user?
The binary scan command does come close to the get_bits function but is not the same thing.
There's no specific function for getting or setting a particular bit. We can make them.
proc get_bit {value bit} {
expr {($value & (1 << $bit)) != 0}
}
proc set_bit {varName bit {value 1}} {
upvar 1 $varName var
if {$value} {
set var [expr {$var | (1 << $bit)}]
} else {
set var [expr {$var & ~(1 << $bit)}]
}
}
Those will work with integer values of any width; you're not restricted to 32 bits or 64 bits.
# Lots of bits!
set x 123456789012345678901234567890
# Fetch a particular bit
puts [get_bit $x 17]
# Set a bit to 1
set_bit x 78
puts "x = $x"
# Set a bit to 0
set_bit x 75 0
puts "x = $x"

finding difference between list elements in Tcl

I am a beginner in using Tcl. I am using it as VMD (molecular visualization) software uses it as a scripting language.
I have a list of co-ordinates of atom positions for a protein like: {{1 2 3} {7 9 13}, ...} I have a separate list of the same length with different positions say: {{3 5 2} {7 3 8}, ...}.
VMD has an inbuilt vecsub function which can subtract {1 2 3} and {3 5 2} to give {-2 -3 1}. I have written a foreach loop to iterate on the entire list and calculate vecsub.
My code is as follows:\
set sel1 [atomselect 0 "protein"] # selecting protein1
set sel2 [atomselect 1 "protein"] # selecting protein2
# create a list of same length as protein to store values
# $sel1 get index returns length of protein
foreach i [$sel1 get index] {
lappend x 0
}
# veclength2 returns square of vector length
# $sel1 get {x y z} returns a position list as described earlier
foreach i [$sel1 get index] {
lset x $i [expr [veclength2 [vecsub [lindex [$sel1 get {x y z}] $i] [lindex [$sel2 get {x y z}] $i]]]]
}
Is there another way to do this in Tcl? Similar to python array subtraction perhaps?
I would try this, but it's just a guess
set x [lmap p1 [$sel1 get {x y z}] p2 [$sel2 get {x y z}] {
expr [veclength2 [vecsub $p1 $p2]]
}]
With this, there's no need to pre-declare $x

a formula with natural logarithm in tcl

This formula will be coded in tcl.
Y= Intercept + Slope1*(X – X0) + (Slope2 – Slope1)*Delta*ln(1+exp((X-X0)/Delta))
I searched that ln() in this formula can be coded using log() in tcl.
However, I cannot get the correct output in tcl.
Here is what I coded, could you please take a look? Any comments? Thank you.
set Intercept 0.7416
set Slope1 52.42
set x0 0.01491
set Slope2 0.2533
set Delta 0.002275
set y_frac [expr {
$Intercept + $Slope1*($x/$tend - $x0/$tend)
+ ($Slope2-$Slope1) * $Delta * log10(1.0 + exp(($x/$tend - $x0/$tend)/$Delta))
}]
set y [expr {$y_frac *100.0}] ​
The log() function computes the natural logarithm of its argument (just as the exp() function is its inverse, computing ex). That means your expression becomes (with the simplest of transformations) just:
set Y [expr {
$Intercept + $Slope1*($X – $X0) + ($Slope2 – $Slope1)*$Delta*log(1+exp(($X-$X0)/$Delta))
}]
I'd refactor the expression a little, as deltas are natural things to extract:
set dX [expr { $X - $X0 }]
set dSlope [expr { $Slope2 - $Slope1 }]
set Y [expr { $Intercept + $Slope1*$dX + $dSlope*$Delta*log(1+exp($dX/$Delta)) }]
At this point, it's probably easier to define a procedure to encapsulate this.
proc computeY {y} {
global Intercept Slope1 Slope2 Delta x0
set dX [expr { $x - $x0 }]
set dSlope [expr { $Slope2 - $Slope1 }]
set Y [expr { $Intercept + $Slope1*$dX + $dSlope*$Delta*log(1+exp($dX/$Delta)) }]
return [expr { $Y * 100.0 }]; # Your final rescaling
}

efficient grid lookup by coordinate in Tcl

I'm trying to implement a simple grid lookup in Tcl. You can think of the grid items as boxes within a grid. Something like the following.
I have the x and y coordinates of the boundaries (left, right , top bottom) of each of the blue boxes within the coordinate space shown in a dictionary called boxcoordinates
given an arbitrary X and Y point, what is the most efficient way to identify which (if any) of the blue boxes are intercepted by the X,Y pair?
I'm currently doing a check for each box, on the conditions where Left < X < Right and Bottom < Y < Top to see which box satisfies those conditions.
Something like
foreach boxid [dict keys boxcoordinates] {
if {([dict get $boxcoordinates $boxid LEFT] < $x) && ([dict get $boxcoordinates $boxid RIGHT] > $x) && ([dict get $boxcoordinates $boxid BOTTOM] < $y) && ([dict get $boxcoordinates $boxid TOP] > $y)} {
set selected $boxid
break
}
}
But that seems very inefficient since there are a lot of boxes to scan through. Is there a more efficient way to do this?
If you sort the coordinate list in a regular fashion, you can do a binary search to find the coordinates you are looking for. The example below only has 9 entries, but should give you the idea. The coordinates used in this exampled are ordered as x1, x2, y1, y2.
global vars
proc init { } {
global vars
set vars(d) {
0 {1 4 1 4}
1 {1 4 6 8}
2 {1 4 10 12}
3 {6 8 1 4}
4 {6 8 6 8}
5 {6 8 10 12}
6 {10 12 1 4}
7 {10 12 6 8}
8 {10 12 10 12}
}
}
proc lCompare { a b } {
lassign $a ax1 ax2 ay1 ay2
lassign $b bx1 bx2 by1 by2
if { $bx1 < $ax1 } {
return -1
} elseif { $bx2 > $ax2 } {
return 1
} elseif { $by1 < $ay1 } {
return -1
} elseif { $by2 > $ay2 } {
return 1
}
return 0
}
proc bsearch { mx my } {
global vars
set target [list $mx $mx $my $my]
set low 0
set high [expr {[dict size $vars(d)]-1}]
while { $low <= $high } {
set mid [expr {($low+$high)/2}] ; # integer division
set lrc [lCompare [dict get $vars(d) $mid] $target]
if { $lrc > 0 } {
set low [expr {$mid+1}]
} elseif { $lrc < 0 } {
set high [expr {$mid-1}]
} else {
return $mid
}
}
return -1
}
init
set idx [bsearch 3 10]
puts "A:$idx"
set idx [bsearch 10 10]
puts "B:$idx"
set idx [bsearch 3 3]
puts "C:$idx"
set idx [bsearch 5 9]
puts "D:$idx"
Output:
bll-tecra:bll$ tclsh z.tcl
A:2
B:8
C:0
D:-1
References: wikipedia: Binary Search Algorithm

How can I calculate distance between two nodes by TOA and TDOA in NS2?

I'm a beginner in ns2. I have two fixed nodes that periodically send a message in the network. These two nodes send their periodic messages simultaneously. Moreover, I have some mobile nodes in my network. I want to calculate distance between a mobile node and two fixed nodes preferably by TOA or TDOA method (we don't have mobile node position and nodes aren't equipped to GPS). I don't know how can I calculate TOA or TDOA between these nodes in NS2 with considering to estimating accurate distance. How can I do it?
It's emergency for me please help me.
# Distance calculation
set nbr [open distance w]
puts $nbr "\t\t\t\t\t Detail of positions"
puts $nbr "\t~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"
puts $nbr "\tNode\t\tNb node\t\tNode-Xpos\tNode-Ypos\tNb-Xpos\t\tNb-Ypos\t\tDistance(d)"
puts $nbr "\t~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"
close $nbr
proc distance { n1 n2 nd1 nd2} {
global c n bnd src dst j0 j1
set a 0
set nbr [open distance a]
set x1 [expr int([$n1 set X_])]
set y1 [expr int([$n1 set Y_])]
set x2 [expr int([$n2 set X_])]
set y2 [expr int([$n2 set Y_])]
set d [expr int(sqrt(pow(($x2-$x1),2)+pow(($y2-$y1),2)))]
puts $nbr "\t$nd1\t\t$nd2\t\t$x1\t\t$y1\t\t$x2\t\t$y2\t\t$d"
close $nbr
}
U can use above function to print distance node's of all nodes in ns2.
call the function"distance" to print neighbor list
for example,
for {set i 0} {$i <$val(nn)} {incr i} {
for {set j 0} {$j <$val(nn)} {incr j} {
$ns at 1.002 "distance $n($i) $n($j) $i $j"
}
}
the above lines will print distance between all nodes at time 1.002
here val(nn) denotes number of nodes.
RSS calculations are less accurate as compared to time based positioning algorithms and angle of arrival needs more processing and complex mathematical manipulations there its good to used Time of arrival or time difference of arrival for the distance calculation. But they need extra hardware implementations.