/// /// 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 } }