A small calculator can be useful to evaluate a single formula involving a few parameters/variables. This formula calculator class constructs a small calculator which evaluates the formula or its inverse with respect to a particular parameter, according to specified code for each result. [RVB]
First, in [incr tcl]:
class ForCalc {
public variable title "formula calculator" {
if {[info exists _Comp(text)]} {
configure $_Comp(text) $title
}
}
private variable _Info
private variable _Comp
# ========================================================================
# constants that can be used in recalculation code
# ========================================================================
common _pi_ [expr {acos(-1)}]
common _tabs_ 273.16 ;# T(O deg C) deg K
common _kb_ 1.380622e-23 ;# (J/K) : boltzmann constant
common _kbev_ 8.61708e-05 ;# (eV/K) : boltzmann constant
common _hbar_ 6.58218e-16 ;# (eV-s) : planck constant
common _co_ 2.99792e+10 ;# (cm/s) : speed of light in vacuum
common _qe_ 1.602192e-19 ;# (C) : unit charge
common _eo_ 8.854215e-14 ;# (F/cm) : permittivity of free space
common _eox_ 3.45314385e-13 ;# F/cm : permittivity of SiO2
common _esi_ 1.03594315e-12 ;# F/cm : permittivity of Si
common _mo_ 9.10956e-31 ;# (kg) : electron rest mass
# ========================================================================
# METHOD: constructor
# ARGUMENTS:
# % par_specs
# list of lists of:
# parameter name
# parameter label for calculator display
# unit label for calculator display
# default value of the parameter
# recalculation key: pointer to code to evaluate
# when return is typed in parameter entry box
# % recalc_specs
# list of lists of:
# recalculation key
# recalculation code
# recalculation code should set the value(s) of one or more of the
# parameters specified in par_specs
# % args
# CONFIGURATION-OPTIONS
# CONFIGURATION-OPTIONS:
# % -title
# specify the calculator title
# ========================================================================
constructor {par_specs recalc_specs args} {
foreach {par label unit value recalc} $par_specs {
lappend _Info(pars) $par
set _Info($par-label) $label
set _Info($par-unit) $unit
set _Info($par-value) $value
set _Info($par-recalc) $recalc
}
foreach {key code} $recalc_specs {
set _Info($key-code) $code
}
eval configure $args
_gui
}
# ========================================================================
# METHOD: destructor
# RESULTS:
# * destroys calculator gui
# ========================================================================
destructor {
if {[info exists _Comp(top)]} {
destroy $_Comp(top)
}
}
# ========================================================================
# METHOD: _gui (private)
# PURPOSE: build calculator gui
# ========================================================================
private method _gui {} {
set top .[namespace tail $this]
toplevel $top
set _Comp(top) $top
#---------------------------------------------------------------------
# main layout
#---------------------------------------------------------------------
frame $top.text -borderwidth 2 -relief raised
pack $top.text -side top -expand 1 -fill both
frame $top.pars -borderwidth 2 -relief raised
pack $top.pars -side top -expand 1 -fill both
set _Comp(text) $top.text.text
set _Comp(quit) $top.text.quit
message $_Comp(text) -justify center -text $title -aspect 800
pack $_Comp(text) -side left -expand 1 -fill both
button $_Comp(quit) -text quit -command "delete object $this"
pack $_Comp(quit) -side left -padx 10 -pady 10 -expand 1 -fill x
#---------------------------------------------------------------------
# parameter entry
#---------------------------------------------------------------------
foreach par $_Info(pars) {
set _Comp($par-frame) $top.pars.$par
set _Comp($par-label) $_Comp($par-frame).l
set _Comp($par-entry) $_Comp($par-frame).e
set _Comp($par-unit) $_Comp($par-frame).u
frame $_Comp($par-frame)
pack $_Comp($par-frame) -side top -expand 1 -fill x
label $_Comp($par-label) -text $_Info($par-label) -width 30 -anchor w
pack $_Comp($par-label) -side left -expand 1 -fill x
entry $_Comp($par-entry) -relief sunken
pack $_Comp($par-entry) -side left -expand 1 -fill x
label $_Comp($par-unit) -text $_Info($par-unit) -width 15 -anchor c
pack $_Comp($par-unit) -side left -expand 1 -fill x
$_Comp($par-entry) insert 0 $_Info($par-value)
bind $_Comp($par-entry) [code $this _recalculate $par]
}
_recalculate [lindex $_Info(pars) 0]
wm title $top $title
}
# ========================================================================
# METHOD: _recalculate (private)
# PURPOSE: recalculate parameter values
# ARGUMENTS:
# % par_changed
# name of parameter which had in entry
# ========================================================================
private method _recalculate {par_changed} {
foreach par $_Info(pars) {
set $par [$_Comp($par-entry) get]
}
set recalc $_Info($par_changed-recalc)
if {[info exists _Info($recalc-code)]} {
eval $_Info($recalc-code)
}
foreach par $_Info(pars) {
$_Comp($par-entry) delete 0 end
$_Comp($par-entry) insert 0 [set $par]
}
}
}
Here is a basic tcl version
namespace eval ::forcalc {
namespace export ForCalc
variable Info
variable Comp
# ========================================================================
# constants that can be used in recalculation code
# ========================================================================
variable _pi_ [expr {acos(-1)}]
variable _tabs_ 273.16 ;# T(O deg C) deg K
variable _kb_ 1.380622e-23 ;# (J/K) : boltzmann constant
variable _kbev_ 8.61708e-05 ;# (eV/K) : boltzmann constant
variable _hbar_ 6.58218e-16 ;# (eV-s) : planck constant
variable _co_ 2.99792e+10 ;# (cm/s) : speed of light in vacuum
variable _qe_ 1.602192e-19 ;# (C) : unit charge
variable _eo_ 8.854215e-14 ;# (F/cm) : permittivity of free space
variable _eox_ 3.45314385e-13 ;# F/cm : permittivity of SiO2
variable _esi_ 1.03594315e-12 ;# F/cm : permittivity of Si
variable _mo_ 9.10956e-31 ;# (kg) : electron rest mass
# ========================================================================
# PROC: ForCalc
# PURPOSE: create and configure a new calculator
# ARGUMENTS:
# % this
# a unique calculator handle
# % par_specs
# list of lists of:
# parameter name
# parameter label for calculator display
# unit label for calculator display
# default value of the parameter
# recalculation key: pointer to code to evaluate
# when return is typed in parameter entry box
# % recalc_specs
# list of lists of:
# recalculation key
# recalculation code
# recalculation code should set the value(s) of one or more of the
# parameters specified in par_specs
# % args
# CONFIGURATION-OPTIONS
# CONFIGURATION-OPTIONS:
# % -title
# specify the calculator title
# ========================================================================
proc ForCalc {this par_specs recalc_specs args} {
variable Info
variable Comp
if {[info exists Comp($this-top)]} {
error "\"$this\" calculator already exists"
}
set title "formula calculator"
while {[llength $args] > 0} {
set arg [lindex $args 0]
set args [lrange $args 1 end]
switch -- $arg {
-title {
set title [lindex $args 0]
set args [lrange $args 1 end]
}
default {
error "option \"$arg\" is not supported"
}
}
}
foreach {par label unit value recalc} $par_specs {
lappend Info($this-pars) $par
set Info($this-$par-label) $label
set Info($this-$par-unit) $unit
set Info($this-$par-value) $value
set Info($this-$par-recalc) $recalc
}
foreach {key code} $recalc_specs {
set Info($this-$key-code) $code
}
set top .$this
toplevel $top
set Comp($this-top) $top
frame $top.text -borderwidth 2 -relief raised
pack $top.text -side top -expand 1 -fill both
frame $top.pars -borderwidth 2 -relief raised
pack $top.pars -side top -expand 1 -fill both
message $top.text.msg -justify center -text $title -aspect 800
pack $top.text.msg -side left -expand 1 -fill both
button $top.text.but -text quit \
-command [list ::forcalc::_destroy $this]
pack $top.text.but -side left -padx 10 -pady 10 -expand 1 -fill x
#---------------------------------------------------------------------
# parameter entry
#---------------------------------------------------------------------
foreach par $Info($this-pars) {
set Comp($this-$par-frame) $top.pars.$par
set Comp($this-$par-label) $Comp($this-$par-frame).l
set Comp($this-$par-entry) $Comp($this-$par-frame).e
set Comp($this-$par-unit) $Comp($this-$par-frame).u
frame $Comp($this-$par-frame)
pack $Comp($this-$par-frame) -side top -expand 1 -fill x
label $Comp($this-$par-label) -text $Info($this-$par-label) \
-width 30 -anchor w
pack $Comp($this-$par-label) -side left -expand 1 -fill x
entry $Comp($this-$par-entry) -relief sunken
pack $Comp($this-$par-entry) -side left -expand 1 -fill x
label $Comp($this-$par-unit) -text $Info($this-$par-unit) \
-width 15 -anchor c
pack $Comp($this-$par-unit) -side left -expand 1 -fill x
$Comp($this-$par-entry) insert 0 $Info($this-$par-value)
bind $Comp($this-$par-entry) \
[list forcalc::_recalculate $this $par]
}
_recalculate $this [lindex $Info($this-pars) 0]
wm title $top $title
return $this
}
# ========================================================================
# METHOD: _destroy
# ARGUMENTS:
# % this
# The calculator handle
# RESULTS:
# * destroys calculator gui
# * unregisters calculator handle
# ========================================================================
proc _destroy {this} {
variable Info
variable Comp
destroy $Comp($this-top)
foreach item [array names Info $this-*] {
unset Info($item)
}
foreach item [array names Comp $this-*] {
unset Comp($item)
}
}
# ========================================================================
# PROC: _recalculate
# PURPOSE: recalculate parameter values
# ARGUMENTS:
# % this
# the calculator handle
# % par_changed
# name of parameter which had in entry
# ========================================================================
proc _recalculate {this par_changed} {
variable Info
variable Comp
variable _pi_
variable _tabs_
variable _kb_
variable _kbev_
variable _hbar_
variable _co_
variable _qe_
variable _eo_
variable _eox_
variable _esi_
variable _mo_
foreach par $Info($this-pars) {
set $par [$Comp($this-$par-entry) get]
}
set recalc $Info($this-$par_changed-recalc)
if {[info exists Info($this-$recalc-code)]} {
eval $Info($this-$recalc-code)
}
foreach par $Info($this-pars) {
$Comp($this-$par-entry) delete 0 end
$Comp($this-$par-entry) insert 0 [set $par]
}
}
}
namespace import forcalc::ForCalc
Here are several examples:
A field mowing calculator. Calculates the total time required to mow
a field at a constant speed and swath and number of turns, or the number
of turns required given total time, swath, and speed.
ForCalc mowcalc {
n "number of turns" {} 43 t
dr "swath" ft 3 n
s "speed" ft/s 3 n
t "total time" min 100 n
} {
t {set t [expr {$n*($n+1)*($dr*$_pi_)/($s*60.0)}]}
n {set n [expr {sqrt(0.25 + ($s*60.0*$t)/($dr*$_pi_)) - 0.5}]}
} -title "field mow calculator"
An integrated resistor calculator. Given a target resistance and width,
calculates the required resistor length. Given a specified length and width,
calculates the resistance.
ForCalc rescalc {
r "Resistance" ohms 1000 l
rho "Sheet Resistance" ohms/square 480 r
dw "delta W" um 0.04 r
dl "delta L" um -0.20 r
l "Length" um 10.0 r
w "Width" um 1.0 l
} {
l {set l [expr {1.0*$r*($w-$dw)/$rho + $dl}]}
r {set r [expr {1.0*$rho*($l-$dl)/($w-$dw)}]}
} -title "integrated circuit resistance calculator"
A fixed-rate mortgage payment calculator.
ForCalc mortcalc {
principal "Principal" $ 100000 payment
years "Years" y 30 payment
rate "Rate" % 8.00 payment
payments_year "Payments/Year" {} 12 payment
payment "Payment" $ 733.76 principal
} {
payment {
set a [expr {1.0e-2*$rate/$payments_year}]
set N [expr {1.0*$payments_year*$years}]
set per_thousand [expr {1.0e+3*$a/(1-pow(1+$a,-$N))}]
set payment [expr {1.0e-3*$principal*$per_thousand}]
set payment [format "%-10.2f" $payment]
}
principal {
set a [expr {1.0e-2*$rate/$payments_year}]
set N [expr {1.0*$payments_year*$years}]
set per_thousand [expr {1.0e+3*$a/(1-pow(1+$a,-$N))}]
set principal [expr {1.0e+3*$payment/$per_thousand}]
set principal [format "%-10.2f" $principal]
}
} -title "fixed rate mortgage calculator"
----
!!!!!!
%|[Category GUI] | [Category Mathematics] | [Category Application]|%
!!!!!!