source: trunk/gui/scripts/color.tcl @ 2742

Last change on this file since 2742 was 1929, checked in by gah, 14 years ago
File size: 7.1 KB
Line 
1# ----------------------------------------------------------------------
2#  UTILITY: color
3#
4#  This file contains various utility functions for manipulating
5#  color values.
6# ======================================================================
7#  AUTHOR:  Michael McLennan, Purdue University
8#  Copyright (c) 2004-2005  Purdue Research Foundation
9#
10#  See the file "license.terms" for information on usage and
11#  redistribution of this file, and for a DISCLAIMER OF ALL WARRANTIES.
12# ======================================================================
13
14namespace eval Rappture::color { # forward declaration }
15
16# ---------------------------------------------------------------------
17# USAGE: brightness <color> <fraction>
18#
19# Used to brighten or dim a Tk <color> value by some +/- <fraction> in
20# the range 0-1.  Returns another color in the same hue, but with
21# different brighness.
22# ----------------------------------------------------------------------
23proc Rappture::color::brightness {color frac} {
24    foreach {h s v} [Rappture::color::RGBtoHSV $color] { break }
25    set v [expr {$v+$frac}]
26
27    # if frac overflows the value, pass changes along to saturation
28    if {$v < 0} {
29        set s [expr {$s+$v}]
30        if {$s < 0} { set s 0 }
31        set v 0
32    }
33    if {$v > 1} {
34        set s [expr {$s-($v-1)}]
35        if {$s < 0} { set s 0 }
36        set v 1
37    }
38
39    return [Rappture::color::HSVtoRGB $h $s $v]
40}
41
42# ---------------------------------------------------------------------
43# USAGE: brightness_min <color> <min>
44#
45# Used to make sure a color is not too dim.  If the value is less
46# than the <min>, then it is capped at that value.  That way, the
47# return color shows up against black.
48# ----------------------------------------------------------------------
49proc Rappture::color::brightness_min {color min} {
50    foreach {h s v} [Rappture::color::RGBtoHSV $color] { break }
51    if {$v < $min} {
52        set v $min
53    }
54    return [Rappture::color::HSVtoRGB $h $s $v]
55}
56
57# ---------------------------------------------------------------------
58# USAGE: brightness_max <color> <max>
59#
60# Used to make sure a color is not too dim.  If the value is less
61# than the <min>, then it is capped at that value.  That way, the
62# return color shows up against black.
63# ----------------------------------------------------------------------
64proc Rappture::color::brightness_max {color max} {
65    foreach {h s v} [Rappture::color::RGBtoHSV $color] { break }
66    if {$v > $max} {
67        set v $max
68    }
69    return [Rappture::color::HSVtoRGB $h $s $v]
70}
71
72# ---------------------------------------------------------------------
73# USAGE: RGBtoHSV <color>
74#
75# Used to convert a Tk <color> value to hue, saturation, value
76# components.  Returns a list of the form {h s v}.
77# ----------------------------------------------------------------------
78proc Rappture::color::RGBtoHSV {color} {
79    #
80    # If the colors are exhausted sometimes winfo can fail with a
81    # division by zero.  Catch it to avoid problems.
82    #
83    if { [catch {winfo rgb . $color} status] != 0 } {
84        set s 0
85        set v 0
86        set h 0
87        return [list $h $s $v]
88    }
89    foreach {r g b} $status {}
90    set min [expr {($r < $g) ? $r : $g}]
91    set min [expr {($b < $min) ? $b : $min}]
92    set max [expr {($r > $g) ? $r : $g}]
93    set max [expr {($b > $max) ? $b : $max}]
94
95    set v [expr {$max/65535.0}]
96
97    set delta [expr {$max-$min}]
98
99    if { $delta == 0 } {
100        # delta=0 => gray color
101        set s 0
102        set v [expr {$r/65535.0}]
103        set h 0
104        return [list $h $s $v]
105    }
106 
107    if {$max > 0} {
108        set s [expr {$delta/double($max)}]
109    } else {
110        # r=g=b=0  =>  s=0, v undefined
111        set s 0
112        set v 0
113        set h 0
114        return [list $h $s $v]
115    }
116
117    if {$r == $max} {
118        set h [expr {($g - $b)/double($delta)}]
119    } elseif {$g == $max} {
120        set h [expr {2 + ($b - $r)/double($delta)}]
121    } else {
122        set h [expr {4 + ($r - $g)/double($delta)}]
123    }
124    set h [expr {$h*1.04719756667}] ;# *60 degrees
125    if {$h < 0} {
126        set h [expr {$h+6.2831854}]
127    }
128    return [list $h $s $v]
129}
130
131# ---------------------------------------------------------------------
132# USAGE: HSVtoRGB <color>
133#
134# Used to convert hue, saturation, value for a color to its
135# equivalent RGB form.  Returns a prompt Tk color of the form
136# #RRGGBB.
137# ----------------------------------------------------------------------
138proc Rappture::color::HSVtoRGB {h s v} {
139    if {$s == 0} {
140        set v [expr round(255*$v)]
141        set r $v
142        set g $v
143        set b $v
144    } else {
145        if {$h >= 6.28318} {set h [expr $h-6.28318]}
146        set h [expr $h/1.0472]
147        set f [expr $h-floor($h)]
148        set p [expr round(255*$v*(1.0-$s))]
149        set q [expr round(255*$v*(1.0-$s*$f))]
150        set t [expr round(255*$v*(1.0-$s*(1.0-$f)))]
151        set v [expr round(255*$v)]
152
153        switch [expr int($h)] {
154            0 {set r $v; set g $t; set b $p}
155            1 {set r $q; set g $v; set b $p}
156            2 {set r $p; set g $v; set b $t}
157            3 {set r $p; set g $q; set b $v}
158            4 {set r $t; set g $p; set b $v}
159            5 {set r $v; set g $p; set b $q}
160        }
161    }
162    return [format "#%.2x%.2x%.2x" $r $g $b]
163}
164
165# ---------------------------------------------------------------------
166# USAGE: wave2RGB <wavelength>
167#
168# Given a visible wavelength in nm, returns a Tk color of the form
169# #RRGGBB. Returns black for nonvisible wavelengths.  Based on code from
170# Dan Bruton (astro@tamu.edu) http://www.physics.sfasu.edu/astro/color/spectra.html
171# ----------------------------------------------------------------------
172
173proc Rappture::color::wave2RGB {wl} {
174
175    # strip off any units
176    set wl [string trimright $wl "nm"]
177
178    if {$wl < 380 || $wl > 780} {
179        return black
180    }
181    set gamma 0.8
182    set r 0.0
183    set g 0.0
184    set b 0.0
185    if {$wl <= 440} {
186        set r [expr (440.0 - $wl) / 60.0]
187        set b 1.0
188    } elseif {$wl <= 490} {
189        set g [expr ($wl - 440.0) / 50.0]
190        set b 1.0
191    } elseif {$wl <= 510} {
192        set g 1.0
193        set b [expr (510.0 - $wl) / 20.0]
194    } elseif {$wl <= 580} {
195        set g 1.0
196        set r [expr ($wl - 510.0) / 70.0]
197    } elseif {$wl <= 645} {
198        set r 1.0
199        set g [expr (645.0 - $wl) / 65.0]
200    } else {
201        set r 1.0
202    }
203
204    if {$wl > 700} {
205        set sss [expr 0.3 + 0.7 * (780.0 - $wl) / 80.0]
206    } elseif {$wl < 420} {
207        set sss [expr 0.3 + 0.7 * ($wl - 380.0) / 40.0]
208    } else {
209        set sss 1.0
210    }
211    set r [expr int(255.0 * pow(($sss * $r), $gamma))]
212    set g [expr int(255.0 * pow(($sss * $g), $gamma))]
213    set b [expr int(255.0 * pow(($sss * $b), $gamma))]
214    return [format "#%.2X%.2X%.2X" $r $g $b]
215}
216
217# Returns a list containing three decimal values in the range 0 to 65535,
218# which are the red, green, and blue intensities that correspond to color
219# in the window given by window. Color may be specified in any of the forms
220# acceptable for a color option.
221proc Rappture::color::RGB {color} {
222    if {[string match "*nm" $color]} {
223        set color [Rappture::color::wave2RGB [string trimright $color "nm"]]
224    }
225    return [winfo rgb . $color]
226}
Note: See TracBrowser for help on using the repository browser.