source: branches/1.3/gui/scripts/color.tcl @ 4918

Last change on this file since 4918 was 3330, checked in by gah, 11 years ago

merge (by hand) with Rappture1.2 branch

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