3

有一组顶点: [ x1 y1 x2 y2 .. xn yn ]

我想改变这些坐标的中心。所以我尝试:

proc changeCenter { vertices X Y } {
    set myList [list]
    foreach element $vertices {
        lappend myList [expr [lindex $element 0] + $X]
        lappend myList [expr [lindex $element 1] + $Y]
    }

 return $myList 
}

但是它的性能太慢了。

我怎样才能改变上面的代码更有效或者可能需要改变顶点的表示?

4

2 回答 2

5

最简单的方法是支撑你的表达:

proc changeCenter { vertices X Y } {
    set myList [list]
    foreach {x0 y0} $vertices {
        lappend myList [expr {$x0 + $X}]
        lappend myList [expr {$y0 + $Y}]
    }

    return $myList 
}

这有几个好处:

  • 数字不必转换为字符串并返回。
  • 可以编译表达式。
  • 您不会遇到由字符串表示形式引入的令人讨厌的舍入错误。
  • 它可以防止注入您不想执行的代码。

有关更多详细信息,请参阅此 wiki 条目

如果您不使用嵌套列表作为输入,请使用带有多个变量的 foreach。

于 2013-06-24T17:26:41.673 回答
5

您的 changeCenter proc 指示顶点集合是对 ( {{x1 y1} {x2 y2} ...}) 的列表,但您返回的是平面列表:

proc changeCenter { vertices deltaX deltaY } {
    set recentered [list]
    foreach vertex $vertices {
        lassign $vertex x y
        lappend recentered [list [expr {$x + $deltaX}] [expr {$y + $deltaY}]]
    }
    return $recentered 
}

如果顶点确实是一个平面列表 ( {x1 y1 x2 y2 ...}),则一次读取列表 2 个元素:

proc changeCenter { vertices deltaX deltaY } {
    set recentered [list]
    foreach {x y} $vertices {
        lappend recentered [expr {$x + $deltaX}] [expr {$y + $deltaY}]
    }
    return $recentered 
}

我没有对其进行基准测试,但我怀疑就地更新顶点列表可能比附加到新列表更快:

proc changeCenter { vertices deltaX deltaY } {
    for {set i 0} {$i < [llength $vertices]} {incr i} {
        lset vertices $i 0 [expr {[lindex $vertices $i 0] + $deltaX}] 
        lset vertices $i 1 [expr {[lindex $vertices $i 1] + $deltaY}] 
    }
    return $vertices 
}

或者

proc changeCenter { vertices deltaX deltaY } {
    for {set i 0} {$i < [llength $vertices]} {incr i 2} {
        lset vertices $i [expr {[lindex $vertices $i] + $deltaX}] 
        set j [expr {$i + 1}]
        lset vertices $j [expr {[lindex $vertices $j] + $deltaY}] 
    }
    return $vertices
}

取决于上面提到的顶点列表的结构。


按名称传递顶点列表会更快(避免复制数据):

proc changeCenter { verticesName deltaX deltaY } {
    upvar 1 $verticesName v
    for {set i 0} {$i < [llength $v]} {incr i 2} {
        lset v $i [expr {[lindex $v $i] + $deltaX}] 
        set j [expr {$i + 1}]
        lset v $j [expr {[lindex $v $j] + $deltaY}] 
    }
    # no need to return a value
}

并用变量调用它:

changeCenter vertices 1 2
于 2013-06-24T18:08:05.550 回答