简体   繁体   中英

Use a list as arg in a TCL procedure

I am a beginner in TCL. I am trying to use as the argument of a procedure a list computed beforehand. And I get as a result "invalid command name". here is the code, where am I wrong ?

proc matrix_to_quaternion { matrix_VMD } {
  set q1 [expr { 0.5*sqrt(1+[lindex $matrix_VMD 0 0]+[lindex $matrix_VMD 1 1]+[lindex $matrix_VMD 2 2]) }]
  set q2 [expr (1/(4*$q1))*([lindex $matrix_VMD 2 1]-[lindex $matrix_VMD 1 2])]
  set q3 [expr (1/(4*$q1))*([lindex $matrix_VMD 0 2]-[lindex $matrix_VMD 2 0])]
  set q4 [expr (1/(4*$q1))*([lindex $matrix_VMD 1 0]-[lindex $matrix_VMD 0 1])]
  puts q1 q2 q3 q4
  }

To return a compound value (as opposed to just printing it out) you should use something like this:

return [list $q1 $q2 $q3 $q4]

We use $ because we want the values in those local variables, not the names of them. You should also put { braces } around all your expressions as that prevents double-interpolation and allows Tcl to compile your code to go much faster. Here's the correct version:

proc matrix_to_quaternion { matrix_VMD } {
    set q1 [expr { 0.5*sqrt(1+[lindex $matrix_VMD 0 0]+[lindex $matrix_VMD 1 1]+[lindex $matrix_VMD 2 2]) }]
    set q2 [expr { (1/(4*$q1))*([lindex $matrix_VMD 2 1]-[lindex $matrix_VMD 1 2]) }]
    set q3 [expr { (1/(4*$q1))*([lindex $matrix_VMD 0 2]-[lindex $matrix_VMD 2 0]) }]
    set q4 [expr { (1/(4*$q1))*([lindex $matrix_VMD 1 0]-[lindex $matrix_VMD 0 1]) }]
    return [list $q1 $q2 $q3 $q4]
}

Apart from that, your code fragment is unlikely to produce that error message with sane input data. Not unless you called your code using a code sequence something like this:

[matrix_to_quaternion $someInput]

In this case, you'd be using the result of the call as a word; the first word of a command is the name of the command, and what you're returning (and what you should return in the correct code) is not the name of a command. That makes Tcl complain at you. Tcl's usually careful to try to give you good information about what it thinks is wrong (not just “unknown command” but “unknown command "BLAH" ”) which can help a lot.


The code you've given us confuses me a little though. It's less clear than we might hope. Here's what I'd use (same algorithm) since I'm also aware of the lassign command…

proc matrix_to_quaternion { matrix_VMD } {
    lassign $matrix_VMD m0 m1 m2
    set q1 [expr { 0.5*sqrt(1 + [lindex $m0 0] + [lindex $m1 1] + [lindex $m2 2]) }]
    set q2 [expr { 0.25/$q1 * ([lindex $m2 1] - [lindex $m1 2]) }]
    set q3 [expr { 0.25/$q1 * ([lindex $m0 2] - [lindex $m2 0]) }]
    set q4 [expr { 0.25/$q1 * ([lindex $m1 0] - [lindex $m0 1]) }]
    return [list $q1 $q2 $q3 $q4]
}

It's faster too when I test (it takes about 60% of the time of the version earlier in my answer, and is about 8 times faster than yours after the correction to return the list; bracing expressions makes a big difference ), but my concern was entirely to do with making the code clearer.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM