如何在TCL中对坐标求和
How to sum coordinates in TCL
我有一个包含 x、y、z 坐标的数据文件 (*.dat)。如下:
{26.3612117767334 40.19668960571289 54.13957977294922}
{27.351043701171875 40.57518768310547 54.05387496948242}
{29.48208999633789 42.08218765258789 56.42238235473633}
对于这个文件,我需要进行如下数学运算:
Xi + (Xf-Xi/4) ; Yi + (Yf-Yi/4) ; Zi + (Zf-Zi/4)
其中“i”是初始位置,“f”是最终位置,表示 Xi、Yi、Zi 是第一行的数据,Xf、Yf、Zf 是第二行的数据。
我需要对循环中的所有行进行这些计算,然后存储在一个单独的文件中,但我不知道如何在 TCL 中进行。预先感谢您的帮助。
因为你的文件的内容可以被视为一堆 tcl 列表,每行一个(所以基本上是一个列表的列表),解析它非常简单。
类似于:
set f [open file.dat]
set coords [read -nonewline $f]
close $f
for {set i 0} {$i < [llength $coords] - 1} {incr i} {
lassign [lindex $coords $i] xi yi zi
lassign [lindex $coords $i+1] xf yf zf
set xn [expr {$xi + ($xf - $xi/4.0)}]
set yn [expr {$yi + ($yf - $yi/4.0)}]
set zn [expr {$zi + ($zf - $zi/4.0)}]
puts "{$xn $yn $zn}"
}
这会跳过将最后一行作为初始坐标集的处理,因为没有下一组坐标。
我提出了另一种方法,它使用 lrange
来选择参与的子列表的重叠范围(这样我们就可以处理它们 element-wise),然后 lmap
应用相同的方法变换表达式到各个坐标轴。
# Same read-in code as Shawn's answer; it's the easiest way
set f [open file.dat]
set coords [read -nonewline $f]
close $f
foreach Ci [lrange $coords 0 end-1] Cf [lrange $coords 1 end] {
# I often like to put expressions on their own line for clarity
puts [list [lmap _i $Ci _f $Cf {expr {
$_i + ($_f - $_i/4.0)
}}]]
}
(其中的包装 list
调用将 lmap
的结果括起来。)
这是编写数学函数的好机会:
proc tcl::mathfunc::f {ai af} {
expr {$ai * 0.75 + $af}
}
proc transform {file} {
set fh [open $file]
# read the first line, aka the initial "previous line"
gets $fh line
scan $line {{%f %f %f}} xi yi zi
# process the rest of the file
while {[gets $fh line] != -1} {
scan $line {{%f %f %f}} xf yf zf
puts "{[expr {f($xi, $xf)}] [expr {f($yi, $yf)}] [expr {f($zi, $zf)}]}"
lassign [list $xf $yf $zf] xi yi zi
}
close $fh
}
transform file.dat
产出
{47.121952533721924 70.72270488739014 94.65855979919434]}
{49.9953727722168 72.51357841491699 96.96278858184814]}
我有一个包含 x、y、z 坐标的数据文件 (*.dat)。如下:
{26.3612117767334 40.19668960571289 54.13957977294922}
{27.351043701171875 40.57518768310547 54.05387496948242}
{29.48208999633789 42.08218765258789 56.42238235473633}
对于这个文件,我需要进行如下数学运算:
Xi + (Xf-Xi/4) ; Yi + (Yf-Yi/4) ; Zi + (Zf-Zi/4)
其中“i”是初始位置,“f”是最终位置,表示 Xi、Yi、Zi 是第一行的数据,Xf、Yf、Zf 是第二行的数据。
我需要对循环中的所有行进行这些计算,然后存储在一个单独的文件中,但我不知道如何在 TCL 中进行。预先感谢您的帮助。
因为你的文件的内容可以被视为一堆 tcl 列表,每行一个(所以基本上是一个列表的列表),解析它非常简单。
类似于:
set f [open file.dat]
set coords [read -nonewline $f]
close $f
for {set i 0} {$i < [llength $coords] - 1} {incr i} {
lassign [lindex $coords $i] xi yi zi
lassign [lindex $coords $i+1] xf yf zf
set xn [expr {$xi + ($xf - $xi/4.0)}]
set yn [expr {$yi + ($yf - $yi/4.0)}]
set zn [expr {$zi + ($zf - $zi/4.0)}]
puts "{$xn $yn $zn}"
}
这会跳过将最后一行作为初始坐标集的处理,因为没有下一组坐标。
我提出了另一种方法,它使用 lrange
来选择参与的子列表的重叠范围(这样我们就可以处理它们 element-wise),然后 lmap
应用相同的方法变换表达式到各个坐标轴。
# Same read-in code as Shawn's answer; it's the easiest way
set f [open file.dat]
set coords [read -nonewline $f]
close $f
foreach Ci [lrange $coords 0 end-1] Cf [lrange $coords 1 end] {
# I often like to put expressions on their own line for clarity
puts [list [lmap _i $Ci _f $Cf {expr {
$_i + ($_f - $_i/4.0)
}}]]
}
(其中的包装 list
调用将 lmap
的结果括起来。)
这是编写数学函数的好机会:
proc tcl::mathfunc::f {ai af} {
expr {$ai * 0.75 + $af}
}
proc transform {file} {
set fh [open $file]
# read the first line, aka the initial "previous line"
gets $fh line
scan $line {{%f %f %f}} xi yi zi
# process the rest of the file
while {[gets $fh line] != -1} {
scan $line {{%f %f %f}} xf yf zf
puts "{[expr {f($xi, $xf)}] [expr {f($yi, $yf)}] [expr {f($zi, $zf)}]}"
lassign [list $xf $yf $zf] xi yi zi
}
close $fh
}
transform file.dat
产出
{47.121952533721924 70.72270488739014 94.65855979919434]}
{49.9953727722168 72.51357841491699 96.96278858184814]}