Is there a Tcl function to map a monotonic varying value to a constant
intensity color that varies smoothly thru the rainbow?
TIA
Richard Owlett wrote:
> Is there a Tcl function to map a monotonic varying value to a constant
> intensity color that varies smoothly thru the rainbow?
Maybe a proc converting HSV color space to RGB color space is what you need.
H is hue and can have values 0 to 360 and S and V are Saturation of the
color and Value in the range from 0 to 1. Choose the Saturation and Value
and use H to wander the trough the rainbow...
Below is a hsv2rgb-proc, that I use in one of my packages.
HTH
Stephan
----------------------------------------------------------------------------
proc hsv2rgb {h s v} {
# hsv2rgb
# @param h: Hue in the range of 0-360 float
# @param s: Saturation in the range of 0-1 float
# @param v: Value in the range of 0-1 float
# @return list r, g, b (0-255 int)
set hi [expr {int($h/60.0)%6}]
set f [expr {($h/60.0)-$hi}]
set p [expr {$v*(1-$s)}]
set q [expr {$v*(1-($f*$s))}]
set t [expr {$v*(1-((1.0-$f)*$s))}]
if {$hi==0} {
set r $v
set g $t
set b $p
} elseif {$hi==1} {
set r $q
set g $v
set b $p
} elseif {$hi==2} {
set r $p
set g $v
set b $t
} elseif {$hi==3} {
set r $p
set g $q
set b $v
} elseif {$hi==4} {
set r $t
set g $p
set b $v
} elseif {$hi==5} {
set r $v
set g $p
set b $q
}
return [list [expr {int($r*255)}] [expr {int($g*255)}] [expr
{int($b*255)}]]
} ;# proc hsv2rgb {h s v}
Your description matches well with what I was trying to say. If V is
what is often called "luminance" in TV, then it's just what I'm looking for.
I'll have to run some test cases to see if result matches my
visualization. IOW does my specification match my desires ;}
Thanks.
I wanted to do a preliminary test.
I loaded above code by doing a cut-n-paste.
I then entered:
hsv2rgb {5.0 0.3 0.4}
The response was:
wrong # args: should be "expr arg ?arg ...?"
What *DUMB* newbie mistake maketh i ;{
Remove the newline which breaks up the return statement. That's supposed
to be a single line.
And I think you meant that you entered:
hsv2rgb 5.0 0.3 0.4
HTH,
Gerry
NOPE :<
Same error whether I enter
hsv2rgb 5.0 0.3 0.4
or
hsv2rgb {5.0 0.3 0.4}
I've done enough training that I suspect I'm making a *REALLY* dumb error ;<
Did you do the above, the first part of my reply?
The error comes from the line:
return [list [expr {int($r*255)}] [expr {int($g*255)}] [expr
Gerry
I suspect I've made VERY fundamental mistake
my session is as follows
(bin) 1 %
(bin) 1 % proc hsv2rgb {h s v} {
> return [list [expr {int($r*255)}] [expr {int($g*255)}] [expr
> {int($b*255)}]]
> } ;# proc hsv2rgb {h s v}
(bin) 2 %
(bin) 2 % hsv2rgb 5.0 0.3 0.4
wrong # args: should be "expr arg ?arg ...?"
(bin) 3 %
I'm using Wish84 from ActiveState under WindowsXP Pro
These last two lines need to be made into a single line, or changed to:
return [list [expr {int($r*255)}] [expr {int($g*255)}] [expr \
{int($b*255)}]]
The last expr is not on the same line as its argument. The email system
broke up one long line into two lines in Stephan's posting. You need to
make it back into one line, or tell Tcl that there is a continuation.
HTH,
Gerry
> What *DUMB* newbie mistake maketh i ;{
As Garry already said, there was a line continuation problem in the
posting. Here is a small script, that contains hsv2rgb and some lines
of a demo how to use it. You should run it with wish or tclsh
(requires Tk). It opens a window with a label showing the color and
three sliders with H, S, V from top to down. Try the H-slider to
wander through colors.
http://www.mempool.net/colors.tcl
Stephan
Is there any reason for the if-elseif-...-else construct in favour of a
simple switch?
just curious.
--
Pozdrawiam! (Regards!)
Googie
Speed.
Normally this is not a problem, because it does not matter, if
execution is a millisecond faster or slower. But I wrote a color
selection dialog in pure Tk (the build in dialog is very outdated and
the dialogs I found at the wiki did not really satisfy me) with real
time updates of RGB- and HSV-sliders and a color field (much like the
color dialog of gimp, if you know that one), where I used as much
optimizations as possible (that's why the proc also does no range- or
type-checks for the arguments, but the public wrapper of the proc
does). I wanted at least 20 or more frames per second for calculating
all widget settings and updates of the color field on my 2.1 GHz
MacBook and I got them (even more)...
I will release the dialog and the procs for conversion as hsv2rgb and
as open source soon (some weeks, since I'm moving to a new
apartment...) as a package. Tk will have a fairly decent color
selection dialog then.
Stephan
Hmm, don't remember exactly since when switch gets bytecompiled,
either in the 8.4 series or only in 8.5, then it should no longer make
a difference.
Michael
I think, it does:
------------------------------------------------------------------------------------------------------------
proc switchTest {v} {
switch $v {
0 { set result 0 }
1 { set result 1 }
2 { set result 2 }
3 { set result 3 }
4 { set result 4 }
default { set result -1 }
}
return $result
}
proc ifElseTest {v} {
if {$v == 0} {
set result 0
} elseif {$v == 1} {
set result 1
} elseif {$v == 2} {
set result 2
} elseif {$v == 3} {
set result 3
} elseif {$v == 4} {
set result 4
} else {
set result -1
}
return $result
}
set values {0 1 2 3 4 5}
puts "switch [time { foreach v $values {switchTest $v} } 10000]"
puts "ifelse [time { foreach v $values {ifElseTest $v} } 10000]"
------------------------------------------------------------------------------------------------------------
When running with tcl 8.4.14 on Linux Fedora 7 on a P...@3.00GHz the
results are
switch 20.7521 microseconds per iteration
ifelse 16.5151 microseconds per iteration
The same with tcl 8.5a6:
switch 38.6253 microseconds per iteration
ifelse 16.6042 microseconds per iteration
The difference is even greater as in tcl 8.4...
Regards
Stephan
> schl...@uni-oldenburg.de wrote:
>> Hmm, don't remember exactly since when switch gets bytecompiled, either
>> in the 8.4 series or only in 8.5, then it should no longer make a
>> difference.
>
> I think, it does:
>
> When running with tcl 8.4.14 on Linux Fedora 7 on a P...@3.00GHz the
> results are
> switch 20.7521 microseconds per iteration
> ifelse 16.5151 microseconds per iteration
>
> The same with tcl 8.5a6:
> switch 38.6253 microseconds per iteration
> ifelse 16.6042 microseconds per iteration
>
> The difference is even greater as in tcl 8.4...
That is because [switch] is bugged in 8.5a6.
[code]
proc switchTest2 {v} {
switch -exact -- $v {
0 { set result 0 }
1 { set result 1 }
2 { set result 2 }
3 { set result 3 }
4 { set result 4 }
default { set result -1 }
}
return $result
}
[/code]
switch 15.9789 microseconds per iteration
ifelse 11.2008 microseconds per iteration
switc2 9.6635 microseconds per iteration
This with 8.5a6.
--
-Kaitzschu
s="TCL ";while true;do echo -en "\r$s";s=${s:1:${#s}}${s:0:1};sleep .1;done
"Good thing programmers don't build bridges
[the same way as Kaitzschu writes code]."
--John Kelly in comp.lang.tcl
> That is because [switch] is bugged in 8.5a6.
...
> switch 15.9789 microseconds per iteration
> ifelse 11.2008 microseconds per iteration
> switc2 9.6635 microseconds per iteration
Thanks for the information. I will wait for newer versions of tcl 8.5 and
possibly use switch for 8.5 and if-else for 8.4.
Regards
Stephan
Don't wait, and don't switch. Unless that if or switch is in a tight
loop the speed difference is a moot point. Optimize your code for
readability and maintainability, and only focus on raw performance when
you can measure a performance bottleneck.
--
Bryan Oakley
http://www.tclscripting.com
No, just put the -- in so that you no longer have problems waiting to
jump up and bite you. (And as a bonus, 8.5 will then become able to
compile it for you.)
Donal.
I think, my code for the color selection dialog is very clean so far,
but OTOH I need to optimize all parts because of the real time updates
of the color field. Otherwise the dialog will be unusable on not so
fast systems. Currently it runs very good on 3GHz P4 and 2.1GHz
CoreDuo and is usable on a lousy 800MHz PowerPC G3 (!) and I can live
with the performance even on a Nokia N800 Handheld. But for this I had
to optimize every bit and line. And, of course, it's only a fun
project... So if I have to create two versions of some calls because
of those performance differences between [if] and [switch] to gain 0.5
fps an the N800, I will do so... ;-)
But for the bread and butter work I agree completely with you: I
optimize only where it's really needed and effective and focus on
good, clean and well documented code.
Regards
Stephan
I will add the "--", thanks.
For the 8.4 vs. 8.5 optimizations I like to add something: I think,
8.5 is overdue for some years now, and although first beta is expected
every day now, we have to admit, that Tcl is 8.4 and not 8.5 and I'm
sure, it will be this way for some time. Even if 8.5 is launched end
of the year or Q1-3 2008 (there are always reasons for unexpected
delays...), 8.4 will be with us for a long time and many distributions
of embedded devices (such as my N800) and others will work with that
version. To ignore 8.4 specifics in optimization (if one bothers to
optimize) would mean to ignore the fact, that Tcl is a *very* slow
moving target...
Besides that: I'm really fidgeting in my seat anticipating 8.5 and
would normally give the same advice as Brian Oakley and you did.
Regards
Stephan
More generally, how are you handling "two versions of
some calls"? My favorite for general situations of
your description is something like this:
switch $the_situation {
one_environment {
proc important_proc1 ...
proc important_proc1 ...
...
}
other_environment {
proc important_proc1 ...
proc important_proc1 ...
...
}
...
}
do_the_real_work
This makes for a nice combination of run-time initialization
and optimization.
> More generally, how are you handling "two versions of
> some calls"? My favorite for general situations of
> your description is something like this:
...
> This makes for a nice combination of run-time initialization
> and optimization.
My approach is similar, but I try to generalize my procs a little bit
more. In such a case where only parts of the thing differ as with
[switch] vs. [if-else], I do something like the following:
---
set body {
code_for_the_proc
%specialization%
more_code
}
switch -- $condition {
c1 {
set code { something}
}
...
default {
set code { something_default }
}
}
proc theProc {the args} [string map [list %specialization% $code ...]
$body]
proc otherProc {the args} [string map [list %other_specialization%
$other_code ...] $body]
...
---
This way I have only one version of a proc body to maintain and can
focus on the specializations only.
Regards
Stephan