[KPV] - Why are manhole covers round? One answer is that they are the simplest shape which won't fall in on themselves. [Bryan Oakley] prefers the answer "because manholes are round". Any other shap just wouldn't work. But what about other "non-simplest" shapes that meet this criteria? This program draws one family of those non-simplest shapes. To visualize what the family of shapes looks like, take an odd-side polygon, place on point of a compass on a vertex, the other on an opposite vertex, and draw the arc to the other opposite vertex. Repeat for all vertices. ---- ##+########################################################################## # # Manhole.tcl # # Draws N-sided manhole covers # by Keith Vetter # # Revisions: # KPV Mar 22, 1996 - initial revision # KPV Sep 22, 2002 - cleaned up for 8+ # proc Init {} { global sz set sz(n) 3 ;# Number of sides set sz(s) 400 ;# Size of canvas set sz(cx) [expr {$sz(s) / 2}] ;# Canvas center point set sz(cy) $sz(cx) set sz(r) [expr {$sz(cx) * 3 / 4}] ;# Radius set sz(rot) 0 ;# How much to rotate by set sz(anim) 0 ;# No animation yet set sz(after) "" ;# No after yet set sz(a) 0 ;# Interior angle to fill in set sz(colored) 1 ;# Colored or solid set colors "cyan green magenta blue deepskyblue hotpink aquamarine " append colors $colors for {set i 0} {$i < 13} {incr i} { set sz($i) [lindex $colors $i] } canvas .c -width $sz(s) -height $sz(s) -bd 2 -relief raised .c config -bg black .c create oval [expr {$sz(cx)-$sz(r)}] [expr {$sz(cy)-$sz(r)}] \ [expr {$sz(cx)+$sz(r)}] [expr {$sz(cy)+$sz(r)}] -tag circle \ -fill [lindex [.c config -bg] 3] button .anim -text Animate -command {Animate 1} label .l -text "Sides: $sz(n)" scale .s -orient h -showvalue 0 -from 0 -to 5 -command MyScale pack .c -side top pack .anim -side right -expand 1 pack .s .l -side bottom -expand 1 wm resizable . 0 0 } ##+########################################################################## # # ngon # # Compute the vertices for a n-gon # proc ngon {n angle} { global v sz catch {unset v} set delta [expr {2*3.14159 / $n}] ;# Angle of vertices on circle set sz(delta) [expr {360.0 / $n}] set sz(a) [expr {180.0 / $n}] ;# Interior angle to fill in set angle [expr {$angle * 3.14159 / 180}] for {set i 0} {$i < $n} {incr i} { set a [expr {$angle + ($i*$delta)}] ;# Angle in radians set v($i,x) [expr {$sz(cx) + $sz(r) * cos($a)}] set v($i,y) [expr {$sz(cy) + $sz(r) * sin($a)}] set i2 [expr {$i + $n}] set v($i2,x) $v($i,x) set v($i2,y) $v($i,y) lappend vertices $v($i,x) $v($i,y) } set n2 [expr {$n/2}] ;# Opposite angle set x [expr {$v(0,x) - $v($n2,x)}] set y [expr {$v(0,y) - $v($n2,y)}] set sz(d) [expr {sqrt($x*$x + $y*$y)}] ;# Length of opposite side for {set i 0} {$i < $n} {incr i} { set v($i,bb) [list [expr {$v($i,x)-$sz(d)}] [expr {$v($i,y)+$sz(d)}] \ [expr {$v($i,x)+$sz(d)}] [expr {$v($i,y)-$sz(d)}]] set i2 [expr {$i + 1}] set n2 [expr {($i + ($sz(n) / 2) + 1) % $sz(n)}] set xy [list $sz(cx) $sz(cy) $v($i,x) $v($i,y) $v($i2,x) $v($i2,y)] .c create poly $xy -fill $sz($n2) -outline $sz($n2) \ -tag {poly poly_$i} } return $vertices } ##+########################################################################## # # DrawPie # # Draws a single pie slice for vertex which. # proc DrawPie {which} { global v sz if {$which == 0} { set n2 [expr {$which + ($sz(n) / 2) + 1}] ;# Opposite angle set x [expr {$v($n2,x) - $v($which,x)}] set y [expr {-($v($n2,y) - $v($which,y))}] set a [expr {atan2( $y, $x) * 180 / 3.14159}] set sz(atan) $a } else { set a [set sz(atan) [expr {$sz(atan) - $sz(delta)}]] } eval .c create arc $v($which,bb) -start $a -extent $sz(a) -style chord \ -fill $sz($which) -outline $sz($which) -tag {{pie pie_$which}} } ##+########################################################################## # # DrawIt # # Draws the n-side manhole cover w/ sz(n) sides at angle sz(rot). # proc DrawIt {} { global sz .c delete pie poly ngon $sz(n) $sz(rot) ;# Get vertices for this angle for {set i 0} {$i < $sz(n)} {incr i} { ;# Draw the pie slices DrawPie $i } update } ##+########################################################################## # # Animate # # Draw the figure rotated by a small amount, then if animation is on, # it schedules itself to be run again in the near future. # proc Animate {toggle} { global sz if {$toggle} { ;# On/off toggle set sz(anim) [expr {1 - $sz(anim)}] ;# Toggle to flag if {$sz(anim)} {set relief sunken} {set relief raised} .anim config -relief $relief } if $sz(anim) { ;# Are we animating??? incr sz(rot) 3 ;# Rotate a bit DrawIt ;# Redraw it after 1 {Animate 0} ;# Rerun in the future } } ##+########################################################################## # # MyScale # # Command called when scale gets a new value # proc MyScale {v} { set ::sz(n) [expr {$v*2+3}] .l config -text "Sides: $::sz(n)" DrawIt } ################################################################ ################################################################ ################################################################ Init DrawIt ---- [Category Graphics]