proc gratt {w args} {
upvar #0 $w ""
set (from) 0
set (to) 24
set (offset) 80
canvas $w
foreach {key value} $args {
switch -- $key {
-line {set line $value}
-from {set (from) $value}
-to {set (to) $value}
-offset {set (offset) $value}
default {$w configure $key $value}
}
}
gratt'draw $w $line
rename $w _$w
proc $w {cmd args} {
set self [lindex [info level 0] 0]
switch -- $cmd {
add {eval gratt'add $self $args}
default {eval _$self $cmd $args}
}
}
return $w
}#-- Internal routines: draw grid, label stations and hours proc gratt'draw {w line} {
upvar #0 $w ""
set x0 $(offset)
set width [$w cget -width]
set (dx) [expr {($width - $x0) / ($(to) - $(from))}]
set height [$w cget -height]
for {set h $(from); set x $x0} {$h <= $(to)} {incr h; incr x $(dx)} {
$w create text $x 8 -text $h
$w create line $x 16 $x [expr {$height-8}] -fill gray
}
incr x -$(dx)
set yfac [expr {double($height-24)/[lindex $line end]}]
foreach {name distance} $line {
set ($name) [expr {$distance*$yfac+16}]
$w create text 5 $($name) -text "$name $distance" -anchor w
$w create line $x0 $($name) $x $($name)
}
}#-- Add a train proc gratt'add {w number schedule args} {
upvar #0 $w ""
set coords {}
foreach {name times} $schedule {
foreach time $times {
lappend coords [gratt'x $w $time] $($name)
}
}
eval $w create line $coords $args
}#-- convert a "military" time (HHMM) to x coordinate proc gratt'x {w time} {
upvar #0 $w ""
scan $time %d time ;# strip off leading zero
set mins [expr {($time/100-$(from))*60+$time%100}]
expr {double($(offset)) + $mins * $(dx)/60}
}if 0 {Here's a testing example: the fictional "Mason - Dixon line". Assume it is single-tracked, and trains can only cross in Mason-East and Springfield. We have regular trains (blue) and expresses (red). First, to declare the line with mileposts:} set md {Mason 0 Mason-East 4 Springfield 12 Dixon-West 18 Dixon 20}
pack [gratt .g -line $md -from 5 -to 19 -bg white -width 720 -height 240]#-- And now for the timetable. Westbound trains: .g add 1201 {
Mason 0550 Mason-East {0556 0558} Springfield {0612 0618} Dixon 0639
} -fill blue
.g add 1203 {
Mason 0655 Mason-East {0701 0703} Springfield {0714 0720}
Dixon-West {0728 0730} Dixon 0741
} -fill blue
.g add X303 {Mason 0730 Springfield {0748 0750} Dixon 0811} -fill red
.g add 1205 {
Mason 0800 Mason-East {0806 0810} Springfield {0824 0830} Dixon 0853
} -fill blue
.g add 1207 {
Mason 1000 Mason-East {1006 1008} Springfield {1022 1026} Dixon 1051
} -fill blue
.g add 1401 {Springfield 1200 Dixon-West {1210 1212} Dixon 1221} -fill blue
.g add 1209 {
Mason 1200 Mason-East {1206 1208} Springfield 1222 Dixon 1251
} -fill blue
.g add X305 {Mason 1330 Springfield {1348 1350} Dixon 1411} -fill red
.g add 1211 {
Mason 1500 Mason-East {1506 1508} Springfield {1522 1524} Dixon 1553
} -fill blue
.g add 1213 {
Mason 1700 Mason-East {1706 1708} Springfield {1722 1724} Dixon 1753
} -fill blue#---------------------- Eastbound trains .g add 1200 {
Dixon 0550 Dixon-West {0556 0558} Springfield {0612 0619}
Mason-East {0628 0630} Mason 0643
} -fill blue
.g add 1202 {
Dixon 0650 Dixon-West {0656 0658} Springfield {0712 0719}
Mason-East {0728 0740} Mason 0753
} -fill blue
.g add 1204 {
Dixon 0900 Dixon-West {0906 0908} Springfield {0922 0929}
Mason-East {0936 0938} Mason 0951
} -fill blue
.g add 1206 {
Dixon 1000 Dixon-West {1006 1008} Springfield {1022 1029}
Mason-East {1036 1038} Mason 1051
} -fill blue
.g add 1408 {Dixon 1130 Dixon-West {1136 1138} Springfield 1146} -fill blue
.g add X306 {Dixon 1100 Springfield {1122 1125} Mason 1143} -fill red
.g add 1208 {
Dixon 1330 Dixon-West {1336 1338} Springfield {1342 1353}
Mason-East {1408 1410} Mason 1423
} -fill blue
.g add 1210 {
Dixon 1600 Dixon-West {1606 1608} Springfield {1622 1629}
Mason-East {1636 1638} Mason 1651
} -fill blue
.g add X308 {Dixon 1730 Springfield {1752 1755} Mason 1813} -fill red
.g add 1212 {
Dixon 1800 Dixon-West {1806 1808} Springfield {1822 1829}
Mason-East {1836 1838} Mason 1851
} -fill blueif 0 {Looking at the diagram, one can deduce that at least three trainsets are needed: a regular one that stays in Dixon overnight (which does two full round-trips and the short Springfield runs around noon), and a regular and an express (if they differ in type) stationed in Mason. It's an interesting pastime to modify the timetable and see how the diagram changes ... :^)}

