Updated 2012-01-18 18:05:45 by RLE

Richard Suchenwirth 2003-02-15 - Regular polygons are convex shapes whose outline consists of straight segments of equal length, with equal angles between adjoining segments. Regular triangles and squares are simple examples. All corners of a r.p. are on a circle.

Talking of circles, one bug of the Tk 8.4a2/WinCE port for the iPAQ is that oval canvas items (which in an enclosing square make circles) are not implemented, making porting things like Nine Men Morris or trains3.tcl a bit hard. I have no doubt that this will be fixed in later releases, but "I want it now"... Hence the following workaround to approximate ovals with polygons - just replace commands like
` \$c create oval 0 0 50 50 ...`

with
` \$c create poly [rp 0 0 50 50] ...`

where the rp function below computes a sequence of polygon points, starting at top center, that approximate an oval on the given enclosing rectangle - regular if it's a square, but also oblongly distorted for non-square rectangles, just as oval objects go. The degree (number of corners) may be specified as fifth argument, but defaults to a number which makes quite nice circles, e.g. 15 for a square side of 30 pixels.

With this workaround in place, I could make a reasonable port of Nine Men Morris to the iPAQ. Dragging the men around is a bit slow in reaction (and risks scratches on the little touch screen), and I had to disable the snap-in-place code, but still it's a nice addition to the games collection ;-)

KPV How about generalizing this to work as a replacement for the arc command? KPV I just went and did it, see Regular Polygons 2.
``` proc rp {x0 y0 x1 y1 {n 0}} {
set xm [expr {(\$x0+\$x1)/2.}]
set ym [expr {(\$y0+\$y1)/2.}]
set rx [expr {\$xm-\$x0}]
set ry [expr {\$ym-\$y0}]
if {\$n==0} {
set n [expr {round((\$rx+\$ry)*0.5)}]
}
set step [expr {atan(1)*8/\$n}]
set res ""
set th [expr {atan(1)*6}] ;#top
for {set i 0} {\$i<\$n} {incr i} {
lappend res \
[expr {\$xm+\$rx*cos(\$th)}] \
[expr {\$ym+\$ry*sin(\$th)}]
set th [expr {\$th+\$step}]
}
set res
}``` Finally, a demo as usual, which shows regular 3..8-gons and a circle approximated as a 15-gon:
``` if {[file tail [info script]]==[file tail \$argv0]} {
pack [canvas .c -width 240 -height 40]
set x 0
set x1 32
foreach n {3 4 5 6 7 8 0} {
.c create poly [rp \$x 2 \$x1 34 \$n] -fill red -outline black
incr x 34; incr x1 34
}
}``` See Traffic lights for another use.

HJG There are bugs hiding in the above calculation of n, which cause divide by zero:
``` # !! Bugs:
.c create poly [rp  250 12  250 12  0] -fill blue -outline black
.c create poly [rp  240 34  272  2  0] -fill cyan -outline black```

The calculation doesn't handle zero radius circles or reversed coordinates
```   if {\$n==0} {
set n [expr {round((abs(\$rx)+abs(\$ry))*0.5)}]  ;# handle reversed coordinates
if {\$n==0} {set n 1}                           ;# handle zero radius circles
}```