[MS]: this is a version of [Recursive curves] that avoids floating point operations: * as all segments drawn have one of two lengths, thess lengths are precomputed, as well as the depth at which a segment is drawn. The depth is hence kept in an integer. * as all angles are multiples of $pi/4, the angle is kept by the integer number of $pi/4 * the angle-dependent values are precomputed in a table, for the 8 possible values of ($angle%8) An additional optimisation is that the second recursion is tail-optimised using [while]. Note that this is ''pure sport'' - the extra optimisation is not really relevant here, there is not much further improvement from the original version as the app is I/O bound (drawing on the canvas). Also note that this implementation makes additional assumptions: * the intial angle is 0 * (dragon only) the intial value of s is 1 ---- proc main {} { pack [canvas .c -width 240 -height 280] set ::points {150 190} # ETFS configurability: uncomment what you want set t [time {ccurve .c 120 0 2}] #set t [time {dragon .c 160 0 1 2.4}] wm title . "[expr {[lindex $t 0]/1000000.}] sec" bind . {exec wish $argv0 &; exit} } # This just sets up the parameters for # table-based ops; we assume here that # the initial angle is 0. proc setParams {len angle minlen} { global parList set maxDepth [expr {(1+floor(2*log($len/$minlen)/log(2)))}] set minlen [expr {$len/pow(sqrt(2),$maxDepth)}] set minlen0 [expr {$minlen/sqrt(2)}] set parList {} lappend parList [list 0.0 $minlen ];# 0 lappend parList [list $minlen0 $minlen0];# 1 lappend parList [list $minlen 0.0 ];# 2 lappend parList [list $minlen0 -$minlen0];# 3 lappend parList [list 0.0 -$minlen ];# 4 lappend parList [list -$minlen0 -$minlen0];# 5 lappend parList [list -$minlen 0.0 ];# 6 lappend parList [list -$minlen0 $minlen0];# 7 return [expr {int($maxDepth)}] } # C curve drawer: assumes initial angle 0 proc ccurve {w len angle minlen} { set maxDepth [setParams $len $angle $minlen] ccurveInt $w $maxDepth $angle } proc ccurveInt {w depth angle} { while {$depth} { incr depth -1 ccurveInt $w $depth [expr {$angle + 1}] incr angle -1 } plotline $w $angle } # Dragon curve drawer: assumes initial angle 0, initial s 1 proc dragon {w len angle s minlen} { set maxDepth [setParams $len $angle $minlen] dragonInt $w $maxDepth $angle $s } proc dragonInt {w depth angle s} { while {$depth} { incr depth -1 dragonInt $w $depth [expr {$angle + $s}] 1 if {$s == 1} { incr angle -1 set s -1 } else { incr angle 1 } } plotline $w $angle } # Plot a line from last end point in specified direction and length proc plotline {w ang} { global points set idx [expr {$ang%8}] if {$idx < 0} { incr $idx 8 } foreach {xadd yadd} [lindex $::parList $idx] { set x [expr {[lindex $points end-1]-$xadd}] set y [expr {[lindex $points end ]-$yadd}] } if {[llength [lappend points $x $y]]>200} { $w create line $points set points [list $x $y] update } } # Let's go! main