Version 2 of A little slide-rule

Updated 2003-09-01 08:28:51

if 0 {Richard Suchenwirth 2003-08-31 - The slide rule was an analog, mechanical device for approximate engineering computing, made obsolete by the pocket calculator since about 1970. The basic principle is that multiplication is done by adding logarithms, hence most of the scales are logarithmic, with uneven increments.

http://mini.net/files/sliderule.jpg

This fun project recreates a slide rule (roughly an Aristo-Rietz Nr. 89 with 7 scales - high-notch ones had up to 24) with a white "body" and a beige "slide" which you can move left or right with mouse button 1 clicked, or in pixel increment with the <Shift-Left>/<Shift-Right> cursor keys. Finally, the blue line represents the "mark" (how is that correctly called? "runner"? "slider"?) which you can move with the mouse over the whole thing to read a value. Fine movements with <Left>/<Right>.

Due to rounding errors (integer pixels), this plaything is even less precise than a physical slide rule was, but maybe you still enjoy the memories... The screenshot shows how I found out that 3 times 7 is approx. 21... (check the A and B scales). }

 proc ui {} {
    set width 620
    pack [canvas .c -width $width -height 170 -bg white]
    pack [label .l -textvariable info -fg blue] -fill x
    .c create rect 0 50 $width 120 -fill grey90
    .c create rect 0 50 $width 120 -fill beige -outline beige \
        -tag {slide slidebase}
    .c create line 0 0 0 120 -tag mark -fill blue
    drawScale .c K  x3    10 5    5 log10 1 1000 186.6666667
    drawScale .c A  x2    10 50  -5 log10 1 100 280
    drawScale .c B  x2    10 50   5 log10 1 100 280 slide
    drawScale .c CI 1/x   10 90 -5 -log10 1 10  560 slide
    drawScale .c C  x     10 120 -5 log10 1 10  560 slide
    drawScale .c D  x     10 120  5 log10 1 10  560 
    drawScale .c L "lg x" 10 160 -5 by100  0 10   5600
    bind .c <Motion> {.c coords mark %x 0 %x 170; set info [values .c]}
    bind .c <1> {set x %x}
    bind .c <B1-Motion> {%W move slide [expr {%x-$x}] 0; set x %x}
    bind . <Shift-Left>  {.c move slide -1 0; set info [values .c]}
    bind . <Shift-Right> {.c move slide  1 0; set info [values .c]}
    bind . <Left>  {.c move mark -1 0; set info [values .c]}
    bind . <Right> {.c move mark  1 0; set info [values .c]}
 }
 proc drawScale {w name label x y dy f from to fac {tag {}}} {
    set color [expr {[string match -* $f]? "red": "black"}]
    $w create text $x [expr $y+2*$dy] -text $name -tag $tag -fill $color
    $w create text 600 [expr $y+2*$dy] -text $label -tag $tag -fill $color
    set x [expr {[string match -* $f]? 580: $x+10}]
    set mod 5
    set lastlabel ""
    set lastx 0
    for {set i [expr {$from*10}]} {$i<=$to*10} {incr i} {
        if {$i>100} {
            if {$i%10} continue ;# coarser increments
            set mod 50
        }
        if {$i>1000} {
            if {$i%100} continue ;# coarser increments
            set mod 500
        }
        set x0 [expr $x+[$f [expr {$i/10.}]]*$fac]
        set y1 [expr {$i%(2*$mod)==0? $y+2.*$dy: $i%$mod==0? $y+1.7*$dy: $y+$dy}]
        set firstdigit [string index $i 0]
        if {$y1==$y+$dy && abs($x0-$lastx)<2} continue
        set lastx $x0
        if {$i%($mod*2)==0 && $firstdigit != $lastlabel} {
            $w create text $x0 [expr $y+3*$dy] -text $firstdigit \
               -tag $tag -font {Helvetica 7} -fill $color
            set lastlabel $firstdigit
        }
        $w create line $x0 $y $x0 $y1 -tag $tag -fill $color
    }
 }
 proc values w {
    set x0 [lindex [$w coords slidebase] 0]
    set x1 [lindex [$w coords mark] 0]
    set lgx [expr {($x1-20)/560.}]
    set x [expr {pow(10,$lgx)}]
    set lgxs [expr {($x1-$x0-20)/560.}]
    set xs [expr {pow(10,$lgxs)}]
    set res     K:[format %.2f [expr {pow($x,3)}]]
    append res "  A:[format %.2f [expr {pow($x,2)}]]"
    append res "  B:[format %.2f [expr {pow($xs,2)}]]"
    append res "  CI:[format %.2f [expr {pow(10,-$lgxs)*10}]]"
    append res "  C:[format %.2f $xs]"
    append res "  D:[format %.2f $x]"
    append res "  L:[format %.2f $lgx]"
 }
 proc pow10 x {expr {pow(10,$x)}}
 proc log10 x {expr {log10($x)}}
 proc -log10 x {expr {-log10($x)}}
 proc by100  x {expr {$x/100.}}
 #--------------------------------
 ui
 bind . <Escape> {exec wish $argv0 &; exit}

Arts and crafts of Tcl-Tk programming