///
/// This file is part of ILNumerics Community Edition.
///
/// ILNumerics Community Edition - high performance computing for applications.
/// Copyright (C) 2006 - 2012 Haymo Kutschbach, http://ilnumerics.net
///
/// ILNumerics Community Edition is free software: you can redistribute it and/or modify
/// it under the terms of the GNU General Public License version 3 as published by
/// the Free Software Foundation.
///
/// ILNumerics Community Edition is distributed in the hope that it will be useful,
/// but WITHOUT ANY WARRANTY; without even the implied warranty of
/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
/// GNU General Public License for more details.
///
/// You should have received a copy of the GNU General Public License
/// along with ILNumerics Community Edition. See the file License.txt in the root
/// of your distribution package. If not, see .
///
/// In addition this software uses the following components and/or licenses:
///
/// =================================================================================
/// The Open Toolkit Library License
///
/// Copyright (c) 2006 - 2009 the Open Toolkit library.
///
/// Permission is hereby granted, free of charge, to any person obtaining a copy
/// of this software and associated documentation files (the "Software"), to deal
/// in the Software without restriction, including without limitation the rights to
/// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
/// the Software, and to permit persons to whom the Software is furnished to do
/// so, subject to the following conditions:
///
/// The above copyright notice and this permission notice shall be included in all
/// copies or substantial portions of the Software.
///
/// =================================================================================
///
using System;
using System.Collections.Generic;
using System.Text;
using System.Drawing;
using ILNumerics;
using ILNumerics.Drawing;
using ILNumerics.Drawing.Graphs;
using ILNumerics.Drawing.Shapes;
using ILNumerics.Drawing.Misc;
using ILNumerics.Drawing.Labeling;
namespace ILNumerics.Drawing.Plots {
///
/// surface plot supporting light and transparency
///
public sealed class ILLitSurface : ILPlot, Interfaces.IILPanelConfigurator {
#region attributes
protected ILColormap m_colorMap;
protected ILArray m_xVals = ILMath.returnType();
protected ILArray m_yVals = ILMath.returnType();
protected ILArray m_zVals = ILMath.returnType();
protected byte m_opacity = 255;
ILArray m_colorIndices = ILMath.returnType();
ILLitQuads m_quads;
#endregion
#region properties
///
/// Overall opacity for the surface
///
public byte Opacity {
get { return m_opacity; }
set {
m_opacity = value;
m_quads.Opacity = value;
Invalidate();
}
}
///
/// colormap used for coloring the surface
///
public ILColormap Colormap {
get { return m_colorMap; }
set {
m_colorMap = value;
Invalidate();
}
}
///
/// reference to the label for the surface
///
public ILShapeLabel Label {
get { return m_quads.Label; }
}
///
/// get a reference to the data values or sets it, used for updates to the plot
///
public ILRetArray XValues {
get { return m_xVals.C; }
set {
using (ILScope.Enter(value)) {
if (object.Equals(value, null)) {
m_xVals.a = ILMath.empty();
} else if (value.Size.IsSameSize(m_zVals.Size)) {
m_xVals.a = value.C;
Invalidate();
} else {
throw new ArgumentException("invalid size: XValues must be null or have the same size as ZValues");
}
}
}
}
///
/// get a reference to the data values or sets it, used for updates to the plot
///
public ILRetArray YValues {
get { return m_yVals; }
set {
using (ILScope.Enter(value)) {
if (object.Equals(value, null)) {
m_yVals.a = ILMath.empty();
} else if (value.Size.IsSameSize(m_zVals.Size)) {
m_yVals.a = value.C;
Invalidate();
} else {
throw new ArgumentException("invalid size: YValues must be null or have the same size as ZValues");
}
}
}
}
///
/// get a reference to the data values or sets it, used for updates to the plot
///
public ILRetArray ZValues {
get { return m_zVals; }
set {
using (ILScope.Enter(value)) {
if (value != null && (m_zVals.IsEmpty || value.Size.IsSameSize(m_zVals.Size))) {
m_zVals.a = value.C;
Invalidate();
} else {
throw new ArgumentException("invalid size: ZValues must be a matrix");
}
}
}
}
///
/// get a reference to the color index values or sets it, used for updates to the plot
///
public ILRetArray ColorIndices {
get { return m_colorIndices; }
set {
using (ILScope.Enter(value)) {
if (object.Equals(value, null)) {
m_colorIndices.a = ILMath.empty();
} else if (value.Size.IsSameSize(m_zVals.Size)) {
m_colorIndices.a = value.C;
Invalidate();
} else {
throw new ArgumentException("invalid size: ColorIndices must be null or have the same size as ZValues");
}
}
}
}
///
/// get reference to IILLitQuads lit composite shape used for rendering the surface
///
public ILLitQuads Quads {
get { return m_quads; }
}
#endregion
#region constructors
///
/// create new lit surface, provide data for X,Y and Z coordinates
///
/// the panel hosting the scene
/// X coordinates matrix, same size as Z or null
/// Y coordinates matrix, same size as Z or null
/// Z data matrix, at least 2 rows, 2 columns
/// colormap used for auto coloring the surface
public ILLitSurface(ILPanel panel, ILInArray Z, ILInArray X = null, ILInArray Y = null, ILColormap colormap = null, ILInArray colorIndices = null)
: base(panel) {
using (ILScope.Enter(X, Y, Z, colorIndices)) {
ZValues = ILMath.check(Z, (a) => { return (a.S[0] >= 2 || a.S[1] >= 2) ? Z : null; }, ErrorMessage: "invalid parameter: Z must be a matrix");
XValues = X;
YValues = Y;
ColorIndices = colorIndices;
m_quads = new ILLitQuads(panel, Z.S.NumberOfElements);
m_quads.Label.Text = "";
m_quads.Shading = ShadingStyles.Interpolate;
if (colormap == null) {
colormap = new ILColormap(Colormaps.ILNumerics);
}
Add(m_quads);
m_colorMap = colormap;
Invalidate();
}
}
#endregion
#region public interface
///
/// (re)configure the plot, causes a recreation of all quads due to changed parameters
///
internal override void Configure() {
if (m_invalidated) {
m_quads.Indices = Computation.configureVertices(
XValues,YValues,ZValues,
m_colorMap, m_quads.Vertices, m_opacity,
ColorIndices);
m_quads.Invalidate();
m_quads.Configure();
m_invalidated = false;
}
base.Configure();
}
#endregion
#region private helper
private class Computation : ILMath {
public static ILRetArray configureVertices(
ILInArray xVals, ILInArray yVals,
ILInArray zVals, ILColormap cmap, C4fN3fV3f[] Vertices, byte opacity,
ILInArray colors = null) {
using (ILScope.Enter(xVals,yVals,zVals)) {
int i = 0, x, y, y0 = zVals.Size[0] - 1;
x = 0;
y = 0;
ILArray colorIndices;
float minZ, maxZ;
// if matching colors were given, scale them to colormap range
// otherwise take zvalues as base
if (isnullorempty(colors) || !colors.S.IsSameShape(zVals.S)) {
if (!zVals.GetLimits(out minZ, out maxZ, false))
minZ = maxZ = 1.0f;
colorIndices = (tosingle((zVals - minZ) / (maxZ - minZ)))[":"] * (cmap.Length - 1);
} else {
if (!colors.GetLimits(out minZ, out maxZ, false))
minZ = maxZ = 1.0f;
colorIndices = (tosingle((colors - minZ) / (maxZ - minZ)))[":"] * (cmap.Length - 1);
}
colorIndices[isnan(colorIndices)] = 0;
bool useXvals = (xVals != null && !xVals.IsEmpty);
bool useYvals = (yVals != null && !yVals.IsEmpty);
foreach (float a in zVals) {
C4fN3fV3f v = Vertices[i];
v.Position = new ILPoint3Df(
(useXvals) ? xVals.GetValue(y, x) : x
, (useYvals) ? yVals.GetValue(y, x) : y0 - y
, a);
byte r, g, b;
cmap.Map(colorIndices.GetValue(i), out r, out g, out b);
v.Color = Color.FromArgb(255, r, g, b);
v.Alpha = opacity;
Vertices[i++] = v;
// set next position
if (++y >= zVals.S[0]) {
x++;
y = 0;
}
}
// create quad indices
int numQuad = (zVals.Size[0] - 1) * (zVals.Size[1] - 1);
x = 0; y = 0;
ILArray ret = zeros(4, numQuad);
ILArray mult = counter(0.0, 1.0, zVals.Size);
mult.a = mult["0:" + (zVals.Size[0] - 2), "0:" + (zVals.Size[1] - 2)];
mult.a = mult[":"].T;
ret["0;:"] = mult;
ret["3;:"] = mult + 1;
mult.a = mult + zVals.Size.SequentialIndexDistance(1);
ret["2;:"] = mult + 1;
ret["1;:"] = mult;
// remove quads having NaN values involved
return ret;
}
}
}
#endregion
#region IILPanelConfigurator Members
public void ConfigurePanel(ILPanel panel) {
panel.InteractiveMode = InteractiveModes.Rotating;
if (panel.AutoDefaultView) {
panel.DefaultView.EventingSuspend();
panel.DefaultView.SetDeg(-25, 45, 100);
panel.DefaultView.EventingResume(false);
}
panel.BackgroundFilled = false;
}
#endregion
}
}