Вопрос

I am new to Tcl arrays. My question is as follows.

I have a rectangle box with two rows R1 and R2. Each of these rows has 8 different values. I want to return these 16 values (x and y coordinates) either in a text file or as an list output from a proc. I read some earlier posts about Tcl proc cannot output an array unless we use dict. So, I will try to draw a picture so u can understand my question better.

R1  x1y1    x2y2        ... x8,y8
R2  x9,y9       ...     x16, y16

Expected output when I run the proc either on command prompt or in a file with dummy values as an example

$>    (1,2)  (2,3) (3,4) ....... (7,8)
      (9,10) (10,11) ......... (15,16)

So this is what I tried and I am getting the results that I need. But this is hardcoded for two rows. I want to make it able to detect how many rows are there and then accordingly output the number of rows.

proc getPointList {rect_boundary rowOffset colOffset rowIncr colIncr } {
 set cordlist $rect_boundary

 set xl  [lindex $cordlist 0]
 set yl  [lindex $cordlist 1]
 set xh  [lindex $cordlist 2]      
 set yh  [lindex $cordlist 3]

 set list "" ;

 for {set y [expr {$yh - $colOffset}]} {$y >= [expr {$yl + $colOffset}]} { incr y $colIncr } {

    for {set x [expr {$xl + $rowOffset}]} {$x <= [expr {$xh - $rowOffset}]} { incr x $rowIncr } {

            set list "$list $x $y" ;
            puts "Value of x is: $x"; puts "\t Value of y is: $y" ;  
        } 
 }
return $list  
}

set rect_boundary {10 15 100 40}     # xl yl xh yh
set rowOffset 5
set colOffset 5
set rowIncr 10
set colIncr 15

Some Logic I need to implement in this code based on yh-yl and xh-xl to calculate height and width of rectangle and accordingly output rows

Command to call the proc

$> getPointList $rect_boundary $rowOffset $colOffset $rowIncr $colIncr

Just for your understanding there are eight x,y points inside the rectangle on a particular row. x offset is the first x point on a row from the left or roght boundary, thereafter all the points are separated by an increment value which I call rowIncr. Same holds true for column.

Expected output : This is what the above code does but it is hardcoded for two rows. I want to increase and implement the logic if the rows and column are variable.

$>  R1:  (15 40) (25 40) (35 40) (45 40) (55 40) (65 40) (75 40) (85 40) (95 40)
    R2:  (15 15) (25 15) (35 15) (45 15) (55 15) (65 15) (75 15) (85 15) (95 15)

Rectangle Image for better clarity as this thing wont let me update pictures

__________________________________________________________________________ (100,40)
|                       |- 5                                              |
|   .          .        .       .        .       .        .        .      |
|                               |- 15                                     |
|-5-.          . --10---.       .        .       .        .        .      |
|                                                                         |
|_________________________________________________________________________|
(10,15)    

For Jerry:

Case1  rowIncr 10 colIncr 20
__________________________________________________________________________ (80,40)
|                       |- 5                                              |
|   .          .        .       .        .       .        .        .      |
|                               |- 20                                     |
|-5-.          . --10---.       .        .       .        .        .      |
|                                                                         |
|_________________________________________________________________________|
(10,10)

Case2   rowIncr 20 colIncr 35
_________________________________________________ (100,70)
|                       |- 5                     |
|   .          .        .       .        .       |
|                               |- 35            |
|-5-.          . --20---.       .        .       |
|              |                         |-5     |
|________________________________________________|
(10,25)

and so on ...

Это было полезно?

Решение

Okay, I think I now understand what you were trying to do, and I think that your proc would have worked for any number of rows after some fixing:

set output [open "output.txt" w]

proc getPointList {rect_boundary rowOffset colOffset plist} {
    global output

    set cordlist $rect_boundary
    set xl  [lindex $cordlist 0]
    set yl  [lindex $cordlist 1]
    set xh  [lindex $cordlist 2]      
    set yh  [lindex $cordlist 3]

    set xpoints [llength [lindex $plist 0]]
    set ypoints [llength $plist]
    set rowIncr [expr {($xh-$xl-2*$rowOffset)/($xpoints-1)}]
    set colIncr [expr {($yh-$yl-2*$colOffset)/($ypoints-1)}]

    set count 0
    set list ""

    for {set y [expr {$yh - $colOffset}]} {$y >= [expr {$yl + $colOffset}]} {incr y -$colIncr} {

        for {set x [expr {$xl + $rowOffset}]} {$x <= [expr {$xh - $rowOffset}]} {incr x $rowIncr} {
            lappend list "($x,$y)"
        }
        incr count
        puts $output "R$count: [join $list " "]"
        set list ""
    }
}

set plist {{A B C D E} {A B C D E} {A B C D E} {A B C D E} {A B C D E}}
set rect_boundary {0 0 100 100}
set rowOffset 0
set colOffset 0

getPointList $rect_boundary $rowOffset $colOffset $plist

close $output

I changed the colIncr to put more rows.

In the first loop, I used incr y -$colIncr because this is actually a decrement if you start with the higher y coordinate.

I also changed the output structure to match the one you were looking for. The above snippet returns the coordinates:

R1: (0,100) (25,100) (50,100) (75,100) (100,100) 
R2: (0,75) (25,75) (50,75) (75,75) (100,75) 
R3: (0,50) (25,50) (50,50) (75,50) (100,50) 
R4: (0,25) (25,25) (50,25) (75,25) (100,25) 
R5: (0,0) (25,0) (50,0) (75,0) (100,0)

EDIT: Added variable offsets, blank final row and variable columns per row.

proc getPointList {rect_boundary uRowOffset lRowOffset uColOffset lColOffset plist} {
    set cordlist $rect_boundary
    set xl  [lindex $cordlist 0]
    set yl  [lindex $cordlist 1]
    set xh  [lindex $cordlist 2]      
    set yh  [lindex $cordlist 3]

    set xpoints 0
    foreach r $plist {
        if {[llength $r] > $xpoints} {set xpoints [llength $r]}
    }

    set ypoints [llength $plist]
    set rowIncr [expr {($xh-$xl-$lRowOffset-$uRowOffset)/($xpoints-1)}]
    set colIncr [expr {($yh-$yl-$lColOffset-$uColOffset)/$ypoints}]

    set count 0
    set list ""

    for {set y [expr {$yh - $uColOffset}]} {$y >= [expr {$yl + $lColOffset}]} {incr y -$colIncr} {
        set x [expr {$xl + $lRowOffset}]
        foreach n [lindex $plist $count] {
            lappend list $x $y
            incr x $rowIncr
        }
        incr count
        if {$count == $ypoints} {return $list}
    }
}

set plist {{A B C D X} {E F G H} {I K L} {M N}}
set qlist 1
foreach n $plist {
    set pattern$plist $n
    incr qlist
}

set rect_boundary {0 0 100 100}
set upperRowOffset 0
set lowerRowOffset 0
set upperColOffset 0
set lowerColOffset 0

set pointList [getPointList $rect_boundary $upperRowOffset $lowerRowOffset $upperColOffset $lowerColOffset $plist]

set count 1
foreach sub_list $plist {
    foreach n $sub_list {
        set pattern$count $n
        incr count
    }
}

set count 1
foreach {a b} $pointList {
    set text "pattern$count"
    puts "command -point $a,$b -text [set $text]"
    incr count 
}

Другие советы

It is up to you how to organize the nested lists. In simplest form, return a single list:

set result {x1 y1 x2 y2 ... x16 y16}

Or, you can have a list of two rows:

set result {
    {x1 y1 x2 y2 ... x8 y8}
    {x9 y9 x10 y10 ... x16 y16}
}

Or, more complex: each pair is a sub-list:

set result {
    { {x1 y1} {x2 y2} ... }
    { {x9 y9} {x10 y10} ... }
}

I don't think you want to use array in this case. FYI, an "array" in TCL is equivalent to a hash in other languages.

Well, with Tcl 8.6

proc parsedata {input} {
    lmap a [split $input \n] {
        lmap b [split $b \t] {
           regexp {x(\d+),?\s*y(\d+)} $b -> c d
           list $c $d
        }
    }
}

Now you can process the data, for example:

foreach line [parsedata $input] {
    puts [lmap pair $line {
        expr {"([lindex $line 0],[linedex $line 1])"}
    }
}
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top