source: trunk/gui/scripts/spectrum.tcl @ 2035

Last change on this file since 2035 was 1929, checked in by gah, 14 years ago
File size: 9.5 KB
Line 
1# ----------------------------------------------------------------------
2#  COMPONENT: spectrum - maps a range of real values onto a color
3#
4#  This data object represents the mapping of a range of real values
5#  onto a range of colors.  It is used in conjunction with other
6#  widgets, such as the Rappture::Gauge.
7#
8#  EXAMPLE:
9#    Rappture::Spectrum #auto {
10#       0.0   red
11#       1.0   green
12#      10.0   #d9d9d9
13#    }
14# ======================================================================
15#  AUTHOR:  Michael McLennan, Purdue University
16#  Copyright (c) 2004-2005  Purdue Research Foundation
17#
18#  See the file "license.terms" for information on usage and
19#  redistribution of this file, and for a DISCLAIMER OF ALL WARRANTIES.
20# ======================================================================
21package require Itk
22
23itcl::class Rappture::Spectrum {
24    inherit Rappture::Dispatcher
25
26    public variable units ""  ;# default units for all real values
27
28    constructor {{sdata ""} args} { # defined below }
29
30    public method insert {args}
31    public method delete {first {last ""}}
32    public method get {args}
33
34    private variable _axis ""       ;# list of real values along axis
35    private variable _rvals ""      ;# list of red components along axis
36    private variable _gvals ""      ;# list of green components along axis
37    private variable _bvals ""      ;# list of blue components along axis
38    private variable _spectrum 0    ;# use continuous visible spectrum
39    private variable _specv0 0      ;# minimum value
40    private variable _specw0 0      ;# wavelength for minimum
41}
42                                                                               
43# ----------------------------------------------------------------------
44# CONSTRUCTOR
45# ----------------------------------------------------------------------
46itcl::body Rappture::Spectrum::constructor {{sdata ""} args} {
47    register !change  ;# used to signal changes in spectrum
48
49    if {[llength $sdata] > 0} {
50        regsub -all {\n} $sdata { } sdata
51        eval insert $sdata
52    }
53    eval configure $args
54}
55
56# ----------------------------------------------------------------------
57# USAGE: insert ?<value1> <color1> <value2> <color2> ...?
58#
59# Clients use this to insert one or more values into the spectrum.
60# Each value has an associated color.  These values are used in the
61# "get" method to map any incoming value to its interpolated color
62# in the spectrum.
63# ----------------------------------------------------------------------
64itcl::body Rappture::Spectrum::insert {args} {
65    set changed 0
66
67    # special case. Two values in nm, then use
68    # spectrum instead of gradient.
69    if {[llength $args] == 4} {
70        set cnt 0
71        foreach {value color} $args {
72            if {[string match "*nm" $color]} {
73                incr cnt
74            }
75        }
76        if {$cnt == 2} {
77            set val0 [lindex $args 0]
78            set color0 [string trimright [lindex $args 1] "nm"]
79            set val1 [lindex $args 2]
80            set color1 [string trimright [lindex $args 3] "nm"]
81           
82            if {"" != $units} {
83                set val0 [Rappture::Units::convert $val0 \
84                              -context $units -to $units -units off]
85                set val1 [Rappture::Units::convert $val1 \
86                              -context $units -to $units -units off]
87            }
88
89            set _spectrum [expr (double($color1) - double($color0)) \
90                           / (double($val1) - double($val0))]
91            set _specv0 $val0
92            set _specw0 $color0
93            return
94        }
95    }
96
97    foreach {value color} $args {
98        if {"" != $units} {
99            set value [Rappture::Units::convert $value \
100                -context $units -to $units -units off]
101        }
102        foreach {r g b} [Rappture::color::RGB $color] { break }
103        set i 0
104        foreach v $_axis {
105            if {$value == $v} {
106                set _rvals [lreplace $_rvals $i $i $r]
107                set _gvals [lreplace $_gvals $i $i $g]
108                set _bvals [lreplace $_bvals $i $i $b]
109                set changed 1
110                break
111            } elseif {$value < $v} {
112                set _axis  [linsert $_axis $i $value]
113                set _rvals [linsert $_rvals $i $r]
114                set _gvals [linsert $_gvals $i $g]
115                set _bvals [linsert $_bvals $i $b]
116                set changed 1
117                break
118            }
119            incr i
120        }
121
122        if {$i >= [llength $_axis]} {
123            lappend _axis $value
124            lappend _rvals $r
125            lappend _gvals $g
126            lappend _bvals $b
127            set changed 1
128        }
129    }
130
131    # let any clients know if something has changed
132    if {$changed} {
133        event !change
134    }
135}
136
137# ----------------------------------------------------------------------
138# USAGE: delete <first> ?<last>?
139#
140# Clients use this to delete one or more entries from the spectrum.
141# The <first> and <last> represent the integer index of the desired
142# element.  If only <first> is specified, then that one element is
143# deleted.  If <last> is specified, then all elements in the range
144# <first> to <last> are deleted.
145# ----------------------------------------------------------------------
146itcl::body Rappture::Spectrum::delete {first {last ""}} {
147    if {$last == ""} {
148        set last $first
149    }
150    if {![regexp {^[0-9]+|end$} $first]} {
151        error "bad index \"$first\": should be integer or \"end\""
152    }
153    if {![regexp {^[0-9]+|end$} $last]} {
154        error "bad index \"$last\": should be integer or \"end\""
155    }
156
157    if {[llength [lrange $_axis $first $last]] > 0} {
158        set _axis [lreplace $_axis $first $last]
159        set _rvals [lreplace $_rvals $first $last]
160        set _gvals [lreplace $_gvals $first $last]
161        set _bvals [lreplace $_bvals $first $last]
162        event !change
163    }
164}
165
166# ----------------------------------------------------------------------
167# USAGE: get ?-color|-fraction? ?<value>?
168#
169# Clients use this to get information about the spectrum.  With no args,
170# it returns a list of elements in the form accepted by the "insert"
171# method.  Otherwise, it returns the interpolated value for the given
172# <value>.  By default, it returns the interpolated color, but the
173# -fraction flag can be specified to query the fractional position
174# along the spectrum.
175# ----------------------------------------------------------------------
176itcl::body Rappture::Spectrum::get {args} {
177    if {[llength $args] == 0} {
178        set rlist ""
179        foreach v $_axis r $_rvals g $_gvals b $_bvals {
180            lappend rlist "$v$units" [format {#%.4x%.4x%.4x} $r $g $b]
181        }
182        return $rlist
183    }
184
185    set what "-color"
186    while {[llength $args] > 0} {
187        set first [lindex $args 0]
188        if {[regexp {^-[a-zA-Z]} $first]} {
189            set what $first
190            set args [lrange $args 1 end]
191        } else {
192            break
193        }
194    }
195    if {[llength $args] != 1} {
196        error "wrong # args: should be \"get ?-color|-fraction? ?value?\""
197    }
198
199    set value [lindex $args 0]
200    if {$units != ""} {
201        set value [Rappture::Units::convert $value \
202            -context $units -to $units -units off]
203    }
204
205    switch -- $what {
206        -color {
207            if {$_spectrum != 0} {
208                # continuous spectrum. just compute wavelength
209                set waveln [expr ($value - $_specv0) * $_spectrum + $_specw0]
210                return [Rappture::color::wave2RGB $waveln]
211            }
212            set i 0
213            set ilast ""
214            while {$i <= [llength $_axis]} {
215                set v [lindex $_axis $i]
216
217                if {$v == ""} {
218                    set r [lindex $_rvals $ilast]
219                    set g [lindex $_gvals $ilast]
220                    set b [lindex $_bvals $ilast]
221                    return [format {#%.4x%.4x%.4x} $r $g $b]
222                } elseif {$value < $v} {
223                    if {$ilast == ""} {
224                        set r [lindex $_rvals $i]
225                        set g [lindex $_gvals $i]
226                        set b [lindex $_bvals $i]
227                    } else {
228                        set vlast [lindex $_axis $ilast]
229                        set frac [expr {($value-$vlast)/double($v-$vlast)}]
230
231                        set rlast [lindex $_rvals $ilast]
232                        set r [lindex $_rvals $i]
233                        set r [expr {round($frac*($r-$rlast) + $rlast)}]
234
235                        set glast [lindex $_gvals $ilast]
236                        set g [lindex $_gvals $i]
237                        set g [expr {round($frac*($g-$glast) + $glast)}]
238
239                        set blast [lindex $_bvals $ilast]
240                        set b [lindex $_bvals $i]
241                        set b [expr {round($frac*($b-$blast) + $blast)}]
242                    }
243                    return [format {#%.4x%.4x%.4x} $r $g $b]
244                }
245                set ilast $i
246                incr i
247            }
248        }
249        -fraction {
250            set v0 [lindex $_axis 0]
251            set vend [lindex $_axis end]
252            return [expr {($value-$v0)/double($vend-$v0)}]
253        }
254        default {
255            error "bad flag \"$what\": should be -color or -fraction"
256        }
257    }
258}
259
260# ----------------------------------------------------------------------
261# CONFIGURATION OPTIONS: -units
262# ----------------------------------------------------------------------
263itcl::configbody Rappture::Spectrum::units {
264    if {"" != $units && [Rappture::Units::System::for $units] == ""} {
265        error "bad value \"$units\": should be system of units"
266    }
267    event !change
268}
Note: See TracBrowser for help on using the repository browser.