File: tk-locomotive.tcl

package info (click to toggle)
nsf 2.4.0-1
  • links: PTS, VCS
  • area: main
  • in suites: sid, trixie
  • size: 13,208 kB
  • sloc: ansic: 32,687; tcl: 10,723; sh: 660; pascal: 176; javascript: 135; lisp: 41; makefile: 24
file content (199 lines) | stat: -rw-r--r-- 6,760 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
#
# Example by <Richard Suchenwirth> 
# https://wiki.tcl-lang.org/1329
#
# - translated from Tcl to XOTcl by gustaf neumann in 2001
# - translated from XOTcl to NX by gustaf neumann in 2010
#
# image::tk-locomotive.png[]
#
# Left mousebutton starts, middle slows down, right stops
#
package require Tk
package require nx
package require nx::trait

nx::Class create Wheel {
  :property x 
  :property y
  :property r
  :property {spokes 24} 
  :property {pivot 0} 
  :property {color red} 
  :property {tag ""}
  
  :public method drawSpokes {} {
    ::nx::var import [:info parent] c alpha
    set delta [expr {360.0 / ${:spokes}}]
    set deg2arc [expr {atan(1.0)*8/360.}]
    for {set i 0} {$i < ${:spokes}} {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 ${:color} -tag spoke
      set alpha [expr {$alpha + $delta}]
    }
    if {[info exists :act_pivot]} {
      lassign [set :act_pivot] item perc
      set rp [expr {${:r} * $perc}]
      set xp [expr {${:x} - $rp * cos($deg2arc * $alpha)}]
      set yp [expr {${:y} - $rp * sin($deg2arc * $alpha)}]
      $c coords $item $xp $yp [expr {$xp + 1}] [expr {$yp + 1}]
    }
  }

  :method init {} {
    ::nx::var import [:info parent] c alpha
    set alpha 0.

    set :y [expr {${:y} - ${:r}}]
    $c create oval \
	[expr {${:x} - ${:r}}] [expr {${:y} - ${:r}}] \
	[expr {${:x} + ${:r}}] [expr {${:y} + ${:r}}] \
	-outline white
    set r1 [expr {${:r}-2}]
    set W [$c create oval \
	       [expr {${:x} - $r1}] [expr {${:y} - $r1}] \
	       [expr {${:x} + $r1}] [expr {${:y} + $r1}] \
	       -outline ${:color} -width 2]
    :drawSpokes
    
    if {${:pivot}} {
      set deg2arc [expr {atan(1.0) * 8 / 360.0}]
      set rp [expr {$r1*${:pivot}}]
      set xp [expr {${:x} - $rp * cos($deg2arc * $alpha)}]
      set yp [expr {${:y} - $rp * sin($deg2arc * $alpha)}]
      set new_pivot [$c create rect $xp $yp [expr {$xp + 1}] [expr {$yp + 1}] \
			 -fill ${:color} -tag [list ${:tag} pivot]]
      set :act_pivot [list $new_pivot ${:pivot}]
      
      $c create arc [expr {${:x} - $r1}] [expr {${:y} - $r1}]\
	  [expr {${:x} + $r1}] [expr {${:y} + $r1}] \
	  -style chord -fill ${:color} -start 310 \
	  -extent 80 -tag counterweight
      set :pivot $new_pivot
    }
    set rh [expr {${:r} / 12.0}]
    $c create oval \
	[expr {${:x} - $rh}] [expr {${:y} - $rh}] \
	[expr {${:x} + $rh}] [expr {${:y} + $rh}] \
	-fill white -tag hub
    set :r $r1
  }
}

  
nx::Class create Locomotive {
  :property {speed 4}

  :require trait nx::trait::callback

  :method turn {} {
    set :alpha [expr {round(${:alpha} + 360 - ${:speed}) % 360}]
    foreach i [${:c} find withtag counterweight] {
      ${:c} itemconfig $i -start [expr {310 - ${:alpha}}]
    }
    ${:c} delete spoke
    foreach wheel [:info children] { $wheel drawSpokes }
    ${:c} raise hub
    set xp0 [expr {105 + 15 * sin((${:alpha} - 90) * atan(1.0) * 8 / 360)}]
    ${:c} delete piston
    ${: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 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() * ${:speed} / 3.0}] [expr {rand() * 2 - 2}]
      }
    }
    set t [${:c} create oval [${:c} bbox chimney] -fill white -outline white -tag smoke]
    ${:c} move $t 0 -10
    ${:c} lower smoke
  }

  :method drawRod {p0 p1 p2 p3} {
    ${:c} delete rod
    ${:c} create rect [${:c} bbox $p1 $p3] -fill white -tag rod
    ${: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
  }

  :public method tick {} {
    :turn
    foreach i [after info] {after cancel $i}
    after 10 [self] tick
  }

  :public method throttle {} {
    incr :speed 2
    :tick
  }
  
  :public method break {} {
    incr :speed -2
    if {${:speed}<0} {set :speed 0}
    :tick
  }

  :public method emergencyBreak {} {
    set :speed 0
    :tick
  }

  :method init {} {
    set :c [canvas .c -width 600 -height 160 -background lightblue]
    pack ${:c}

    bind ${:c} <1> [:callback throttle]
    bind ${:c} <2> [:callback break]
    bind ${:c} <3> [:callback emergencyBreak]
    
    ${:c} delete all
    ${: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 new -childof [self] -x 50 -y 150 -r 13 -spokes 12
    Wheel new -childof [self] -x 105 -y 150 -r 13 -spokes 12
    Wheel new -childof [self] -x 150 -y 150 -r 30 -pivot 0.5 -tag p1
    Wheel new -childof [self] -x 215 -y 150 -r 30 -pivot 0.5 -tag p2
    Wheel new -childof [self] -x 280 -y 150 -r 30 -pivot 0.5 -tag p3
    :drawRod p0 p1 p2 p3
    Wheel new -childof [self] -x 340 -y 150 -r 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 new -childof [self] -x 395 -y 150 -r 13 -spokes 12
    Wheel new -childof [self] -x 440 -y 150 -r 13 -spokes 12
    ${:c} create rect 380 132 456 142 -fill red
    Wheel new -childof [self] -x 495 -y 150 -r 13 -spokes 12
    Wheel new -childof [self] -x 540 -y 150 -r 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
    :tick
  }
}

Locomotive new