1 | ///
|
---|
2 | /// This file is part of ILNumerics Community Edition.
|
---|
3 | ///
|
---|
4 | /// ILNumerics Community Edition - high performance computing for applications.
|
---|
5 | /// Copyright (C) 2006 - 2012 Haymo Kutschbach, http://ilnumerics.net
|
---|
6 | ///
|
---|
7 | /// ILNumerics Community Edition is free software: you can redistribute it and/or modify
|
---|
8 | /// it under the terms of the GNU General Public License version 3 as published by
|
---|
9 | /// the Free Software Foundation.
|
---|
10 | ///
|
---|
11 | /// ILNumerics Community Edition is distributed in the hope that it will be useful,
|
---|
12 | /// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
---|
13 | /// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
---|
14 | /// GNU General Public License for more details.
|
---|
15 | ///
|
---|
16 | /// You should have received a copy of the GNU General Public License
|
---|
17 | /// along with ILNumerics Community Edition. See the file License.txt in the root
|
---|
18 | /// of your distribution package. If not, see <http://www.gnu.org/licenses/>.
|
---|
19 | ///
|
---|
20 | /// In addition this software uses the following components and/or licenses:
|
---|
21 | ///
|
---|
22 | /// =================================================================================
|
---|
23 | /// The Open Toolkit Library License
|
---|
24 | ///
|
---|
25 | /// Copyright (c) 2006 - 2009 the Open Toolkit library.
|
---|
26 | ///
|
---|
27 | /// Permission is hereby granted, free of charge, to any person obtaining a copy
|
---|
28 | /// of this software and associated documentation files (the "Software"), to deal
|
---|
29 | /// in the Software without restriction, including without limitation the rights to
|
---|
30 | /// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
---|
31 | /// the Software, and to permit persons to whom the Software is furnished to do
|
---|
32 | /// so, subject to the following conditions:
|
---|
33 | ///
|
---|
34 | /// The above copyright notice and this permission notice shall be included in all
|
---|
35 | /// copies or substantial portions of the Software.
|
---|
36 | ///
|
---|
37 | /// =================================================================================
|
---|
38 | ///
|
---|
39 |
|
---|
40 | using System;
|
---|
41 | using System.Collections.Generic;
|
---|
42 | using System.Text;
|
---|
43 | using System.Drawing;
|
---|
44 | using ILNumerics;
|
---|
45 | using ILNumerics.Drawing;
|
---|
46 | using ILNumerics.Drawing.Graphs;
|
---|
47 | using ILNumerics.Drawing.Shapes;
|
---|
48 | using ILNumerics.Drawing.Misc;
|
---|
49 | using ILNumerics.Drawing.Labeling;
|
---|
50 |
|
---|
51 | namespace ILNumerics.Drawing.Plots {
|
---|
52 | /// <summary>
|
---|
53 | /// surface plot supporting light and transparency
|
---|
54 | /// </summary>
|
---|
55 | public sealed class ILLitSurface : ILPlot, Interfaces.IILPanelConfigurator {
|
---|
56 |
|
---|
57 | #region attributes
|
---|
58 | protected ILColormap m_colorMap;
|
---|
59 | protected ILArray<float> m_xVals = ILMath.returnType<float>();
|
---|
60 | protected ILArray<float> m_yVals = ILMath.returnType<float>();
|
---|
61 | protected ILArray<float> m_zVals = ILMath.returnType<float>();
|
---|
62 | protected byte m_opacity = 255;
|
---|
63 | ILArray<float> m_colorIndices = ILMath.returnType<float>();
|
---|
64 | ILLitQuads m_quads;
|
---|
65 | #endregion
|
---|
66 |
|
---|
67 | #region properties
|
---|
68 | /// <summary>
|
---|
69 | /// Overall opacity for the surface
|
---|
70 | /// </summary>
|
---|
71 | public byte Opacity {
|
---|
72 | get { return m_opacity; }
|
---|
73 | set {
|
---|
74 | m_opacity = value;
|
---|
75 | m_quads.Opacity = value;
|
---|
76 | Invalidate();
|
---|
77 | }
|
---|
78 | }
|
---|
79 | /// <summary>
|
---|
80 | /// colormap used for coloring the surface
|
---|
81 | /// </summary>
|
---|
82 | public ILColormap Colormap {
|
---|
83 | get { return m_colorMap; }
|
---|
84 | set {
|
---|
85 | m_colorMap = value;
|
---|
86 | Invalidate();
|
---|
87 | }
|
---|
88 | }
|
---|
89 | /// <summary>
|
---|
90 | /// reference to the label for the surface
|
---|
91 | /// </summary>
|
---|
92 | public ILShapeLabel Label {
|
---|
93 | get { return m_quads.Label; }
|
---|
94 | }
|
---|
95 | /// <summary>
|
---|
96 | /// get a reference to the data values or sets it, used for updates to the plot
|
---|
97 | /// </summary>
|
---|
98 | public ILRetArray<float> XValues {
|
---|
99 | get { return m_xVals.C; }
|
---|
100 | set {
|
---|
101 | using (ILScope.Enter(value)) {
|
---|
102 | if (object.Equals(value, null)) {
|
---|
103 | m_xVals.a = ILMath.empty<float>();
|
---|
104 | } else if (value.Size.IsSameSize(m_zVals.Size)) {
|
---|
105 | m_xVals.a = value.C;
|
---|
106 | Invalidate();
|
---|
107 | } else {
|
---|
108 | throw new ArgumentException("invalid size: XValues must be null or have the same size as ZValues");
|
---|
109 | }
|
---|
110 | }
|
---|
111 | }
|
---|
112 | }
|
---|
113 | /// <summary>
|
---|
114 | /// get a reference to the data values or sets it, used for updates to the plot
|
---|
115 | /// </summary>
|
---|
116 | public ILRetArray<float> YValues {
|
---|
117 | get { return m_yVals; }
|
---|
118 | set {
|
---|
119 | using (ILScope.Enter(value)) {
|
---|
120 | if (object.Equals(value, null)) {
|
---|
121 | m_yVals.a = ILMath.empty<float>();
|
---|
122 | } else if (value.Size.IsSameSize(m_zVals.Size)) {
|
---|
123 | m_yVals.a = value.C;
|
---|
124 | Invalidate();
|
---|
125 | } else {
|
---|
126 | throw new ArgumentException("invalid size: YValues must be null or have the same size as ZValues");
|
---|
127 | }
|
---|
128 | }
|
---|
129 | }
|
---|
130 | }
|
---|
131 | /// <summary>
|
---|
132 | /// get a reference to the data values or sets it, used for updates to the plot
|
---|
133 | /// </summary>
|
---|
134 | public ILRetArray<float> ZValues {
|
---|
135 | get { return m_zVals; }
|
---|
136 | set {
|
---|
137 | using (ILScope.Enter(value)) {
|
---|
138 | if (value != null && (m_zVals.IsEmpty || value.Size.IsSameSize(m_zVals.Size))) {
|
---|
139 | m_zVals.a = value.C;
|
---|
140 | Invalidate();
|
---|
141 | } else {
|
---|
142 | throw new ArgumentException("invalid size: ZValues must be a matrix");
|
---|
143 | }
|
---|
144 | }
|
---|
145 | }
|
---|
146 | }
|
---|
147 | /// <summary>
|
---|
148 | /// get a reference to the color index values or sets it, used for updates to the plot
|
---|
149 | /// </summary>
|
---|
150 | public ILRetArray<float> ColorIndices {
|
---|
151 | get { return m_colorIndices; }
|
---|
152 | set {
|
---|
153 | using (ILScope.Enter(value)) {
|
---|
154 | if (object.Equals(value, null)) {
|
---|
155 | m_colorIndices.a = ILMath.empty<float>();
|
---|
156 | } else if (value.Size.IsSameSize(m_zVals.Size)) {
|
---|
157 | m_colorIndices.a = value.C;
|
---|
158 | Invalidate();
|
---|
159 | } else {
|
---|
160 | throw new ArgumentException("invalid size: ColorIndices must be null or have the same size as ZValues");
|
---|
161 | }
|
---|
162 | }
|
---|
163 | }
|
---|
164 | }
|
---|
165 | /// <summary>
|
---|
166 | /// get reference to IILLitQuads lit composite shape used for rendering the surface
|
---|
167 | /// </summary>
|
---|
168 | public ILLitQuads Quads {
|
---|
169 | get { return m_quads; }
|
---|
170 | }
|
---|
171 | #endregion
|
---|
172 |
|
---|
173 | #region constructors
|
---|
174 | /// <summary>
|
---|
175 | /// create new lit surface, provide data for X,Y and Z coordinates
|
---|
176 | /// </summary>
|
---|
177 | /// <param name="panel">the panel hosting the scene</param>
|
---|
178 | /// <param name="X">X coordinates matrix, same size as Z or null</param>
|
---|
179 | /// <param name="Y">Y coordinates matrix, same size as Z or null</param>
|
---|
180 | /// <param name="Z">Z data matrix, at least 2 rows, 2 columns</param>
|
---|
181 | /// <param name="colormap">colormap used for auto coloring the surface</param>
|
---|
182 | public ILLitSurface(ILPanel panel, ILInArray<float> Z, ILInArray<float> X = null, ILInArray<float> Y = null, ILColormap colormap = null, ILInArray<float> colorIndices = null)
|
---|
183 | : base(panel) {
|
---|
184 | using (ILScope.Enter(X, Y, Z, colorIndices)) {
|
---|
185 | ZValues = ILMath.check(Z, (a) => { return (a.S[0] >= 2 || a.S[1] >= 2) ? Z : null; }, ErrorMessage: "invalid parameter: Z must be a matrix");
|
---|
186 | XValues = X;
|
---|
187 | YValues = Y;
|
---|
188 | ColorIndices = colorIndices;
|
---|
189 | m_quads = new ILLitQuads(panel, Z.S.NumberOfElements);
|
---|
190 | m_quads.Label.Text = "";
|
---|
191 | m_quads.Shading = ShadingStyles.Interpolate;
|
---|
192 | if (colormap == null) {
|
---|
193 | colormap = new ILColormap(Colormaps.ILNumerics);
|
---|
194 | }
|
---|
195 | Add(m_quads);
|
---|
196 | m_colorMap = colormap;
|
---|
197 | Invalidate();
|
---|
198 | }
|
---|
199 | }
|
---|
200 | #endregion
|
---|
201 |
|
---|
202 | #region public interface
|
---|
203 | /// <summary>
|
---|
204 | /// (re)configure the plot, causes a recreation of all quads due to changed parameters
|
---|
205 | /// </summary>
|
---|
206 | internal override void Configure() {
|
---|
207 | if (m_invalidated) {
|
---|
208 | m_quads.Indices = Computation.configureVertices(
|
---|
209 | XValues,YValues,ZValues,
|
---|
210 | m_colorMap, m_quads.Vertices, m_opacity,
|
---|
211 | ColorIndices);
|
---|
212 | m_quads.Invalidate();
|
---|
213 | m_quads.Configure();
|
---|
214 | m_invalidated = false;
|
---|
215 | }
|
---|
216 | base.Configure();
|
---|
217 | }
|
---|
218 | #endregion
|
---|
219 |
|
---|
220 | #region private helper
|
---|
221 | private class Computation : ILMath {
|
---|
222 | public static ILRetArray<int> configureVertices(
|
---|
223 | ILInArray<float> xVals, ILInArray<float> yVals,
|
---|
224 | ILInArray<float> zVals, ILColormap cmap, C4fN3fV3f[] Vertices, byte opacity,
|
---|
225 | ILInArray<float> colors = null) {
|
---|
226 | using (ILScope.Enter(xVals,yVals,zVals)) {
|
---|
227 | int i = 0, x, y, y0 = zVals.Size[0] - 1;
|
---|
228 | x = 0;
|
---|
229 | y = 0;
|
---|
230 | ILArray<float> colorIndices;
|
---|
231 | float minZ, maxZ;
|
---|
232 | // if matching colors were given, scale them to colormap range
|
---|
233 | // otherwise take zvalues as base
|
---|
234 | if (isnullorempty(colors) || !colors.S.IsSameShape(zVals.S)) {
|
---|
235 | if (!zVals.GetLimits(out minZ, out maxZ, false))
|
---|
236 | minZ = maxZ = 1.0f;
|
---|
237 | colorIndices = (tosingle((zVals - minZ) / (maxZ - minZ)))[":"] * (cmap.Length - 1);
|
---|
238 | } else {
|
---|
239 | if (!colors.GetLimits(out minZ, out maxZ, false))
|
---|
240 | minZ = maxZ = 1.0f;
|
---|
241 | colorIndices = (tosingle((colors - minZ) / (maxZ - minZ)))[":"] * (cmap.Length - 1);
|
---|
242 | }
|
---|
243 | colorIndices[isnan(colorIndices)] = 0;
|
---|
244 | bool useXvals = (xVals != null && !xVals.IsEmpty);
|
---|
245 | bool useYvals = (yVals != null && !yVals.IsEmpty);
|
---|
246 | foreach (float a in zVals) {
|
---|
247 | C4fN3fV3f v = Vertices[i];
|
---|
248 | v.Position = new ILPoint3Df(
|
---|
249 | (useXvals) ? xVals.GetValue(y, x) : x
|
---|
250 | , (useYvals) ? yVals.GetValue(y, x) : y0 - y
|
---|
251 | , a);
|
---|
252 | byte r, g, b;
|
---|
253 | cmap.Map(colorIndices.GetValue(i), out r, out g, out b);
|
---|
254 | v.Color = Color.FromArgb(255, r, g, b);
|
---|
255 | v.Alpha = opacity;
|
---|
256 | Vertices[i++] = v;
|
---|
257 | // set next position
|
---|
258 | if (++y >= zVals.S[0]) {
|
---|
259 | x++;
|
---|
260 | y = 0;
|
---|
261 | }
|
---|
262 | }
|
---|
263 |
|
---|
264 | // create quad indices
|
---|
265 | int numQuad = (zVals.Size[0] - 1) * (zVals.Size[1] - 1);
|
---|
266 | x = 0; y = 0;
|
---|
267 | ILArray<int> ret = zeros<int>(4, numQuad);
|
---|
268 | ILArray<int> mult = counter<int>(0.0, 1.0, zVals.Size);
|
---|
269 | mult.a = mult["0:" + (zVals.Size[0] - 2), "0:" + (zVals.Size[1] - 2)];
|
---|
270 | mult.a = mult[":"].T;
|
---|
271 |
|
---|
272 | ret["0;:"] = mult;
|
---|
273 | ret["3;:"] = mult + 1;
|
---|
274 | mult.a = mult + zVals.Size.SequentialIndexDistance(1);
|
---|
275 | ret["2;:"] = mult + 1;
|
---|
276 | ret["1;:"] = mult;
|
---|
277 |
|
---|
278 | // remove quads having NaN values involved
|
---|
279 |
|
---|
280 | return ret;
|
---|
281 | }
|
---|
282 | }
|
---|
283 | }
|
---|
284 | #endregion
|
---|
285 |
|
---|
286 | #region IILPanelConfigurator Members
|
---|
287 |
|
---|
288 | public void ConfigurePanel(ILPanel panel) {
|
---|
289 | panel.InteractiveMode = InteractiveModes.Rotating;
|
---|
290 | if (panel.AutoDefaultView) {
|
---|
291 | panel.DefaultView.EventingSuspend();
|
---|
292 | panel.DefaultView.SetDeg(-25, 45, 100);
|
---|
293 | panel.DefaultView.EventingResume(false);
|
---|
294 | }
|
---|
295 | panel.BackgroundFilled = false;
|
---|
296 | }
|
---|
297 |
|
---|
298 | #endregion
|
---|
299 | }
|
---|
300 | }
|
---|