[Arjen Markus] (18 december 2002) The script below is a first (well, second) attempt to render mathematical formulae in a canvas. It is far from complete, and if I ever finish it, it will probably end up totally differently, but it works to a certain degree with a certain class of formulae. Several people, among whom [Lars Hellstrom] and [Kevin Kenny], provided useful information on existing algorithms, such as the one used in [TeX], and pointers to articles by [Brian Kernighan] [http://citeseer.nj.nec.com/kernighan75system.html]. See also: [Binomial coefficients] for a quick-and-dirty solution. ---- # mathform.tcl -- # Simple script to render mathematical formulae # namespace eval ::MathFormula:: { variable poshoriz 0 variable offhoriz 0 variable posvert 0 variable offvert 0 variable offset_add 0 } # drawFormula -- # Draw the formula at a given position (lower-left) # # Arguments: # canvas The canvas to use # xpos X-position to start # ypos Y-position to start # formula String holding the formula # # Result: # None # # Side effect: # The formula is rendered on the screen # # proc ::MathFormula::drawFormula {canvas xpos ypos formula} { variable poshoriz variable offhoriz variable posvert variable offvert variable offset_add set poshoriz $xpos set posvert $ypos set offhoriz 0 set offvert 0 set offset_add 0 set tokens [analyseFormula $formula] foreach {token xp yp advance} $tokens { renderToken $canvas $token $xp $yp $advance } } # renderToken -- # Render the given token # # Arguments: # canvas Canvas in which to draw # token Token to be drawn # xp X-position relative to current drawing position # yp Y-position relative to current drawing position # # Result: # None # # Side effect: # The token is drawn on the canvas # proc ::MathFormula::renderToken {canvas token xp yp advance} { variable poshoriz variable posvert variable offhoriz variable offvert set xpos [expr {$poshoriz+$xp}] set ypos [expr {$posvert+$yp}] switch -- $token { "INT" { # Integral set item [$canvas create line -3 9 -1 10 0 0 1 -10 3 -9 -width 1 -fill black -smooth 1] $canvas move $item $xpos $ypos incr xpos 5 } "SUM" { # Sum set item [$canvas create line 8 2 0 2 5 -4 0 -9 8 -9 -width 1 -fill black] $canvas move $item $xpos $ypos incr xpos 8 } "Inf" { # Infinity set item1 [$canvas create oval -5 -2 0 2 -outline black] set item2 [$canvas create oval 0 -2 5 2 -outline black] $canvas move $item1 $xpos $ypos $canvas move $item2 $xpos $ypos } default { # Letters set item [$canvas create text $xpos $ypos -text $token -fill black -anchor w -font "Times 12"] set bbox [$canvas bbox $item] set width [expr {[lindex $bbox 2]-[lindex $bbox 0]}] set xp $width set xpos [expr {$xpos+$width}] } } if { $advance } { set poshoriz $xpos } else { set offhoriz [expr {$xp>$offhoriz? $xp : $offhoriz}] } } # analyseFormula -- # Analyse the formula and determine the positions of the tokens # # Arguments: # formula Formula to be drawn # # Result: # List of tokens with relative positions and advancing information # proc ::MathFormula::analyseFormula {formula} { set result [list] set advance 1 set xp 0 set yp 0 foreach token $formula { switch -- $token { "_" { # Subscript set yp 5 set advance 0 continue } "^" { # Superscript set yp -3 set advance 0 continue } "~" { # Force space set token " " set advance 1 } "`" { # Force extra space incr xp 1 set advance 1 continue } "INT" { # Integral set xp 0 set yp 0 set advance 1 } "SUM" { # Sum set xp 0 set yp 2 set advance 1 } "from" { # Lower bound set xp -10 set yp 14 set advance 0 continue } "to" { # Upper bound set xp 1 set yp -10 set advance 0 continue } "Inf" { # Infinity incr yp -2 ;# Increase, not set! set advance 1 } default { # Letters set advance 1 } } lappend result $token $xp $yp $advance if { $advance } { set xp 0 set yp 0 } } return $result } # Main -- # Set up a canvas, analyse the formula and draw it # canvas .c -background white pack .c -fill both set pi "\u3c0" set alpha "\u3b1" set DELTA "\u394" set omega "\u3c9" set string "SUM from i=0 to Inf ~ A _ i ~ = ~ INT from 0 to $pi cos ^ 2 x dx" ::MathFormula::drawFormula .c 10 20 "Not ~ p ` erfect ~ yet, ~ but ..." ::MathFormula::drawFormula .c 10 60 $string ::MathFormula::drawFormula .c 10 100 "0.1 = e ^ -kT90" ::MathFormula::drawFormula .c 10 140 "f(x) = x ^ 3 - x ^ 2 + x - 1" ::MathFormula::drawFormula .c 10 180 "h(t) = cos( $omega t - $alpha )" ---- [[ [Category Mathematics] | [Category Graphics] ]]