FE 'tkGooie' Utilities

IMAGEcreators
Shaded3D group

A Tk GUI to
Draw a
colored-DISK

with a centered
ColorGradient
and a
color-shaded, 3D-like
edge

(FE = Freedom Environment)

FE 'tkGooie' interface for
a maker of a color-shaded, 3D-like
DISK with centered color-gradient

FE Home Page > FE Downloads Page >

FE 'tkGooies' Description Page >

FE 'tkGooies' 'IMAGEcreators - Shaded3D' Page >

This 'draw_DISK_centeredColorGradient_colorShaded3D' tkGooie Page

INTRODUCTION to
a Tcl-Tk GUI to
'Draw a DISK with a centered ColorGradient
and a color-shaded 3D-like edge'

I am interested in making nice images for 'toolchest' and 'drawer' backgrounds (and other GUI embellishments), as I have indicated at wiki.tcl.tk (and on this freedomenv.com site) --- as indicated by

and

In 2012 early October, I posted code at wiki.tcl.tk, and later on this freedomenv.com site, for GUI for Drawing 'Gradient Spheres' (lighted disks), with lots of control, based on a 'demo script' of Keith Vetter, donated at wiki.tcl.tk many years ago.

Both Vetter's script and mine used a canvas-'create oval' technique to make the disk and its lighting.

However, in the past month, I have written several scripts that get better edge-shading at the outer edge of shapes, by using a canvas-'create image' technique.

Those scripts are posted at wiki.tcl.tk in pages titled

That sequence of scripts was set off by a wiki.tcl.tk posting by 'ulis' (deceased circa 2008) in which he used the canvas-'create image' (and 'put') technique to create one of these 'super' shapes --- with shading at the edge. I give credit here to 'ulis'. (R.I.P.)

These edge-shading scripts used the concept of a 'color-metric' --- a scalar function defined over the x,y pixels of a Tk canvas image.

The metric had the value 1.0 on the boundary of the shape, and the value zero in the center.

The metrics that I used for the 4 shapes above were

  • v = |x/a|^n + |y/b|^n --- for the super-ellipse

  • v = sqrt(x*x + y*y) / R(theta) --- for the super-formula

  • v = max(abs(x/xhalf), abs(y/yhalf)) --- for the rectangle

  • v = a * (rho - (R+r)/2) ^ 2,
    where the coefficient 'a' is given by
    1 / ((R-r)/2) ^ 2 --- for the donut (ring)

(See the page-links above for details.)

So I knew I should be able to devise a metric over the disk to achieve nice shading --- even though I wanted to keep the lighting effect on the disk, with nice shading of the lighting --- not just have nice shading at the outer edge of the disk.

More specifically, I wanted a Tk GUI script that 'draws' a color-filled 'disk shape' --- including shading to a 'background color' at the outer edge of the disk shape.

AND, to get an effect like a light-reflection in the middle, the disk includes shading from a 'lighting color' in the center to the 'disk color', as one moves outward from the center.

So there are 3 colors involved:

lighting-color --> disk-color --> background-color

going from the-center-of-the-disk to its-outer-edge.

Examples of use of this disk-shaped image:

  • At a large size, the 3D-looking disk image could be used as a background for a LOGO.

  • At a medium size, the image could be used as a background for an ICON.

  • At a small size, the image could be used as a 'BULLET' --- for line items on a web page or for menu items in a Tk GUI 'toolchest'.


DERIVATION OF A 'COLOR METRIC'
FOR THE '3-COLOR-GRADIENT DISK' :

Let 'R' be the radius of the outer edge of the circular disk.

We will let 'r' be the radius at which the 'lighting-color' at the center of the disk FINISHES transitioning to the 'disk-color'. Furthermore 'r' is the radius at which the 'disk-color' STARTS transitioning to the 'background color'.

Let any point x,y in the rectangular image area be measured from the center of the rectangular image.

Let 'rho' denote the radial distance of the point x,y from that center. So

rho(x,y) = sqrt (x*x + y*y)

We will, as a preliminary step, let our 'color-metric' be

v = rho(x,y) / r     when rho is between 0 and r

Note that v on this 'domain' is 0 at rho=0 and 1 at rho=r.

On the 'outer' part of the disk, we want v to be 0 at rho=r and v to be 1 at rho=R.

For rho between r and R

v = (rho(x,y) - r) / ( R - r)

looks like it will work.

This is a suitable metric if we apply it over the 2 different 'domains' to the 2 different color pairs.

---

Specifically, when rho(x,y) is between 0 and r, we get the color at the pixel x,y by the weighted average

(1 - v) * lighting-color + v * disk-color.

Check:

At x,y=0,0 , rho=0, so v = 0 and the equation reduces to the 'lighting-color', which is what we want.

And when x,y is such that rho=r, then v=1 and the equation reduces to the 'disk-color', which is what we want.

---

And when rho(x,y) is between r and R, we get the color at the pixel x,y by the weighted average

(1 - v) * disk-color + v * background-color.

Check:

When x,y is such that rho=r, then v=(r-r)/(R-r)=0 and the equation for the color at pixel x,y reduces to the 'disk-color', which is what we want.

When x,y is such that rho=R, then v=(R-r)/(R-r)=1 and the equation for the color at pixel x,y reduces to the 'background-color', which is what we want.

Now we have a suitable metric, v.


USING THE 'COLOR METRIC' TO COLOR A PIXEL
inside of (or outside of) the disk:

At a point x,y in the image rectangle, we determine

rho(x,y) = sqrt (x*x + y*y)

When 'rho' is greater than 'R', we can color the pixel with the 'background' color.

At a point x,y that is inside the disk (rho ≤ R) , we determine the 'shaded color' at the point by using one of the two 'v,1-v' equations.

We calculate the 'shaded color' at x,y by calculating a weighted average based on applying the factor (1.0 - v) to color1 --- and applying v to color2.

shaded-color = (1 - v) * color1 + v * color2

We actually calculate via formulas like

shaded-R = (1 - v) * R1 + v * R2
shaded-G = (1 - v) * G1 + v * G2
shaded-B = (1 - v) * B1 + v * B2

If x,y is such that rho=sqrt(x*x + y*y) is between 0 and r, then color1 and color2 will be the 'lighting' color and the 'disk' color.

If x,y is such that rho=sqrt(x*x + y*y) is between r and R, then color1 and color2 will be the 'disk' color and the 'background' color.

Thus we will get the two kinds of shading (lighting-shading and the 3D effect of edge-shading at the outer radius) for the 'disk shape'.

Note that over either domain --- 0 to r, or r to R --- if color1 = color2, then the color given by

(1 - v) * color1 + v * color2

is simply a constant color --- color1 = color2.


THE GUI DESIGN:

To create the Tk script, I used the code of the 'color-shaded donut' script (referenced above) as a starting point.

That GUI had most of the needed widgets.

Of course, the GUI made by this Tk script needs to contain a rectangular canvas widget on which the 3-color-gradient disk shape will be drawn.

I decided to put 3 'scale' widgets on the GUI --- whose slider-bars can be used to change the values of

  • ratio 'rOverR'
  • exponent M
  • exponent N

where the exponents are used to control 'extensity' of the shading. (The term 'extensity' is discussed at the bottom of this page.)

The 2 scales for the exponents M and N are used to control the intensity and extent of the shading --- which is achieved using the two color weighting factors v^M and (1.0 - v^M) over the 'domain' (0,r)--- and the two color weighting factors v^N and (1.0 - v^N) over the 'domain' (r,R).

Like in the other 'color-metric' GUI's, I used buttons to call on a color selector GUI --- to set the 3 colors involved --- 'lighting', 'disk', and 'background'.

    (I could add a checkbutton widget so that I could turn the 'edge-shading' on or off, but I did not do that.

    That's left as an exercise. But note that you can get the same effect by setting N real high.)

After some coding of a 'ReDraw' proc that uses the 'color-metric' to draw the shaded disk, I ended up with the following GUI --- and the code presented below.

Note that the 3 color buttons call on a color-selector-GUI script to set those colors.

You can make that color-selector script by cutting-and-pasting the code from the page that offers a non-obfuscated color selector GUI on this site.

---

Note that I include a display of 'elapsed time' for each redraw --- by using the Tcl 'clock milliseconds' command.

When I developed the script that I posted at wiki.tcl.tk, and on this site, at GUI for Drawing 'Super-ellipses', with nice shaded edges, I learned my lesson about needing to use braces with 'expr' statements --- for much better execution times.

    (Brent Welch et. al. point this out before page 8 in the 4th edition of 'Practical Programming in Tcl and Tk' --- although they do not use this advice in many 'expr' examples later in the book.)

It made a huge difference, so, in this script (and in all my Tk scripts henceforth), I consistently use braces with ALL 'expr' commands --- in particular, in the compute-intensive 'ReDraw' proc and in any procs that are called by 'ReDraw'.


DESCRIPTION OF THE CODE

Below is the code that produced this GUI.

There are comments at the top of the code, in a section titled 'USING THE GENERATED IMAGE', that describe how one could make use of images produced by this GUI.

I follow my usual 'canonical' structure for Tk code, for this Tk script:



  0) Set general window & widget parms (win-name, win-position,
     win-color-scheme, fonts, widget-geometry-parms, win-size-control).

  1a) Define ALL frames and sub-frames.
  1b) Pack   ALL frames and sub-frames.

  2) Define & pack all widgets in the frames.

  3) Define keyboard and mouse/touchpad/touch-sensitive-screen action
     BINDINGS, if needed.

  4) Define PROCS, if needed.

  5) Additional GUI initialization (typically with one or more of
     the procs), if needed.


This Tk coding structure is discussed in more detail on the page A Canonical Structure for Tk Code --- and variations.

This makes it easy for me to find code sections --- while generating and testing this script, and when looking for code snippets to include in other scripts.


Experimenting with the GUI

As in all my scripts that use the 'pack' geometry manager (which is all of my 100-plus Tk scripts, so far), I provide the four main pack parameters --- '-side', '-anchor', '-fill', and '-expand' --- on all the 'pack' commands for the frames and widgets.

I think I have found a good setting of the '-side', '-anchor', '-fill', and '-expand' parameters on the 'pack' commands for the various widgets of this GUI. In particular ...

The 'canvas' widget expands/contracts appropriately when the window size is changed --- and button and label widgets stay fixed in size and relative-location as the window size is changed.

If anyone wants to change the way the GUI configures itself as the main window size is changed, they can experiment with the '-side', '-anchor', '-fill', and '-expand' parameters on the 'pack' commands for the various widgets --- to get the widget behavior that they want.

For example, you may want the scale widgets to stay fixed in length, rather than x-expanding whenever the window is expanded in the x-direction.

---

Additional experimentation:
You might want to change the fonts used for the various GUI widgets. For example, you could change '-weight' from 'bold' to 'normal' --- or '-slant' from 'roman' to 'italic'. Or change font families.

In fact, you may NEED to change the font families, because the families I used may not be available on your computer --- and the default font that the 'wish' interpreter chooses may not be very pleasing.

I use variables to set geometry parameters of widgets --- parameters such as border-widths and padding. And I have included the '-relief' parameter on the definitions of frames and widgets. Feel free to experiment with those 'appearance' parameters as well.


Some features of the code

There are plenty of comments in the code to describe what most of the code-sections are doing.

See the top of the 'PROCS' section for a list of the procs used in this Tk script.

See comments in the procs for details on the purpose of each proc and for details on the methods by which each proc was implemented.

Here is a quick overview of the procs --- to give an idea of the 'guts' of this utility:



  - ReDraw                - called by button1-release bindings on several 
                            scale widgets, by the set-color procs,
                            and in the GUI initialization section at the
                            bottom of this script.

  - set_shape_color1      - called by the color1 ('lighting') button

  - set_shape_color2      - called by the color2 ('disk') button

  - set_background_color  - called by the background color button


The most complex code is in the 'ReDraw' proc. I attempted to significantly reduce the number of 'put' commands used to draw an image --- by using 'horizontal-scanlines' (of hex-colors) in the areas of the image where the color is totally the background color --- i.e. above and below the square containing the disk --- and on the left and right of that square.

By using the 'horizontal-scanlines' technique with the 'put' command, I was able to keep the draw times to about half a second for the default window/canvas size.

No doubt more draw-speed improvements could be made. (See the 'Enhancements' section below.)


A fervent hope

It is my hope that the copious comments in the code will help Tcl-Tk coding 'newbies' get started in making GUI's like this.

Without the comments --- especially in the 'ReDraw' proc --- the code would look like 'too much monkey business to be involved in', to quote Chuck Berry.

Without the comments, potential young Tcler's might be tempted to return to their iPhones and iPads and iPods --- to watch projectile vomiting videos.


The Tcl-Tk CODE

Here is a link to CODE for the Tk script
'make_colorDisk_ withCenteredColorGradient_ andWithShadedBorder.tk'.

With your web browser, you can 'right-click' on this link --- and in the menu that pops up, select an item like 'Save Link Target As ...' --- to save this file to your local computer.

Then you can rename the file to remove the '.txt' suffix. Make sure that you have execute permission set on the file --- in order to execute the script.


On the edge shading

The term 'extensity' on the GUI is meant to convey the fact that the exponents M and N control both the apparent intensity of a color at a boundary and the apparent extent of the color from the boundary.

By putting a scale widget on the GUI for adjusting a 'pow' (power) function exponent to change the 'extensity' of the shading --- at the outer edge of the disk (big R) --- and at the maximum extent of the high-lighting (little r), it is easy to find a most-pleasing shading effect.

I found that low powers (like 1 or 2) at the outer edge of the disk give a really washed-out edge to the disk where it meets the background color. I think you will find that a higher value (like 6) gives a good-looking edge.

That means that v^6 and (1 - v^6) gives a better border edge when blending the 'disk' color and the 'background' color to give the pixel color at an x,y near the outer boundary --- better than using the weighted average of the 2 colors using v and (1-v).


Off-center high-lighting
(an enhancement for the future)

If you look at the code for a GUI for Drawing 'Gradient Spheres' (lighted disks), with lots of control, you will see that Vetter's script and mine --- using the canvas-'create oval' technique --- included an extra feature.

Namely, the lighting was actually off-center.

In Vetter's script the 'high-light' was on the 'northwest' side of the disk --- in my script, you could set it to any of 8 compass points --- or center.

It turns out the math of getting a good 'color-metric' to achieve that effect may be rather messy.

You may end up with a quadratic equation to solve that has some really messy coefficients to calculate.

It might be actually easier to do the coding using an 'iterative numerical analysis' technique to find the 'root' ('zero') of the non-linear equation --- and it may even be computationally faster.

I may return to this script someday to enhance it --- to handle an off-center lighting effect --- and add a compass-points-options-widget to the GUI, like I had in the script at GUI for Drawing 'Gradient Spheres' (lighted disks), with lots of control.

That may give me an opportunity to implement and experiment with some non-linear equation solving procs --- using a bisection, Newton-Raphson, or secant method.


Some other possible FUTURE ENHANCEMENTS

It appears that one could make some quite high-quality 'bullet', 'button', icon-background, and logo-background images with this utility.

And I have the option of enhancing the Tk script on this page, to provide a few more capabilities to this 'color-shaded, 3D-like' image generator.

There are several items that I can foresee wanting to implement in the future to make this Tk script a little bit better:

  • Add a 'Help' button
    In the help text I would add how-to-use information --- such as:
    The user can control the size of the generated image by resizing the entire GUI window. That causes the Tk 'canvas' to resize, and the size of the image to generate is determined from the canvas size.

  • Add 2 widgets by which to set ImgWidth and ImgHeight (pixels) precisely
    This would allow the user to set the generated image size precisely.

  • Improve the draw-speed, by a factor of 2 or more
    As indicated above, we can improve the draw-speed significantly by saving up the hex-colors for pixels in a Tcl 'list' and then apply those colors to the image 'structure' one horizontal scan-line at a time.

    In fact, there is at least one small demo script on wiki.tcl.tk in which a Tcl-er has saved up all the hex-colors for an entire image (in a list of horizontal scan-line lists --- a list of lists) and applied all of them to the image 'structure' in one 'put' call.

    That may be worth a try with this utility. It might provide sub-second draw times, even when the image is the size of an entire computer monitor.

I may implement these enhancements sometime in the future.

(If I use this script as a starting point for another 'image-creator_color-shaded_3D-like' utility, then I will probably implement these enhancements in that new utility --- and then, perhaps, go back to this utility and implement the enhancements.)

You are welcome to take this code and add these enhancements --- and others.


IN CONCLUSION

As I have said on several other code-donation pages on this freedomenv.com site and on the Tclers' wiki at wiki.tcl.tk ...

There's a lot to like about a utility that is 'free freedom' --- that is, no-cost and open-source so that you can modify/enhance/fix it without having to wait for someone else to do it for you (which may be never).

A BIG THANK YOU to Ousterhout for starting Tcl-Tk, and a BIG THANK YOU to the Tcl-Tk developers and maintainers who have kept the simply MAH-velous 'wish' interpreter going.

Bottom of this page with
Tcl-Tk Code to
Draw a DISK with a centered ColorGradient
and a color-shaded, 3D-like edge

--- a utility in the FE 'tkGooies' system,
in the 'IMAGEcreatorsShaded3D' group.

To return to a previously visited web page location, click on the Back button of your web browser a sufficient number of times. OR, use the History-list option of your web browser.
OR ...

< Go to Top of Page, above. >

Page history:

The code was created in 2012 --- and posted 2012 Oct 28 at http://wiki.tcl.tk/37219.

This FE web page was created 2014 May 07 --- as a backup and alternative to the wiki.tcl.tk page.

This page was changed 2015 Oct 07.
(Small changes.)

Page was changed 2015 Dec 30.
(Added some paragraphs and some links.)

Page was changed 2019 Mar 01.
(Added css and javascript to try to handle text-size for smartphones, esp. in portrait orientation.)

Page was changed 2019 Jun 14.
(Specified image widths in percents to size the images according to width of the browser window.)


NOTE:
The code here MAY BECOME more 'up-to-date' than the code posted on the Tcler's Wiki ---
wiki.tcl-lang.org --- formerly wiki.tcl.tk.