2013-05-31 2 views
3

Я хочу создать 3D-график поверхности, как показано на рисунке. Я использую ILNumerics, recent RC from the website. До сих пор я мог бы создать поверхность (данные только для тестирования), используя этот код:3D-окраска поверхности с особыми знаками 4-го измерения

using System; 
using System.Drawing; 
using System.Windows.Forms; 
using ILNumerics; 
using ILNumerics.Drawing; 
using ILNumerics.Drawing.Plotting; 

namespace WindowsFormsApplication1 { 
    public partial class Form1 : Form { 
     public Form1() { 
      InitializeComponent(); 
     } 

    private void ilPanel1_Load(object sender, EventArgs e) { 
     using (ILScope.Enter()) { 
      ILArray<float> R = ILMath.linspace<float>(-4, 4, 100); 
      ILArray<float> y = 1; 
      ILArray<float> x = ILMath.meshgrid(R, R, y); 

      ILArray<float> Z = ILMath.zeros<float>(x.S[0], x.S[1], 3); 
      Z[":;:;1"] = x; Z[":;:;2"] = y; 
      Z[":;:;0"] = 0.4f * x * x - 0.2f * y * y * y; 

      ilPanel1.Scene.Add(new ILPlotCube(twoDMode: false) { 
       new ILSurface(Z, colormap: Colormaps.Cool) { 
        Colors = 1.4f * x * x * x + 0.13f * y * y, 
        Childs = { new ILColorbar() } 
       } 
      }); 
     } 
    } 
    } 
} 

surface graph without marked values

Что является лучшим способом, чтобы пометить все фасеток с (цвет) значения данных 0 в другой цвет? Вероятно, использование цветовой панели было бы способом? Но как именно это делается?

ответ

3

Этого можно достичь с помощью пользовательской цветовой карты. Но нужно позаботиться, чтобы сделать это надежно. Простое размещение новой красной ключевой точки в середине цветовой карты даст очень неправильные результаты ...: |

Я слегка изменил и задокументировал ваш пример. В принципе, в цветовых картах содержатся ключевые точки с положением и цветом. Позиции обычно (но не обязательно) варьируются от [0..1]. Цвета всегда находятся в диапазоне [0..1]. Задача здесь состоит в том, чтобы найти правильную позицию вашего значения «0» cdata в диапазоне цветовых диапазонов.

Во-первых, создайте стандартную цветовую карту Cool. Она имеет следующие два ключевые точки (в строках):

colorkeys 
<Single> [2,5] 
    [0]: 0,00000 0,00000 1,00000 1,00000 1,00000 <- position: 0, color: RGBA 
    [1]: 1,00000 1,00000 0,00000 1,00000 1,00000 <- position: 1 

Вы должны добавить по крайней мере 3 новые ключевые точки: первые два образца оригинального цвета по краям выделенной области. Третий дает отмеченную область красного цвета. Это не будет работать, чтобы просто добавить красную характерную точку, так как это будет влиять на все значения в карте, а не только значения данных около 0.

В конце концов ключевых точек выглядит следующим образом:

colorkeys 
<Single> [5,5] 
    [0]: 0,00000 0,00000 1,00000 1,00000 1,00000 
    [1]: 1,00000 1,00000 0,00000 1,00000 1,00000 
    [2]: 0,49150 0,49150 0,50850 1,00000 1,00000 
    [3]: 0,49702 0,49702 0,50298 1,00000 1,00000 
    [4]: 0,49426 1,00000 0,00000 0,00000 1,00000 

Обратите внимание, что порядок ключевых точек не важен. В любом случае они сортируются при создании новой цветовой карты. Новая карта просто предоставляется ILSurface:

private void ilPanel1_Load(object sender, EventArgs e) { 

    // create some X/Y meshgrid data 
    ILArray<float> y = 1, R = ILMath.linspace<float>(-4, 4, 100); 
    ILArray<float> x = ILMath.meshgrid(R, ILMath.linspace<float>(-4, 4, 100), y); 

    // precreate the surface data array 
    ILArray<float> Z = ILMath.zeros<float>(x.S[0], x.S[1], 3); 
    // surface expects Z, X and Y coords (in that order) 
    Z[":;:;2"] = y; Z[":;:;1"] = x; 
    Z[":;:;0"] = 0.4f * x * x - 0.2f * y * y * y; 

    // our color data are based on another function 
    ILArray<float> cdata = 1.4f * x * x * x + 0.13f * y * y; 

    // we need cdatas limits for creating a new colormap 
    float min, max; cdata.GetLimits(out min, out max); 

    // get default 'Cool' colormap 
    var colormap = new ILColormap(Colormaps.Cool); 
    // get colormap keys as array: [position,R,G,B,A] 
    ILArray<float> colorkeys = colormap.Data; 
    // helper function to map true values to 0..1 range 
    Func<float, float> map = a => { return (a - min)/(max - min); }; 

    // the value to mark and +/- tolerance width (to make it a visible strip at least) 
    float markValue = 0, tolerance = 0.5f; 
    // sample the colormap at the marked edges 
    Vector4 key1 = colormap.Map(markValue - tolerance, new Tuple<float, float>(min, max)); 
    Vector4 key2 = colormap.Map(markValue + tolerance, new Tuple<float, float>(min, max)); 
    // create new keypoints at the edges of marked area 
    colorkeys[ILMath.end + 1, ":"] = ILMath.array(map(markValue - tolerance), key1.X, key1.Y, key1.Z, 1f); 
    colorkeys[ILMath.end + 1, ":"] = ILMath.array(map(markValue + tolerance), key2.X, key2.Y, key2.Z, 1f); 
    // create new keypoint for the marked area itself; color red 
    colorkeys[ILMath.end + 1, ":"] = ILMath.array(map(markValue), 1f, 0f, 0f, 1f); // red 
    // make a new colormap out of it 
    colormap = new ILColormap(colorkeys); 
    // create & add a plot cube 
    ilPanel1.Scene.Add(new ILPlotCube(twoDMode: false) { 
     // add surface plot, give custom colormap & colormap data ... 
     new ILSurface(Z, colormap: colormap, C: cdata) { 
      // add colorbar 
      Childs = { new ILColorbar() } 
     } 
    }); 
} 

Это производит этот выход: enter image description here

+0

Большой материал! Но для меня это выглядит по-другому. Цвета не работают так гладко, как на картинке. Кажется, вы используете моно для рендеринга. Является ли это обычной дисперсией вывода между различными рендерами/фреймами? – user492238

+1

Нет. Вывод * очень * похож на всех платформах, независимо от того, использует ли он OpenGL, GDI или SVG. Вероятно, вы испытали ошибку. Вот ссылка на последний RC: http://ilnumerics.net/release/EUJJRWPO225PlHDjW09/ILNumerics_v3.0_RCh.zip –

+1

Работает для меня. Интересно, если то же самое нельзя было сделать и в индивидуальном цветовом режиме? Я имею в виду, если я дам каждой точке сетки отдельный цвет? –

 Смежные вопросы

  • Нет связанных вопросов^_^