source: trunk/gui/scripts/spectrum.tcl

Last change on this file was 6021, checked in by ldelgass, 9 years ago

Merge UQ and fixes from 1.4 branch

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