package re Tk proc wheel {c x y r args} { global g array set opt {-color red -spokes 24 -pivot 0 -tag {}} array set opt $args set y0 [expr $y-$r] $c create oval [expr $x-$r] [expr $y0-$r] [expr $x+$r] [expr $y0+$r] \ -outline white set r1 [expr $r-2] set col $opt(-color) set it [$c create oval [expr $x-$r1] [expr $y0-$r1] [expr $x+$r1] [expr $y0+$r1] \ -outline $col -width 2] lappend g(wheels) $it set g($it,spokes) $opt(-spokes) set g($it,r) $r1 set g($it,x) $x set g($it,y) $y0 set g(alpha) 0. set g(-color) $opt(-color) drawSpokes $c $it if $opt(-pivot) { set deg2arc [expr {atan(1.0)*8/360.}] set rp [expr {$r1*$opt(-pivot)}] set xp [expr {$x-$rp*cos($deg2arc*$::g(alpha))}] set yp [expr {$y0-$rp*sin($deg2arc*$::g(alpha))}] set pivot [$c create rect $xp $yp \ [expr {$xp+1}] [expr {$yp+1}] -fill $opt(-color) \ -tag [list $opt(-tag) pivot]] set g($it,pivot) [list $pivot $opt(-pivot)] $c create arc [expr {$x-$r1}] [expr {$y0-$r1}]\ [expr {$x+$r1}] [expr {$y0+$r1}] \ -style chord -fill $g(-color) -start 310\ -extent 80 -tag counterweight } set rh [expr $r/12.] $c create oval [expr $x-$rh] [expr $y0-$rh] [expr $x+$rh] [expr $y0+$rh] \ -fill white -tag hub } proc turn {c deg} { global g set g(alpha) [expr {round($g(alpha)+360-$deg)%360}] foreach i [$c find withtag counterweight] { $c itemconfig $i -start [expr 310-$g(alpha)] } $c delete spoke foreach i $g(wheels) { drawSpokes $c $i } $c raise hub set xp0 [expr {105+15*sin(($g(alpha)-90)*atan(1.0)*8/360)}] $c delete piston eval $c coords p0 $xp0 120 [expr {$xp0+2}] 122 ;#CW $c create line 90 121 $xp0 121 -width 2 -fill white -tag piston ;#CW drawRod $c p0 p1 p2 p3 $c raise p0 foreach i [$c find withtag smoke] { if {[lindex [$c bbox $i] 3]<0} { $c delete $i } else { $c move $i [expr {rand()*$::g(speed)/3.}] [expr {rand()*2-2}] } } set t [eval $c create oval [$c bbox chimney] -fill white -outline white -tag smoke] $c move $t 0 -10 $c lower smoke } proc drawSpokes {c item} { global g set nspokes $g($item,spokes) set delta [expr 360./$nspokes] set alpha $g(alpha) set r $g($item,r) set x $g($item,x) set y $g($item,y) set deg2arc [expr {atan(1.0)*8/360.}] for {set i 0} {$i<$nspokes} {incr i} { set x1 [expr {$x+cos($deg2arc*$alpha)*$r}] set y1 [expr {$y+sin($deg2arc*$alpha)*$r}] $c create line $x $y $x1 $y1 -fill $g(-color) -tag spoke set alpha [expr {$alpha+$delta}] } if [info exists g($item,pivot)] { foreach {item perc} $g($item,pivot) break set rp [expr {$r*$perc}] set xp [expr {$x-$rp*cos($deg2arc*$::g(alpha))}] set yp [expr {$y-$rp*sin($deg2arc*$::g(alpha))}] $c coords $item [expr {$xp}] [expr {$yp}] [expr {$xp+1}] [expr {$yp+1}] } } proc drawRod {c p0 p1 p2 p3} { $c delete rod eval $c create rect [$c bbox $p1 $p3] -fill white -tag rod eval $c create line [lrange [$c bbox $p0] 0 1] \ [lrange [$c bbox $p2] 0 1] -width 3 -fill white -tag rod $c raise rod $c raise pivot } set c [canvas .c -width 600 -height 160 -background lightblue] pack $c bind $c <1> {incr ::g(speed) 6; speed $c} ;# throttle bind $c <3> { foreach i [after info] {after cancel $i} set g(speed) 0 ;# emergency brake } proc speed {c} { turn $c $::g(speed) foreach i [after info] {after cancel $i} after 140 speed $c } $c delete all catch {unset g} $c create rect 32 115 360 125 -fill black ;# frame $c create rect 22 118 32 122 -fill grey30 ;# buffer $c create line 22 115 22 125 $c create poly 60 95 40 115 50 115 70 95 -fill black $c create rect 60 45 310 95 -fill grey25 ;# boiler $c create oval 55 50 65 90 -fill black ;# smokebox $c create rect 70 32 85 50 -fill black -tag chimney $c create rect 40 52 90 75 -fill black ;# wind diverter $c create oval 130 36 150 52 -fill black ;# dome $c create rect 195 35 215 50 -fill black ;# sandbox $c create oval 260 36 280 52 -fill black ;# dome $c create rect 65 100 90 135 -fill black ;# cylinder $c create rect 90 120 92 122 -fill red -tag p0 ;# crossbar $c create rect 72 87 82 100 -fill black ;# steam tube $c create rect 310 40 370 115 -fill black ;# cab $c create rect 310 32 390 42 -fill grey30 ;# cab roof $c create text 338 82 -text "01 234" -fill gold -font {Times 7} $c create rect 318 48 333 66 -fill white ;# cab window #1 $c create rect 338 48 355 66 -fill white ;# cab window #2 wheel $c 50 150 13 -spokes 12 wheel $c 105 150 13 -spokes 12 wheel $c 150 150 30 -pivot 0.5 -tag p1 wheel $c 215 150 30 -pivot 0.5 -tag p2 wheel $c 280 150 30 -pivot 0.5 -tag p3 drawRod $c p0 p1 p2 p3 wheel $c 340 150 16 -spokes 12 $c create rect 360 110 380 118 -fill black $c create rect 380 65 560 125 -fill black -tag tender $c create rect 560 118 570 122 -fill grey30 ;# buffer $c create line 571 116 571 125 $c create rect 390 45 525 65 -fill black -tag tender wheel $c 395 150 13 -spokes 12 wheel $c 440 150 13 -spokes 12 $c create rect 380 132 456 142 -fill red wheel $c 495 150 13 -spokes 12 wheel $c 540 150 13 -spokes 12 $c create rect 480 132 556 142 -fill red -outline red $c create rect 0 150 600 160 -fill brown ;# earth $c create line 0 150 600 150 -fill grey -width 2 ;# rail set ::g(speed) 4 speed $c