1

I am using ILNumerics to generate a surface plot.

I want to use a flat shaded color map (i.e. color ranges) instead of a smooth shaded color map (i.e. each pixel has it's own color).

Is this possible with ILNumerics?

Example of Flat-Shaded surface plot and color bar legend:

Flat Surface Plot Flat Color Map

Example of Smooth-Shaded surface plot and color bar legend:

Smooth Surface Plot Smooth Color Map

JRS
  • 1,438
  • 2
  • 16
  • 26

2 Answers2

1

This is not possible. Surface plots in ILNumerics always interpolate colors between grid points. For other shading models you must create your own surface class.

user492238
  • 4,094
  • 1
  • 20
  • 26
1

You can create a colormap which exposes a flat shading behavior. Just duplicate the keypoints existing in a common colormap in order to model a range of color data getting the same color assigned.

How flat shaded colormaps are working

According to the documentation the keypoints for colormaps consist out of 5 columns: a "position" and 4 color values (RGBA). In order to model a 'flat' shaded colormap, place two keypoints 'almost' exactly on top of each other, giving the first one the color of the next lower range and the second one the color of the next higher range. A color range therefore is modeled by two keypoints having the same color assigned.

I wrote 'almost' in the above paragraph, because I thought you have to leave at least a tiny gap between the edges of two ranges - hoping no actual color data value will ever hit that gap. But it seems, there is no gap needed at all and one can give both keypoints exactly the same value. But you will have to be careful while sorting: don't mix the colors up (the quicksort in ILMath.sort() is not stable!)

In the following example a flat shaded colormap is created from Colormaps.Jet:

Keypoints for Colormaps.Jet (original, interpolating)
<Single> [6,5]
[0]:          0          0          0     0,5625          1 
[1]:     0,1094          0          0     0,9375          1 
[2]:     0,3594          0     0,9375          1          1 
[3]:     0,6094     0,9375          1     0,0625          1 
[4]:     0,8594          1     0,0625          0          1 
[5]:          1     0,5000          0          0          1 

The flat shading version derived from it:

Colormaps.Jet - flat shading version
<Single> [11,5]
[0]:          0          0          0     0,5625          1 
[1]:     0,1094          0          0     0,5625          1 
[2]:     0,1094          0          0     0,9375          1 
[3]:     0,3594          0          0     0,9375          1 
[4]:     0,3594          0     0,9375          1          1 
[5]:     0,6094          0     0,9375          1          1 
[6]:     0,6094     0,9375          1     0,0625          1 
[7]:     0,8594     0,9375          1     0,0625          1 
[8]:     0,8594          1     0,0625          0          1 
[9]:     1,0000          1     0,0625          0          1 
[10]:          1     0,5000          0          0          1 

As you can easily see, I made a mistake in CreateFlatShadedColormap(): The last keypoint with (0.5,0,0,1) will never be used. I'll leave it as an exercise to fix that... ;)

Full Flat Shaded Example

private void ilPanel1_Load(object sender, EventArgs e) {
    ILArray<float> A = ILMath.tosingle(ILSpecialData.terrain["0:400;0:400"]);
    // derive a 'flat shaded' colormap from Jet colormap
    var cm = new ILColormap(Colormaps.Jet);
    ILArray<float> cmData = cm.Data;
    cmData.a = Computation.CreateFlatShadedColormap(cmData);
    cm.SetData(cmData); 
    // display interpolating colormap
    ilPanel1.Scene.Add(new ILPlotCube() { 
        Plots = {
            new ILSurface(A, colormap: Colormaps.Jet) {
                Children = { new ILColorbar() },
                Wireframe = { Visible = false }
            }
        }, 
        ScreenRect = new RectangleF(0,-0.05f,1,0.6f)
    }); 

    // display flat shading colormap
    ilPanel1.Scene.Add(new ILPlotCube() {
        Plots = {
            new ILSurface(A, colormap: cm) {
                Children = { new ILColorbar() },
                Wireframe = { Visible = false }
            }
        },
        ScreenRect = new RectangleF(0, 0.40f, 1, 0.6f)
    }); 

}

private class Computation : ILMath {
    public static ILRetArray<float> CreateFlatShadedColormap(ILInArray<float> cm) {
        using (ILScope.Enter(cm)) {
            // create array large enough to hold new colormap
            ILArray<float> ret = zeros<float>(cm.S[0] * 2 - 1, cm.S[1]);
            // copy the original
            ret[r(0, cm.S[0] - 1), full] = cm; 
            // double original keypoints, give small offset (may not even be needed?) 
            ret[r(cm.S[0], end), 0] = cm[r(1, end), 0] - epsf;
            ret[r(cm.S[0], end), r(1, end)] = cm[r(0, end - 1), r(1, end)];
            // reorder to sort keypoints in ascending order
            ILArray<int> I = 1;
            sort(ret[full, 0], Indices: I);
            return ret[I, full];
        }

    }

Result

Flat Shaded Colormaps in ILNumerics

Haymo Kutschbach
  • 3,322
  • 1
  • 17
  • 25
  • Although I accepted this answer, the plot is still not flat shaded. This can be easily seen by zooming in or with less dense data sets. As @user492238 noted, colors are always interpolated (smooth shaded) between data points. – JRS Jul 29 '14 at 16:02
  • Right. If you happen to have tiles which pick different colors for any of their vertices the color will still be interpolated. I wonder how your flat shaded surface is defined to handle such cases? Which color would be used for the whole tile area than? A color corresponding to an average value? But what would this be useful for? Also, consider updating your question, because it refers to "a flat shaded *color map*". This is what the answer gives. – Haymo Kutschbach Jul 29 '14 at 16:52