Free cookie consent management tool by TermsFeed Policy Generator

source: branches/HeuristicLab.Problems.GaussianProcessTuning/ILNumerics.2.14.4735.573/Drawing/Collections/ILGraphCollection.cs @ 10770

Last change on this file since 10770 was 9102, checked in by gkronber, 12 years ago

#1967: ILNumerics source for experimentation

File size: 24.8 KB
Line 
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#pragma warning disable 1591
41
42using System;
43using System.Collections.Generic;
44using System.Text;
45using ILNumerics.Exceptions;
46using ILNumerics.Drawing.Misc;
47using ILNumerics.Drawing.Interfaces;
48using ILNumerics.Drawing.Graphs;
49using ILNumerics.Drawing.Plots;
50
51namespace ILNumerics.Drawing.Collections {
52    /// <summary>
53    /// Collection of graph objects - all graphs currently contained in a subfigure
54    /// </summary>
55    public sealed class ILGraphCollection : List<ILGraph>, IDisposable {
56
57        public event ILGraphCollectionChangedEvent CollectionChanged;
58        public event ILGraphChangedEvent GraphChanged;
59        /// <summary>
60        /// triggers the ILGraphCollectionChanged event
61        /// </summary>
62        /// <param name="sender"></param>
63        /// <param name="reason"></param>
64        void OnChange (ILGraph graph, GraphCollectionChangeReason reason, IILPanelConfigurator configurator) {
65            if (CollectionChanged != null)
66                CollectionChanged(this, new ILGraphCollectionChangedEventArgs((ILGraph)graph, reason, configurator));
67        }
68        /// <summary>
69        /// triggers GraphChanged event, bubbles from single graph
70        /// </summary>
71        /// <param name="graphArgs">event arguments from graph</param>
72        void OnGraphChanged(ILGraph sender, ILGraphChangedEventArgs graphArgs) {
73            if (GraphChanged != null) {
74                GraphChanged(sender,graphArgs);
75            }
76        }
77
78        #region members / properties
79        private IILCreationFactory m_graphFact;
80        private ILClippingData m_clippingData;
81        private List<ILGraph> m_unsortedCache;
82        private ILGraphComparer m_graphComparer;
83        /// <summary>
84        /// Clippping volume for data in all graphs of the collection
85        /// </summary>
86        /// <remarks>This gives back the real ILClippingData object (no copy)</remarks>
87        public ILClippingData Limits {
88            get {
89                return m_clippingData;
90            }
91        }
92        #endregion
93
94        #region constructor / disposal
95        /// <summary>
96        /// Create new ILGraphCollection
97        /// </summary>
98        /// <param name="panel">Output panel </param>
99        /// <param name="clippingData"></param>
100        internal ILGraphCollection(IILCreationFactory vPainterFact) : base() {
101            m_graphFact = vPainterFact;
102            m_clippingData = new ILClippingData();
103            m_unsortedCache = new List<ILGraph>();
104            m_graphComparer = new ILGraphComparer();
105        }
106        /// <summary>
107        /// dispose all graphs contained in this collection
108        /// </summary>
109        public void Dispose() {
110            foreach (ILGraph graph in this) {
111                if (graph != null)
112                    graph.Dispose();
113            }
114        }
115        #endregion
116
117        #region event handling
118        ///// <summary>
119        ///// signaled when one/some of the ILGraphs have changed
120        ///// </summary>
121        ///// <param name="sender"></param>
122        ///// <param name="e"></param>
123        //void Graph_Changed(object sender, ILGraphChangedEventArgs e) {
124        //    OnGraphChanged(sender as ILGraph,e);
125        //}
126        /// <summary>
127        /// called once the limits of a graph have changed
128        /// </summary>
129        /// <param name="sender">graph</param>
130        /// <param name="e">event args, holding a reference to the clipping data</param>
131        void Limits_Changed(object sender, ClippingChangedEventArgs e) {
132            ILPoint3Df max = ILPoint3Df.MinValue;
133            ILPoint3Df min = ILPoint3Df.MaxValue;
134            foreach (ILGraph graph in this) {
135                max = ILPoint3Df.Max(max,graph.Limits.Max);
136                min = ILPoint3Df.Min(min,graph.Limits.Min);
137            }
138            m_clippingData.Set(min,max);
139        }
140        #endregion
141
142        #region Collection manager
143        /// <summary>
144        /// clear all graphs from the collection
145        /// </summary>
146        public new void Clear() {
147            lock (this) {
148                foreach (ILGraph g in this) {
149                    g.Dispose();
150                }
151                base.Clear();
152            }
153            m_clippingData.Reset(); 
154            Invalidate();
155            OnChange(null,GraphCollectionChangeReason.Deleted,null);
156        }
157        /// <summary>
158        /// Add a new surface graph, provide all coordinate data
159        /// </summary>
160        /// <param name="Z">matrix holding Z coordinates (heights)</param>
161        /// <returns>reference to newly created surface graph</returns>
162        public ILSurfaceGraph AddSurfGraph(ILInArray<float> X, ILInArray<float> Y, ILInArray<float> Z, ILInArray<float> C) {
163            using (ILScope.Enter(X, Y, Z, C)) {
164                ILSurfaceGraph ret;
165                ret = (ILSurfaceGraph)m_graphFact.CreateGraph(Z, GraphType.Surf, X, Y, C);
166                m_clippingData.Update(ret.Limits);
167                Add(ret);
168                ret.Changed += new ILGraphChangedEvent(GraphChanged);
169                // trigger change event
170                OnChange(ret, GraphCollectionChangeReason.Added, null);
171                return ret;
172            }
173        }
174        /// <summary>
175        /// Add a new surface graph to collection
176        /// </summary>
177        /// <param name="data">matrix holding data to be plotted</param>
178        /// <returns>reference to newly created surface graph</returns>
179        public ILSurfaceGraph AddSurfGraph(ILInArray<float> data) {
180            using (ILScope.Enter(data)) {
181                return (ILSurfaceGraph)Add(data, GraphType.Surf)[0];
182            }
183        }
184        /// <summary>
185        /// add a plot to a new scene graph
186        /// </summary>
187        /// <param name="plot">plot to be added to the panel</param>
188        /// <returns>newly created scene graph</returns>
189        public ILSceneGraph AddPlot(ILPlot plot) {
190            ILSceneGraph scene = AddSceneGraph();
191            scene.AddNode(plot);
192            return scene;
193        }
194        /// <summary>
195        /// Add a new scene graph to collection
196        /// </summary>
197        /// <returns>reference to newly created surface graph</returns>
198        public ILSceneGraph AddSceneGraph() {
199            ILSceneGraph newGraph = m_graphFact.CreateSceneGraph(); 
200            Add(newGraph);
201            newGraph.Changed += new ILGraphChangedEvent(GraphChanged);
202            newGraph.Limits.Changed += new ILClippingDataChangedEvent(Limits_Changed);
203            newGraph.NodeAdded += new SceneGraphNodeHandler(sceneGraph_NodeAdded);
204            OnChange(newGraph, GraphCollectionChangeReason.Added, null);
205            return newGraph;
206        }
207
208        void sceneGraph_NodeAdded(object sender, ILSceneGraphNodeEventArgs args) {
209            if (args.Node != null && args.Node is IILPanelConfigurator) {
210                OnChange(sender as ILGraph, GraphCollectionChangeReason.Added, args.Node as IILPanelConfigurator);
211            }
212        }
213        /// <summary>
214        /// add an newly created scene graph instance to the collection of graphs
215        /// </summary>
216        /// <param name="sceneGraph">exisisting instance of scene graph</param>
217        /// <remarks><para>This overload may be used to add user defined graphs to
218        /// the collection of graphs in order to use them in ILPanels. The user
219        /// defined graph needs to derive from scene graph. It may uses all shapes
220        /// compatible with ILSceneGraph. (ILLine,ILPolygon,ILLitBox,ILQuads,ILTriangles, etc...)
221        /// </para></remarks>
222        public void AddSceneGraph(ILSceneGraph sceneGraph) {
223            if (sceneGraph == null) throw new ILArgumentException("scene graph must not be null!");
224            Add(sceneGraph);
225            sceneGraph.Changed += new ILGraphChangedEvent(GraphChanged);
226            sceneGraph.Limits.Changed += new ILClippingDataChangedEvent(Limits_Changed);
227            OnChange(sceneGraph, GraphCollectionChangeReason.Added, null);
228        }
229
230        /// <summary>
231        /// Add a new imagesc graph to collection
232        /// </summary>
233        /// <param name="data">matrix holding data to be drawn</param>
234        /// <returns>newly created graph</returns>
235        public ILImageSCGraph AddImageSCGraph(ILInArray<float> data) {
236            using (ILScope.Enter(data))
237            return (ILImageSCGraph)Add(data,GraphType.Imagesc)[0];
238        }
239
240        /// <summary>
241        /// Add line graph(s)
242        /// </summary>
243        /// <param name="data">vector or matrix with date to be plotted. For matrices, the columns will be used to create new graphs.</param>
244        /// <returns>Array of newly created graph(s)</returns>
245        public ILPlot2DGraph[] AddLineGraph(ILInArray<double> A) {
246            using (ILScope.Enter(A)) {
247                return AddLineGraph(ILMath.tosingle(A));
248            }
249        }
250        /// <summary>
251        /// Add line graph(s)
252        /// </summary>
253        /// <param name="data">vector or matrix with date to be plotted. For matrices, the columns will be used to create new graphs.</param>
254        /// <returns>Array of newly created graph(s)</returns>
255        public ILPlot2DGraph[] AddLineGraph(ILInArray<float> A) {
256            using (ILScope.Enter(A)) {
257                List<ILGraph> graphs = Add(A, GraphType.Plot2D);
258                List<ILPlot2DGraph> ret = new List<ILPlot2DGraph>();
259                ILColorEnumerator cenumerator = new ILColorEnumerator(Colormaps.Lines);
260                foreach (ILGraph g in graphs) {
261                    ILPlot2DGraph plot2DGraph = (ILPlot2DGraph)g;
262                    ret.Add(plot2DGraph);
263                    plot2DGraph.Line.Color = cenumerator.NextColor();
264                }
265                return ret.ToArray();
266            }
267
268        }
269        /// <summary>
270        /// Add X/Y line graph(s)
271        /// </summary>
272        /// <param name="X">X coordinates. If this is a matrix, every column provides data for an individual graph.</param>
273        /// <param name="Y">Y coordinates. Same size as 'X'.</param>
274        /// <returns>newly created graph(s)</returns>
275        public ILPlot2DGraph[] AddLineGraph(ILInArray<double> XData, ILInArray<double> YData) {
276            using (ILScope.Enter(XData,YData)) {
277                return AddLineGraph(ILMath.tosingle(XData), ILMath.tosingle(YData));
278            }
279        }
280        /// <summary>
281        /// Add X/Y line graph(s)
282        /// </summary>
283        /// <param name="X">X coordinates. If this is a matrix, every column provides data for an individual graph.</param>
284        /// <param name="Y">Y coordinates. Same size as 'X'.</param>
285        /// <returns>newly created graph(s)</returns>
286        public ILPlot2DGraph[] AddLineGraph(ILInArray<float> XData, ILInArray<float> YData) {
287            using (ILScope.Enter(XData, YData)) {
288                List<ILGraph> graphs = Add(XData, YData, GraphType.Plot2D);
289                List<ILPlot2DGraph> ret = new List<ILPlot2DGraph>();
290                ILColorEnumerator cenumerator = new ILColorEnumerator(Colormaps.Lines);
291                foreach (ILGraph g in graphs) {
292                    ILPlot2DGraph plot2DGraph = (ILPlot2DGraph)g;
293                    ret.Add(plot2DGraph);
294                    plot2DGraph.Line.Color = cenumerator.NextColor();
295                }
296                return ret.ToArray();
297            }
298        }
299        /// <summary>
300        /// [Depricated] Add new line graph(s) (2D) to collection
301        /// </summary>
302        /// <param name="data">vector/array with date to be plotted. For arrays, the columns will be used.</param>
303        /// <returns>Array of newly created graph(s)</returns>
304        public ILPlot2DGraph[] AddPlot2DGraph(ILInArray<float> data) {
305            return AddLineGraph(data);
306        }
307        /// <summary>
308        /// [Depricated] Add new X/Y 2D line graph(s), provide X and Y coordinates
309        /// </summary>
310        /// <param name="X">X coordinates. If this is a matrix, every column will produce an individual graph.</param>
311        /// <param name="Y">Y coordinates. Same size than 'X'.</param>
312        /// <returns>Array of newly created graph(s)</returns>
313        public ILPlot2DGraph[] AddPlot2DGraph(ILInArray<float> XData, ILInArray<float> YData) {
314            return AddLineGraph(XData, YData);
315        }
316        /// <summary>
317        /// Add new numeric graph(s) of arbitrary (math) type
318        /// </summary>
319        /// <param name="data">data to be plotted</param>
320        /// <param name="properties">determine GraphType</param>
321        /// <returns>List with newly created graph(s)</returns>
322        public List<ILGraph> Add(ILInArray<float> data, GraphType graphType) {
323            using (ILScope.Enter(data)) {
324                if (!data.IsNumeric)
325                    throw new ILArgumentException("Add graph: data array must be numeric!");
326                List<ILGraph> ret = new List<ILGraph>();
327                ILGraph newGraph;
328                ILArray<float> tmpData;
329                lock (this) {
330                    #region add each graph type seperately
331                    switch (graphType) {
332                        case GraphType.Plot2D:
333                            if (data.IsVector || data.IsScalar) {
334                                newGraph = m_graphFact.CreateGraph(data, graphType);
335                                Add(newGraph);
336                                newGraph.Changed += new ILGraphChangedEvent(GraphChanged);
337                                m_clippingData.Update(newGraph.Limits);
338                                newGraph.Limits.Changed += new ILClippingDataChangedEvent(Limits_Changed);
339                                ret.Add(newGraph);
340                            } else if (data.IsMatrix) {
341                                // plot columns
342                                m_clippingData.EventingSuspend();
343                                tmpData = ILMath.tosingle(data);
344                                for (int c = 0; c < tmpData.Size[1]; c++) {
345                                    newGraph = m_graphFact.CreateGraph(tmpData[":", c], graphType);
346                                    Add(newGraph);
347                                    newGraph.Changed += new ILGraphChangedEvent(GraphChanged);
348                                    ret.Add(newGraph);
349                                    m_clippingData.Update(newGraph.Limits);
350                                    newGraph.Limits.Changed += new ILClippingDataChangedEvent(Limits_Changed);
351                                }
352                                m_clippingData.EventingResume();
353                            }
354                            // trigger change event
355                            OnChange(ret[0], GraphCollectionChangeReason.Added, ret[0] as IILPanelConfigurator);
356                            break;
357                        case GraphType.Surf:
358                            if (!data.IsMatrix)
359                                throw new ILArgumentException("Surf: source data must be a matrix!");
360                            tmpData = ILMath.tosingle(data);
361                            m_clippingData.EventingSuspend();
362                            // margin for Z-Direction
363                            float min, max;
364                            tmpData.GetLimits(out min, out max);
365                            float zmarg = (max - min > 0) ? (float)(Math.Abs(max - min) / 10.0) : 0.0f;
366                            m_clippingData.Update(new ILPoint3Df(0, 0, min - zmarg), new ILPoint3Df(data.Size[1] - 1, data.Size[0] - 1, max + zmarg));
367                            m_clippingData.EventingResume();
368                            newGraph = m_graphFact.CreateGraph(tmpData, graphType);
369                            Add(newGraph);
370                            newGraph.Changed += new ILGraphChangedEvent(GraphChanged);
371                            // trigger change event
372                            ret.Add(newGraph);
373                            OnChange(newGraph, GraphCollectionChangeReason.Added, newGraph as IILPanelConfigurator);
374                            break;
375                        case GraphType.Imagesc:
376                            if (!data.IsMatrix)
377                                throw new ILArgumentException("Surf: source data must be a matrix!");
378                            tmpData = ILMath.tosingle(data);
379                            // note, ImageSC does not contribute to global clipping, except that the clipping
380                            // will be updated to include z = 0!
381                            m_clippingData.EventingSuspend();
382                            m_clippingData.Update(new ILPoint3Df(-0.5f, -.5f, 0), new ILPoint3Df(data.Size[1] - 0.5f, data.Size[0] - 0.5f, 0));
383                            m_clippingData.EventingResume();
384                            newGraph = m_graphFact.CreateGraph(tmpData, graphType);
385                            Add(newGraph);
386                            newGraph.Changed += new ILGraphChangedEvent(GraphChanged);
387                            // trigger change event
388                            OnChange(newGraph, GraphCollectionChangeReason.Added, newGraph as IILPanelConfigurator);
389                            ret.Add(newGraph);
390                            break;
391                        default:
392                            throw new ILDrawingException("the type of drawing is not supported!");
393                    }
394                    #endregion
395                }
396                return ret;
397            }
398        }
399        /// <summary>
400        /// Add new graph(s) of arbitrary type, provide both axis data
401        /// </summary>
402        /// <param name="xData">x coordinates </param>
403        /// <param name="graphType">type of graph to be added</param>
404        /// <param name="yData">y coordinates</param>
405        /// <returns>List with newly created graph(s)</returns>
406        /// <remarks>The return value will be a list of all graphs created (and added),
407        /// since more than one graph may have been specified. This depends on the
408        /// shape of the data provided.
409        /// <para>Currently only Plot2D graphs are supported as GraphType! </para></remarks>
410        /// <exception cref="ILNumerics.Exceptions.ILArgumentException">if the data provided are nor
411        /// numeric or the size for one of the arrays <typeparamref name="xData"/> or <typeparamref name="yData"/>
412        /// do not match. </exception>
413        public List<ILGraph> Add(ILInArray<float> xData, ILInArray<float> yData, GraphType graphType) {
414            using (ILScope.Enter(xData, yData)) {
415                if (!yData.IsNumeric || !xData.IsNumeric)
416                    throw new ILArgumentException("Add graph: data arrays must be numeric!");
417                List<ILGraph> ret = new List<ILGraph>();
418                ILGraph newGraph;
419                ILArray<float> tmpDataY, tmpDataX;
420                lock (this) {
421                    #region add each graph type seperately
422                    switch (graphType) {
423                        case GraphType.Plot2D:
424                            if (!yData.Size.IsSameSize(xData.Size))
425                                throw new ILArgumentException("Add graph: for X/Y plots, the size of X and Y must be equal!");
426                            if (yData.IsVector || yData.IsScalar) {
427                                newGraph = m_graphFact.CreateGraph(yData, graphType, xData);
428                                Add(newGraph);
429                                newGraph.Changed += new ILGraphChangedEvent(GraphChanged);
430                                m_clippingData.Update(newGraph.Limits);
431                                ret.Add(newGraph);
432                            } else if (yData.IsMatrix) {
433                                // plot columns
434                                m_clippingData.EventingSuspend();
435                                tmpDataY = ILMath.tosingle(yData);
436                                tmpDataX = ILMath.tosingle(xData);
437                                for (int c = 0; c < tmpDataY.Size[1]; c++) {
438                                    newGraph = m_graphFact.CreateGraph(tmpDataY[":", c], graphType, tmpDataX[":", c]);
439                                    Add(newGraph);
440                                    newGraph.Changed += new ILGraphChangedEvent(GraphChanged);
441                                    ret.Add(newGraph);
442                                    m_clippingData.Update(newGraph.Limits);
443                                }
444                                m_clippingData.EventingResume();
445                            }
446                            // trigger change event
447                            OnChange(ret[0], GraphCollectionChangeReason.Added, ret[0] as IILPanelConfigurator);
448                            break;
449                        default:
450                            throw new ILDrawingException("graph type is not supported in that mode yet!");
451                    }
452                    #endregion
453                }
454                return ret;
455            }
456        }
457        /// <summary>
458        /// Remove a graph from the collection and rescale data limits
459        /// </summary>
460        /// <param name="key">key of graph to be removed</param>
461        /// <returns>the ILGraph removed or null, if the key does not exist</returns>
462        /// <remarks>If the graph has been removed, the clipping data will be updated and a change event will be fired. </remarks>
463        public new bool Remove(ILGraph graph) {
464            lock (this) {
465                if (!Contains(graph)) return false;
466                base.Remove(graph);
467                // recreate clipping regions
468                m_clippingData.EventingSuspend();
469                m_clippingData.Reset(); 
470                foreach (ILGraph gr in this) {
471                    m_clippingData.Update (gr.Limits);
472                }
473                m_clippingData.EventingResume();
474                OnChange(graph,GraphCollectionChangeReason.Deleted,null);
475                Invalidate();
476                return true;
477            }
478        }
479       
480        #endregion
481
482        #region public interface
483        public void Invalidate() {
484            foreach (ILGraph g in this) {
485                g.Invalidate();
486            }
487        }
488        internal void GetSortedList4Render(ILCamera camera, List<ILGraph> sortList) {
489            m_unsortedCache.Clear();
490            foreach (ILGraph g in this) {
491                if (g.Is3DGraph()) {
492                    sortList.Add(g);
493                } else {
494                    m_unsortedCache.Add(g);
495                }
496            }
497            m_graphComparer.Camera = camera;
498            sortList.Sort(m_graphComparer);
499            sortList.AddRange(m_unsortedCache);
500        }
501        #endregion
502
503        #region private helper
504        #endregion
505
506    }
507}
Note: See TracBrowser for help on using the repository browser.