Free cookie consent management tool by TermsFeed Policy Generator

source: branches/HeuristicLab.Problems.GaussianProcessTuning/ILNumerics.2.14.4735.573/Drawing/Controls/ILPanel.cs @ 10903

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

#1967: ILNumerics source for experimentation

File size: 93.7 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 System.Drawing;
46using System.Reflection;
47using System.Windows.Forms;
48using System.IO;
49using ILNumerics.Drawing;
50using ILNumerics.Drawing.Interfaces;
51using ILNumerics.Drawing.Collections;
52using ILNumerics.Drawing.Graphs;
53using ILNumerics.Drawing.Labeling;
54using ILNumerics.Drawing.Misc;
55using System.Diagnostics;
56
57namespace ILNumerics.Drawing {
58
59    /// <summary>
60    /// Basic abstract base class for GL dependent display.
61    /// </summary>
62    /// <remarks>This control is the main plot control of ILNumerics.</remarks>
63    public abstract class ILPanel : Control {
64
65        #region attributes
66        protected ILRendererManager m_textRendererManager;
67        protected ILClippingData m_clippingView;
68        protected ILAxisCollection m_axes;
69        protected ILGraphCollection m_graphs;
70        protected ILTextureManager m_textureManager;
71        protected Point m_mouseStart;
72        protected bool m_isDragging;
73        protected bool m_active = false;
74        protected bool m_drawHidden = true;
75        protected bool m_ready = false;
76        private bool m_isStartingUp = true;
77        protected ILCamera m_camera;
78        protected ILCamera m_defaultView;
79        protected bool m_autoDefaultView = true;
80        protected InteractiveModes m_selectingMode = InteractiveModes.Rotating;
81        protected InteractiveModes m_oldSelectingMode;
82        protected bool m_isCtrlKeyDown;
83        protected ILPoint3Df m_scaling;
84        protected Projection m_projection = Projection.Orthographic;
85        protected Color m_backColor = Color.FromKnownColor(KnownColor.Control);
86        protected Color m_cubeBGColor = Color.FromArgb(250, 250, 250);
87        protected ILColormap m_colormap;
88        protected ILLegend m_legend;
89        protected ZoomModes m_zoomMode = ZoomModes.RollHard;
90        protected ILZoomAction m_zoomAction;
91        protected float m_zoomOffset = 50f;
92        protected GraphicDeviceType m_graphicsDevice;
93        protected ILLineProperties m_selectionRectangle;
94        protected bool m_fillBackground = true;
95        private AutoZoomOptions m_autoZoomOptions = AutoZoomOptions.OnDataChanges;
96        protected ILLayoutData m_layoutData = new ILLayoutData();
97        protected ILLightCollection m_lights = new ILLightCollection();
98        protected ILRenderProperties m_renderProperties;
99        protected ILAction m_action;
100        protected List<ILGraph> m_sortingCacheList = new List<ILGraph>();
101        /// <summary>
102        /// pixel size of the current PlotCubeScreenRectangle
103        /// </summary>
104        protected RectangleF m_plotBoxScreenRectF;
105        protected PlotBoxScreenSizeMode m_plotBoxScreenSizeMode;
106        protected AspectRatioMode m_aspectRatio;
107        protected double[] m_clipplanes = new double[24];
108       
109        private const int MAXRENDERPASSES = 2;
110        private const float LABELS_VERTICAL_MIN_RHO = 0.8f;
111        protected const float pi05 = (float) Math.PI / 2;
112        protected const float pi2 = (float) Math.PI * 2;
113        protected const float pi32 = (float) Math.PI / 2 * 3;
114        protected const float pi4 = (float) Math.PI / 4;
115        protected const float pi8 = (float) Math.PI / 8;
116        #endregion
117
118        #region properties
119        /// <summary>
120        /// Gets the mode for automatic view angle updates or sets it
121        /// </summary>
122        public bool AutoDefaultView {
123            get { return m_autoDefaultView; }
124            set { m_autoDefaultView = value; }
125        }
126        /// <summary>
127        /// Determines how the projected data plots are mapped to PlotCubeScreenRectF
128        /// </summary>
129        public AspectRatioMode AspectRatio {
130            get { return m_aspectRatio; }
131            set { m_aspectRatio = value; }
132        }
133        /// <summary>
134        /// The normalizes projected size (range 0..1) of plot cube on 2D client area, on set: also sets PlotCubeScreenMode -> Manual
135        /// </summary>
136        public RectangleF PlotBoxScreenRect {
137            get { return m_plotBoxScreenRectF; }
138            set {
139                m_plotBoxScreenRectF = value;
140                m_plotBoxScreenSizeMode = PlotBoxScreenSizeMode.Manual;
141                //Invalidate();
142            }
143        }
144        /// <summary>
145        /// Options for determining the size of the plot cube on the 2D screen client area, default: optimal
146        /// </summary>
147        public PlotBoxScreenSizeMode PlotBoxScreenSizeMode {
148            get { return m_plotBoxScreenSizeMode; }
149            set {
150                m_plotBoxScreenSizeMode = value;
151                if (value == PlotBoxScreenSizeMode.Maximum) {
152                    m_plotBoxScreenRectF = new RectangleF(0, 0, 1f, 1f);
153                }
154            }
155        }
156        /// <summary>
157        /// Access collection of lights for configuration
158        /// </summary>
159        public ILLightCollection Lights {
160            get { return m_lights; }
161        }
162        /// <summary>
163        /// Legend for panel's graphs
164        /// </summary>
165        public ILLegend Legend {
166            get {
167                return m_legend;
168            }
169        }
170        /// <summary>
171        /// Get texture manager instance, storing all textures used in the scene
172        /// </summary>
173        internal ILTextureManager TextureManager {
174            get {
175                return m_textureManager;
176            }
177        }
178        /// <summary>
179        /// Colormap used to translate color indices into true colors
180        /// </summary>
181        public ILColormap Colormap {
182            get {
183                return m_colormap;
184            }
185            set {
186                m_colormap = value;
187                OnColormapChanged();
188            }
189        }
190        /// <summary>
191        /// Determines if background of the rendering cube will be filled with the CubeBackgroundColor property value
192        /// </summary>
193        public bool BackgroundFilled {
194            get {
195                return m_fillBackground;
196            }
197            set {
198                m_fillBackground = value;
199                //Invalidate();
200            }
201        }
202        /// <summary>
203        /// True: the control will always be drawn, even if it does not own the focus
204        /// </summary>
205        public bool DrawInactive {
206            get {
207                return m_drawHidden;
208            }
209            set {
210                m_drawHidden = value;
211                //Invalidate();
212            }
213        }
214        /// <summary>
215        /// Get/set the background color for the inner cube drawing
216        /// </summary>
217        public Color BackColorCube {
218            get {
219                return m_cubeBGColor;
220            }
221            set {
222                m_cubeBGColor = value;
223                //Invalidate();
224            }
225        }
226        /// <summary>
227        /// View settings, get access to the clipping limits for all axises
228        /// </summary>
229        public ILClippingData Limits {
230            get {
231                return m_clippingView;
232            }
233        }
234        /// <summary>
235        /// Get the type of device currently used for rendering
236        /// </summary>
237        public GraphicDeviceType GraphicDeviceType {
238            get {
239                return m_graphicsDevice;
240            }
241        }
242        /// <summary>
243        /// Get/set properties for selection rectangle, drawn when zooming with the mouse
244        /// </summary>
245        public ILLineProperties SelectionRectangle {
246            get {
247                return m_selectionRectangle;
248            }
249        }
250        /// <summary>
251        /// color of the figure background
252        /// </summary>
253        public override Color BackColor {
254            get {
255                return m_backColor;
256            }
257            set {
258                m_backColor = value;
259                //Invalidate();
260            }
261        }
262        /// <summary>
263        /// type of projection: orthographic (default) or perspective
264        /// </summary>
265        public Projection Projection {
266            get {
267                return m_projection;
268            }
269            set {
270                m_projection = value;
271                //Invalidate();
272            }
273        }
274        /// <summary>
275        /// Get or set viewport properties (distance &amp; angles)
276        /// </summary>
277        /// <remarks>Changing </remarks>
278        public ILCamera Camera {
279            get {
280                return m_camera;
281            }
282        }
283        /// <summary>
284        /// Get the current mode for mouse interaction or set's it
285        /// </summary>
286        public InteractiveModes InteractiveMode {
287            get {
288                return m_selectingMode;
289            }
290            set {
291                m_selectingMode = value;
292                m_oldSelectingMode = value;
293                //if (value == InteractiveModes.Rotating)
294                //    m_axes[AxisNames.ZAxis].Visible = true;
295                //else if (value == InteractiveModes.ZoomRectangle)
296                //    m_axes[AxisNames.ZAxis].Visible = false;
297            }
298        }
299        /// <summary>
300        /// Gives all graphs as value collection (readonly)
301        /// </summary>
302        public ILGraphCollection Graphs {
303            get {
304                if (m_graphs == null)
305                    CreateControl();
306                return m_graphs;
307            }
308        }
309        /// <summary>
310        /// Get axes collection - holds all 3 axes
311        /// </summary>
312        public ILAxisCollection Axes {
313            get {
314                if (m_axes == null)
315                    CreateControl();
316                return m_axes;
317            }
318        }
319        /// <summary>
320        /// (experimental) content for graphs will be clipped outside the unit cube
321        /// </summary>
322        /// <remarks>For 2D plots, not clipping the vertex data may lead to hiding
323        /// the labels drawn next to axes. For 3D plots Clipping may cause unexpected behavior.
324        /// <para>Therefore Clipping will be activated for 2D plots by default and
325        /// deactivated for 3D plots by default.</para></remarks>
326        public bool ClipViewData {
327            get {
328                return m_renderProperties.Clipping;
329            }
330            set {
331                m_renderProperties.Clipping = value;
332            }
333        }
334        /// <summary>
335        /// Manager providing collection of available IILTextRenderer types
336        /// </summary>
337        /// <remarks>IILTextRenderer are used to draw labels for axis of this panel (device specific).
338        /// <para>Text renderer objects must be instantiated through the ILTextRendererManager instance's
339        /// CreateInstance() method.</para></remarks>
340        public ILRendererManager TextRendererManager {
341            get {
342                return m_textRendererManager;
343            }
344        }
345        /// <summary>
346        /// Get or set default camera position for reset of the scene
347        /// </summary>
348        /// <remarks>The default position is used when the scene is reset. That
349        /// reset is usually triggered by double clicking the panel with the mouse.
350        /// <para>setting this value to null will make the panel ignore any double
351        /// clicks, which enables the user to manually react to double click via the
352        /// common DoubleClick event of the panel and reset the camera position from
353        /// outside the component.</para></remarks>
354        public ILCamera DefaultView {
355            get {
356                return m_defaultView;
357            }
358            protected set {
359                if (value != null) {
360                    m_defaultView = value;
361                    m_autoDefaultView = false;
362                } else {
363                    m_autoDefaultView = true;
364                }
365            }
366        }
367        /// <summary>
368        /// Options for the view cube adapting data limit changes
369        /// </summary>
370        public AutoZoomOptions AutoZoomContent {
371            get {
372                return m_autoZoomOptions;
373            }
374            set {
375                m_autoZoomOptions = value;
376            }
377        }
378        /// <summary>
379        /// choose the ramp for zooming
380        /// </summary>
381        public ZoomModes ZoomMode {
382            get { return m_zoomMode; }
383            set { m_zoomMode = value; }
384        }
385        /// <summary>
386        /// How much the view cube will be shrinked/expanded on zooming operations (percent)
387        /// </summary>
388        public float ZoomOffset {
389            set { m_zoomOffset = value; }
390            get { return m_zoomOffset; }
391
392        }
393        protected ILZoomAction ZoomAction {
394            get {
395                return m_zoomAction;
396            }   
397        }
398        #endregion
399
400        #region constructors
401        protected ILPanel(GraphicDeviceType graphicsDevice) : base () {
402#if TRACE
403            Trace.TraceInformation("{0},{1} ILPanel.ctor()",DateTime.Now, Environment.TickCount);
404#endif
405            this.DoubleBuffered = false;
406            //BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
407            m_plotBoxScreenSizeMode = PlotBoxScreenSizeMode.Optimal;
408            m_graphicsDevice = graphicsDevice;
409            m_textureManager = new ILTextureManager(m_graphicsDevice);
410            m_textureManager.DefaultHeight = 500;
411            m_textureManager.DefaultWidth = 500;
412            m_selectionRectangle = new ILLineProperties();
413            m_selectionRectangle.Antialiasing = false;
414            m_selectionRectangle.Color = Color.Blue;
415            m_selectionRectangle.Width = 1;
416            m_selectionRectangle.Style = LineStyle.Solid;
417            m_selectionRectangle.Changed += new EventHandler(m_selectionRectangle_Changed);
418            m_camera = new ILCamera((float)0.0f,0.0f,10.0f);
419            m_defaultView = new ILCamera(m_camera);
420            m_defaultView.Changed += new EventHandler(m_defaultView_Changed);
421            m_renderProperties = new ILRenderProperties ();
422            m_renderProperties.Camera = Camera;
423            m_textRendererManager = new ILRendererManager(this);
424            m_clippingView = new ILClippingData();
425            m_clippingView.AllowZeroVolume = false;
426            m_layoutData = new ILLayoutData(m_camera);
427            m_clippingView.Changed += new ILClippingDataChangedEvent(m_viewLimits_Changed);
428            m_colormap = new ILColormap();
429            m_colormap.Changed += new EventHandler(m_colormap_Changed);
430            Padding = new Padding(5);
431            BackColor = Color.White;
432            Dock = DockStyle.Fill;
433            m_legend = ILLegend.Create(this);
434            m_legend.Changed += new EventHandler(m_legend_Changed);
435            m_active = false;
436            m_ready = false;
437        }
438
439        #endregion
440
441        #region public interface function
442        /// <summary>
443        /// Dispose this panel, frees all devices, graph- and axis collection
444        /// </summary>
445        public new void Dispose () {
446            Dispose(false);
447        }
448        /// <summary>
449        /// dispose this panel
450        /// </summary>
451        /// <param name="disposing">manual disposing</param>
452        /// <remarks>derived classed (ILDXPanel,ILOGLPanel) free their resources here</remarks>
453        protected override void Dispose(bool disposing) {
454#if TRACE
455            Trace.TraceInformation("{0},{1} ILPanel.Dispose(bool) start",DateTime.Now, Environment.TickCount);
456            Trace.Indent();
457#endif
458            m_ready = false;
459            if (m_graphs != null)
460                m_graphs.Dispose();
461            if (m_axes != null)
462                m_axes.Dispose();
463            if (m_textureManager != null)
464                m_textureManager.Dispose();
465            base.Dispose(disposing);
466#if TRACE
467            Trace.Unindent();
468            Trace.TraceInformation("{0},{1} ILPanel.Dispose(bool) end",DateTime.Now, Environment.TickCount);
469#endif
470        }
471
472        /// <summary>
473        /// causes the panel to redraw
474        /// </summary>
475        public override void Refresh() {
476            if (InvokeRequired) {
477                Invoke((MethodInvoker) delegate () { Refresh(); });
478            } else {
479                base.Refresh();
480            }
481        }
482        #endregion
483
484        #region events
485        /// <summary>
486        /// fired, if the data limits of any graphs changed
487        /// </summary>
488        public event ILClippingDataChangedEvent DataLimitsChanged;
489        /// <summary>
490        /// fired, if the clipping rectangle for viewing graphs changed
491        /// </summary>
492        public event ILClippingDataChangedEvent ViewLimitsChanged;
493        /// <summary>
494        /// fires, if the current colormap has changed
495        /// </summary>
496        public event EventHandler ColormapChanged;
497        /// <summary>
498        /// fired, if the internal graphics device reset (Direct3D devices only)
499        /// </summary>
500        public event ILGraphicsDeviceResetEvent GraphicsDeviceReset;
501        /// <summary>
502        /// fired, if the internal graphics device has been (re)created
503        /// </summary>
504        public event ILGraphicsDeviceCreatedEvent GraphicsDeviceCreated;
505        #endregion
506
507        #region event handlers
508        protected void m_defaultView_Changed(object sender, EventArgs e) {
509            m_autoDefaultView = false;
510        }
511        protected override void OnHandleCreated(EventArgs e) {
512#if TRACE
513            Trace.TraceInformation("{0},{1} ILPanel.OnHandleCreated() start",DateTime.Now, Environment.TickCount);
514            Trace.Indent();
515#endif
516            base.OnHandleCreated(e);
517            this.SetStyle(ControlStyles.AllPaintingInWmPaint,true);
518            this.SetStyle(ControlStyles.UserPaint,true);
519#if TRACE
520            Trace.Unindent();
521            Trace.TraceInformation("{0},{1} ILPanel.OnHandleCreated() end",DateTime.Now, Environment.TickCount);
522#endif
523        }
524        protected override void OnHandleDestroyed(EventArgs e) {
525#if TRACE
526            Trace.TraceInformation("{0},{1} ILPanel.OnHandleDestroyed() start",DateTime.Now, Environment.TickCount);
527            Trace.Indent();
528#endif
529            if (m_zoomAction != null) m_zoomAction.Cancel();
530            Dispose();
531            base.OnHandleDestroyed(e);
532#if TRACE
533            Trace.Unindent();
534            Trace.TraceInformation("{0},{1} ILPanel.OnHandleDestroyed() end",DateTime.Now, Environment.TickCount);
535#endif
536
537        }
538        protected virtual void OnViewLimitsChanged(ClippingChangedEventArgs e) {
539            if (ViewLimitsChanged != null)
540                ViewLimitsChanged(this,e); 
541        }
542        protected virtual void OnDataLimitsChanged(ClippingChangedEventArgs e) {
543            if (DataLimitsChanged != null)
544                DataLimitsChanged(this,e); 
545        }
546        protected virtual void OnGraphicsDeviceReset() {
547#if TRACE
548            Trace.TraceInformation("{0},{1} ILPanel.OnGraphicsDeviceReset() start",DateTime.Now, Environment.TickCount);
549            Trace.Indent();
550#endif
551            Configure();
552            if (GraphicsDeviceReset != null) {
553                GraphicsDeviceReset(this,null);
554            }
555#if TRACE
556            Trace.Unindent();
557            Trace.TraceInformation("{0},{1} ILPanel.OnGraphicsDeviceReset() end",DateTime.Now, Environment.TickCount);
558#endif
559        }
560        protected virtual void OnGraphicsDeviceCreated() {
561#if TRACE
562            Trace.TraceInformation("{0},{1} ILPanel.OnGraphicsDeviceCreated() start",DateTime.Now, Environment.TickCount);
563            Trace.Indent();
564#endif
565            IILCreationFactory graphFact = GetCreationFactory();
566            m_graphs = new ILGraphCollection(graphFact);
567            m_graphs.CollectionChanged += new ILGraphCollectionChangedEvent(m_graphs_OnCollectionChanged);
568            m_graphs.Limits.Changed += new ILClippingDataChangedEvent(m_dataLimits_Changed);
569            m_graphs.GraphChanged += new ILGraphChangedEvent(m_graphs_GraphChanged);
570            m_axes = new ILAxisCollection(m_clippingView,graphFact);
571            if (GraphicsDeviceCreated!= null) {
572                GraphicsDeviceCreated(this,null);
573            }
574            //Invalidate();
575#if TRACE
576            Trace.Unindent();
577            Trace.TraceInformation("{0},{1} ILPanel.OnGraphicsDeviceCreated() end",DateTime.Now, Environment.TickCount);
578#endif
579        }
580
581        protected virtual void OnColormapChanged() {
582            if (ColormapChanged != null)
583                ColormapChanged(this,null);
584            m_graphs.Invalidate();
585        }
586
587        protected override void OnLostFocus(EventArgs e) {
588            base.OnLostFocus(e);
589            m_active = false;
590        }
591        protected override void OnGotFocus(EventArgs e) {
592            base.OnGotFocus(e);
593            m_active = true;
594        }
595        protected override void OnVisibleChanged(EventArgs e) {
596      if (IsHandleCreated && !IsDisposed) {
597              base.OnVisibleChanged(e);
598              if (Visible)
599                  m_active = true;
600              else
601                  m_active = false;
602      }
603        }
604        protected override void OnSizeChanged(EventArgs e) {
605            base.OnSizeChanged(e);
606            base.Invalidate();
607        }
608
609        protected override void OnMouseMove(MouseEventArgs e) {
610            base.OnMouseMove(e);
611            if (m_selectingMode == InteractiveModes.Rotating) {
612                #region rotation
613                if (m_isDragging || (e.Button == System.Windows.Forms.MouseButtons.Left
614                    && Math.Sqrt(Math.Pow(Math.Abs(e.X - m_mouseStart.X),2) + Math.Pow(Math.Abs(e.Y - m_mouseStart.Y),2)) > 3.0)) {
615                    m_isDragging = true;
616                    m_camera.EventingSuspend();
617                    int distX = e.Location.X - m_mouseStart.X;
618                    int distY = e.Location.Y - m_mouseStart.Y;
619                    float tmp = m_camera.Phi - distX / 200.0f;
620                    // if alt is pressed, lock on even angles
621                    if (((Control.ModifierKeys & Keys.Alt) != 0)
622                        && (Math.Abs(Math.Round(tmp/pi4) - (tmp / pi4)) < 0.05)) {
623                        tmp = (float)(Math.Round(tmp / pi4) * pi4);
624                    }
625                    m_camera.Phi = tmp;
626                    tmp = m_camera.Rho - distY / 200.0f;
627                    // if alt is pressed, lock on even angles
628                    if (((Control.ModifierKeys & Keys.Alt) != 0)
629                        && (Math.Abs(Math.Round(tmp/pi8) - (tmp / pi8)) < 0.05)) {
630                        tmp = (float)(Math.Round(tmp / pi8) * pi8);
631                    }
632                    m_camera.Rho = tmp;
633                    if (m_camera.Rho > Math.PI) m_camera.Rho = (float)Math.PI;
634                    if (m_camera.Rho < 0) m_camera.Rho = 0.0f;
635                    m_camera.EventingResume();
636                    m_mouseStart = e.Location;
637                    Refresh();
638                }
639                #endregion
640            } else if (m_selectingMode == InteractiveModes.ZoomRectangle) {
641                #region selection rectangle
642                if (m_isDragging || (e.Button == System.Windows.Forms.MouseButtons.Left
643                    && Math.Sqrt(Math.Pow(Math.Abs(e.X - m_mouseStart.X),2) + Math.Pow(Math.Abs(e.Y - m_mouseStart.Y),2)) > 3.0)) {
644                    m_isDragging = true;
645                    Cursor = Cursors.Cross;
646                    Refresh();
647                }
648                #endregion
649            } else if (m_selectingMode == InteractiveModes.Translating) {
650                if (m_isDragging || (e.Button == System.Windows.Forms.MouseButtons.Left
651                    && Math.Sqrt(Math.Pow(Math.Abs(e.X - m_mouseStart.X),2) + Math.Pow(Math.Abs(e.Y - m_mouseStart.Y),2)) > 1.0)) {
652                    ILPoint3Df p1,p2,dummy;
653                    Screen2World(m_mouseStart.X,Height - m_mouseStart.Y, out p1, out dummy);
654                    Screen2World(e.X, Height - e.Y, out p2, out dummy);
655                    if (m_projection == Projection.Perspective) {
656                        p1 = ILPoint3Df.normalize(p1 - m_camera.Position) * m_camera.Distance;
657                        p2 = ILPoint3Df.normalize(p2 - m_camera.Position) * m_camera.Distance;
658                    }
659                    p1 = p2 - p1;
660                    m_camera.LookAt -= p1; 
661                    m_mouseStart = e.Location;
662                    Refresh();
663                }
664           
665            }
666        }
667        protected override void OnMouseUp(MouseEventArgs e) {
668            base.OnMouseUp(e);
669            //System.Diagnostic.Debug.WriteLine("MouseUp");
670            if (m_selectingMode == InteractiveModes.ZoomRectangle && m_isDragging) {
671                Zoom(Screen2World2D(m_mouseStart.X,Height - m_mouseStart.Y),Screen2World2D(e.X, Height - e.Y));
672            }
673            m_isDragging = false;
674            Cursor = Cursors.Default;
675        }
676        protected override void OnMouseDown(MouseEventArgs e) {
677            base.OnMouseDown(e);
678            m_mouseStart = e.Location;
679        }
680        protected override void OnMouseClick(MouseEventArgs e) {
681            base.OnMouseClick(e);
682            //System.Diagnostic.Debug.WriteLine("Click");
683            if (m_isDragging == false && (m_selectingMode == InteractiveModes.ZoomRectangle
684                || m_selectingMode == InteractiveModes.Rotating)) {
685                // determine new center coords
686                ILPoint3Df near, far;
687                Screen2World(e.X,Height - e.Y, out near, out far); //Limits.CenterF.Z);
688                if (e.Button == System.Windows.Forms.MouseButtons.Left) {
689                    Zoom(near,far,m_zoomOffset / 100);
690                }
691                else if (e.Button == System.Windows.Forms.MouseButtons.Right)
692                    Zoom(near,far,- m_zoomOffset / 100);
693            }
694        }
695        protected override void OnMouseDoubleClick(MouseEventArgs e) {
696            base.OnMouseDoubleClick(e);
697            ResetView(true);
698            Refresh();
699        }
700        protected override void OnKeyDown(KeyEventArgs e) {
701            if (e.Control && !m_isCtrlKeyDown) {
702                m_oldSelectingMode = m_selectingMode;
703                m_selectingMode = InteractiveModes.Translating;
704                m_isCtrlKeyDown = true;
705                Cursor = Cursors.NoMove2D;
706                //m_isDragging = false;
707            }
708            base.OnKeyDown(e);
709        }
710        protected override void OnKeyUp(KeyEventArgs e) {
711            if (!e.Control) {
712                if (m_isCtrlKeyDown) {
713                    m_isCtrlKeyDown = false;
714                    m_selectingMode = m_oldSelectingMode;
715                }
716                Cursor = Cursors.Default;
717                //m_isDragging = false;
718            }
719            base.OnKeyUp(e);
720        }
721        protected override void OnPaint(System.Windows.Forms.PaintEventArgs e) {
722            if (DesignMode) {
723                e.Graphics.Clear(Color.LightBlue);
724                return;
725            }
726            if (e.ClipRectangle.Width == 0 || e.ClipRectangle.Height == 0) {
727#if TRACE
728                Trace.TraceInformation("{0},{1} ILPanel.OnPaint(): ClipRectangle.Size = empty -> skipping",DateTime.Now, Environment.TickCount);
729#endif
730                return;
731            }
732/* THIS IS PRELIMINARY IMPLEMENTATION! REASON: While using GDI renderer,
733 * it is importatnt, to have the whole (visible) surface area invalidated
734 * and available for clipping of the graphics objects in 'e'. Otherwise
735 * rendered objects will not show, after the buffers have swapped. The
736 * following code helps pick those situations, where the clipping region
737 * is only a subregion of the controls surface, but it introduces new
738 * problems, if the whole control is (partially) obscured by other controls.
739 * Since the GDI Renderer currently is not the recommended method of rendering,
740 * this code is commented until a better solution was found. */
741//            if (e.ClipRectangle.X > 0 || e.ClipRectangle.Y > 0) {
742//#if TRACE
743//                Trace.TraceInformation("{0},{1} ILPanel.OnPaint(): partial clipping detected -> refreshing whole controls area",DateTime.Now, Environment.TickCount);
744//#endif
745//                Refresh();
746//                return;
747//            }
748            try {
749#if TRACE
750                    Trace.TraceInformation("{0},{1} ILPanel.OnPaint(): started (re-)configure",DateTime.Now, Environment.TickCount);
751                    Trace.Indent();
752#endif
753                    Configure();
754                    if (m_isStartingUp && (m_autoZoomOptions != AutoZoomOptions.Never)) {
755                        ResetView(true);
756                    }
757#if TRACE
758                Trace.Unindent();
759                Trace.TraceInformation("{0},{1} ILPanel.OnPaint(): rendering started",DateTime.Now, Environment.TickCount);
760                Trace.Indent();
761                Trace.TraceInformation(String.Format("this: {1}, ClipRectangle: {0}, Graphics.ClipBounds: L:{2} T:{3} W:{4} H:{5}"
762                    ,e.ClipRectangle.ToString()
763                    ,this.ClientRectangle.ToString()
764                    ,e.Graphics.VisibleClipBounds.Left
765                    ,e.Graphics.VisibleClipBounds.Top
766                    ,e.Graphics.VisibleClipBounds.Width
767                    ,e.Graphics.VisibleClipBounds.Height));
768#endif
769                m_renderProperties.Graphics = e.Graphics;
770                m_renderProperties.Reason = RenderReason.PaintEvent;
771                m_renderProperties.MinX = int.MaxValue;
772                m_renderProperties.MinY = int.MaxValue;
773                m_renderProperties.MaxX = int.MinValue;
774                m_renderProperties.MaxY = int.MinValue;
775                RenderScene(m_renderProperties.Reset());
776#if TRACE
777                Trace.Unindent();
778                Trace.TraceInformation("{0},{1} ILPanel.OnPaint(): rendering ended",DateTime.Now, Environment.TickCount);
779#endif
780                if (m_isStartingUp) {
781                    m_isStartingUp = false;
782                    Refresh();
783                }
784                System.Diagnostics.Debug.WriteLine("Current Camera Setting: " + m_camera.ToString());
785            } catch (Exceptions.ILArgumentException exc) {
786#if TRACE
787                Trace.TraceWarning("{0},{1} ILPanel.OnPaint(): rendering failed. reason: {2}",DateTime.Now, Environment.TickCount,exc.ToString());
788                Trace.Indent();
789#endif
790                System.Diagnostics.Debug.WriteLine("ILPanel.OnPaint failed: " + exc.ToString());
791                throw new Exceptions.ILArgumentException("rendering failed. Details attached.",exc);
792            }
793        }
794        void m_legend_Changed(object sender, EventArgs e) {
795            Invalidate();
796        }
797
798        void m_graphs_GraphChanged(object sender, ILGraphChangedEventArgs args) {
799            ResetView(false);
800        }
801        protected void m_graphs_OnCollectionChanged(object sender, ILGraphCollectionChangedEventArgs args) {
802            if (args.Reason == GraphCollectionChangeReason.Added) {
803                if (AutoDefaultView && (args.Configurator != null)) {
804                    args.Configurator.ConfigurePanel(this);
805                }
806            }
807       }
808        protected void m_viewLimits_Changed(object sender, ClippingChangedEventArgs e) {
809            if (this.InvokeRequired && IsHandleCreated) {
810                try {
811                    Invoke(new ILClippingDataChangedEvent(m_viewLimits_Changed), sender, e);
812                } catch (Exception) { }
813            } else {
814                m_camera.LookAt = m_clippingView.CenterF;
815                OnViewLimitsChanged(e);
816            }
817        }
818        protected void m_dataLimits_Changed(object sender, ClippingChangedEventArgs e) {
819            if (m_autoDefaultView) {
820                m_defaultView.EventingSuspend();
821                bool oldDefaultViewSetting = m_autoDefaultView;
822                m_defaultView.LookAt = m_graphs.Limits.CenterF;
823                m_defaultView.Distance = m_graphs.Limits.SphereRadius * 2;
824                m_defaultView.EventingResume(false);
825            }
826            if (m_autoZoomOptions == AutoZoomOptions.OnDataChanges)
827                ResetView(false);
828            OnDataLimitsChanged(e); 
829        }
830
831        protected void m_colormap_Changed(object sender, EventArgs e) {
832            OnColormapChanged();
833        }
834        void m_selectionRectangle_Changed(object sender, EventArgs e) {
835            // nothing to do here
836        }
837
838        #endregion event handler
839
840        #region virtual abstract interface
841        /// <summary>
842        /// Get current rendering device (implementation dependent)
843        /// </summary>
844        /// <returns></returns>
845        public abstract object GetDeviceContext();
846        /// <summary>
847        /// Causes a reconfiguration of all axes and graphs on the next paint event
848        /// </summary>
849        /// <remarks>Call this method after any changes to vertex relevant data. It causes all drawable objects to clear their caches and recalculate all vertex data.</remarks>
850        protected new void Invalidate() {
851            if (!m_ready) return;
852            m_ready = false;
853            m_graphs.Invalidate();
854            m_axes.Invalidate();
855            //base.Invalidate(this.ClientRectangle, true); <- this would cause an immediate redraw also. Use Refresh() for this!
856        }
857        /// <summary>
858        /// update viewing limits to show all data, rotate the scene to default (-> DefaultView)
859        /// </summary>
860        public virtual void ResetView() {
861            ResetView(true);
862        }
863        /// <summary>
864        /// update viewing limits to show all data, optionally reset the scene rotation
865        /// </summary>
866        /// <param name="resetRotation">true: rotate the scene to the default (-> DefaultView)</param>
867        public virtual void ResetView(bool resetRotation) {
868            if (m_zoomAction != null)
869                m_zoomAction.Cancel();
870            m_clippingView.EventingSuspend();
871            m_clippingView.CopyFrom(m_graphs.Limits);
872            m_clippingView.Update(m_clippingView.CenterF,1.1f);
873            m_clippingView.EventingResume();
874            if (m_defaultView != null && resetRotation) {
875                m_camera.LookAt = m_defaultView.LookAt;
876                m_camera.Phi = m_defaultView.Phi;
877                m_camera.Rho = m_defaultView.Rho;
878                m_camera.Distance = m_defaultView.Distance;
879            }
880        }
881        /// <summary>
882        /// Move &amp; shrink/expand current view cube along a given line
883        /// </summary>
884        /// <param name="nearLineEnd"></param>
885        /// <param name="farLineEnd"></param>
886        /// <param name="offset"></param>
887        protected virtual void Zoom(ILPoint3Df nearLineEnd, ILPoint3Df farLineEnd, float offset) {
888            ILPoint3Df minCorner, maxCorner;
889            m_clippingView.GetZoomParameter(nearLineEnd,farLineEnd,offset, out minCorner, out maxCorner);
890            Zoom(minCorner,maxCorner);
891            //m_camera.LookAt = m_clippingView.CenterF;
892        }
893        /// <summary>
894        /// move the center of the viewing cube and expand / shrink the volume by offset
895        /// </summary>
896        /// <param name="center">new center</param>
897        /// <param name="offset">offset multiplicator, 1f means: no change</param>
898        protected virtual void Zoom(ILPoint3Df center, float offset) {
899            m_clippingView.Update(center,offset);
900            Refresh();
901        }
902        /// <summary>
903        /// Zoome the scene to new limits
904        /// </summary>
905        /// <param name="luCorner">'upper left' (first) corner of the new viewing cube</param>
906        /// <param name="rbCorner">'bottom right' (opposed) corner of the viewing cube</param>
907        protected virtual void Zoom(ILPoint3Df luCorner, ILPoint3Df rbCorner) {
908            if (m_zoomAction != null)
909                m_zoomAction.Cancel();
910            ILActionRamp ramp;
911            switch (m_zoomMode) {
912                case ZoomModes.Jump:
913                    ramp = ILActionRamp.NoRamp;
914                    break;
915                case ZoomModes.RollSoft:
916                    ramp = ILActionRamp.Soft;
917                    break;
918                case ZoomModes.RollHard:
919                    ramp = ILActionRamp.Hard;
920                    break;
921                case ZoomModes.RollOverride:
922                    ramp = ILActionRamp.Override;
923                    break;
924                default:
925                    ramp = ILActionRamp.Linear;
926                    break;
927            }
928            m_zoomAction = new ILZoomAction(m_clippingView.Min, luCorner, m_clippingView.Max, rbCorner, ramp, this);
929            m_zoomAction.Run();
930        }
931
932
933        /// <summary>
934        /// Transform two coordinates for a line from world to screen coordinates
935        /// </summary>
936        /// <param name="start">1st coordinate (world)</param>
937        /// <param name="end">2nd coordinate (world)</param>
938        /// <param name="start2D">[output] 1st coordinate (screen pixels)</param>
939        /// <param name="end2D">[output] 2nd coordinate (screen pixels)</param>
940        /// <remarks>This function is provided by the concrete derived class, using the
941        /// current rendering framework.</remarks>
942        public abstract void World2Screen(ILPoint3Df start, ILPoint3Df end, out Point start2D, out Point end2D);
943
944        /// <summary>
945        /// Transform from a point on screen into world coordinates [depricated]
946        /// </summary>
947        /// <param name="x">screen x</param>
948        /// <param name="y">screen y: GL viewport coord! -> (0,0) is lower left corner!</param>
949        /// <returns>world coordinate point</returns>
950        public abstract ILPoint3Df Screen2World2D(int x, int y);
951        /// <summary>
952        /// gives the line in world coords, a specific point on screen lays on
953        /// </summary>
954        /// <param name="x">screen x</param>
955        /// <param name="y">screen y: GL viewport coord! -> (0,0) is lower left corner</param>
956        /// <param name="farClip">far end point of the resulting line in world coords</param>
957        /// <param name="nearClip">near end point of the resulting line in world coords</param>
958        public abstract void Screen2World(int x, int y, out ILPoint3Df nearClip, out ILPoint3Df farClip);
959       
960        /// <summary>
961        /// Transform world coordinate to screen coordinate under current transformation
962        /// </summary>
963        /// <param name="worldPoint">world coordinate</param>
964        /// <returns>screen location</returns>
965        /// <remarks>the actual transform is carried out in the derived specialized class,
966        /// where the current transformation matrices are known</remarks>
967        public abstract Point World2Screen(ILPoint3Df worldPoint);
968        /// <summary>
969        /// Transform world coordinate to screen coordinate, provide (custom) modelview matrix
970        /// </summary>
971        /// <param name="worldPoint"></param>
972        /// <param name="modelview">(custom) model view matrix. The parameter must match the format required by the deriving concrete ILPanel class. ILOGLPanel: double[16]</param>
973        /// <returns>screen location</returns>
974        /// <remarks>the actual transform is carried out in the derived specialized class,
975        /// where the current transformation matrices are known</remarks>
976        public abstract Point World2Screen(ILPoint3Df worldPoint, double[] modelview);
977
978        /// <summary>
979        /// Draws content of this subfigure into predefined bitmap
980        /// </summary>
981        /// <param name="bitmap">predefined bitmap to draw content into. The size must have been initialized according to 'bounds'.</param>
982        /// <param name="bounds">Rectangle specifying the region to be copied.</param>
983        public new abstract void DrawToBitmap(Bitmap bitmap, Rectangle bounds);
984        #endregion
985
986        #region helper functions
987        /// <summary>
988        /// draws the selection rectangle with GDI functions
989        /// </summary>
990        /// <param name="endPoint">end point</param>
991        /// <remarks>The start point is stored in the member m_mouseStart.</remarks>
992        protected virtual void drawSelectionRect(Point endPoint) {
993            Graphics g = Graphics.FromHwnd(this.Handle);
994            Pen pen = new Pen(m_selectionRectangle.Color, 1.0f);
995            Point[] points = new Point[3];
996            // upper left corner
997            points[0] = new Point(m_mouseStart.X, m_mouseStart.Y + (endPoint.Y - m_mouseStart.Y) / 4);
998            points[1] = new Point(m_mouseStart.X, m_mouseStart.Y);
999            points[2] = new Point(m_mouseStart.X + (endPoint.X - m_mouseStart.X) / 4, m_mouseStart.Y);
1000            g.DrawLines(pen, points);
1001            // lower left corner
1002            points[0] = new Point(m_mouseStart.X, endPoint.Y - (endPoint.Y - m_mouseStart.Y) / 4);
1003            points[1] = new Point(m_mouseStart.X, endPoint.Y);
1004            points[2] = new Point(m_mouseStart.X + (endPoint.X - m_mouseStart.X) / 4, endPoint.Y);
1005            g.DrawLines(pen, points);
1006            // lower right corner
1007            points[0] = new Point(endPoint.X, endPoint.Y - (endPoint.Y - m_mouseStart.Y) / 4);
1008            points[1] = new Point(endPoint.X, endPoint.Y);
1009            points[2] = new Point(endPoint.X - (endPoint.X - m_mouseStart.X) / 4, endPoint.Y);
1010            g.DrawLines(pen, points);
1011            // upper right corner
1012            points[0] = new Point(endPoint.X, m_mouseStart.Y + (endPoint.Y - m_mouseStart.Y) / 4);
1013            points[1] = new Point(endPoint.X, m_mouseStart.Y);
1014            points[2] = new Point(endPoint.X - (endPoint.X - m_mouseStart.X) / 4, m_mouseStart.Y);
1015            g.DrawLines(pen, points);
1016        }
1017        public static short StippleFromLineStyle(LineStyle style, ref int stipFactr) {
1018            short ret = 1;
1019            switch (style) {
1020                case LineStyle.Dashed:
1021                    ret = (short)255;
1022                    stipFactr = 2;
1023                    break;
1024                case LineStyle.PointDash:
1025                    ret = (short)255 + 4096;
1026                    stipFactr = 1;
1027                    break;
1028                case LineStyle.Dotted:
1029                    ret = (short)13107; // 3 + 48 + 768 + 8192 + 4096;
1030                    stipFactr = 2;
1031                    break;
1032                case LineStyle.UserPattern:
1033                    break;
1034                    // ret = 0;
1035                case LineStyle.None:
1036                    break;
1037                default:      // solid
1038                    ret = (short)-1;
1039                    break;
1040            }
1041            return ret;
1042        }
1043        private void calculateDefaultView(bool setPositions, bool setDirection) {
1044            m_defaultView.EventingSuspend();
1045            if (setPositions) {
1046                m_defaultView.LookAt = m_graphs.Limits.CenterF;
1047                m_defaultView.Distance = m_clippingView.SphereRadius * 2f;
1048            }
1049            if (setDirection) {
1050                m_defaultView.Phi = 0; // -(float)Math.PI / 2;
1051                m_defaultView.Rho = 0;
1052            }
1053            m_defaultView.EventingResume(false);
1054        }
1055        #endregion
1056
1057        #region private rendering setup helper
1058        protected void helperUpdateMatrices(float width2D, float height2D, out float worldSceneWidth, out float worldSceneHeight, out ILPoint3Df top, out ILPoint3Df moveOffset)
1059        {
1060            float localPlotCubeScreenRectLeft;
1061            float localPlotCubeScreenRectWidth;
1062
1063            float localPlotCubeScreenRectTop;
1064            float localPlotCubeScreenRectHeight;
1065
1066            float offsetX;
1067            float offsetY;
1068
1069            localPlotCubeScreenRectHeight = m_plotBoxScreenRectF.Height;
1070            localPlotCubeScreenRectWidth = m_plotBoxScreenRectF.Width;
1071            localPlotCubeScreenRectTop = m_plotBoxScreenRectF.Top;
1072            localPlotCubeScreenRectLeft = m_plotBoxScreenRectF.Left;
1073
1074            if (AspectRatio == AspectRatioMode.StretchToFill)
1075            {
1076                worldSceneWidth = width2D / localPlotCubeScreenRectWidth;
1077                worldSceneHeight = height2D / localPlotCubeScreenRectHeight;
1078            }
1079            else
1080            { //if (RenderAspectRatioMode == RenderAspectRatioMode.MaintainRatios) {
1081                float plotCubeScreenRectAspectRatio =
1082                    (m_plotBoxScreenRectF.Width * ClientSize.Width)
1083                    / (m_plotBoxScreenRectF.Height * ClientSize.Height);
1084                float dataAspectRatio = width2D / height2D;
1085                if (plotCubeScreenRectAspectRatio > dataAspectRatio)
1086                {
1087                    // width > height
1088                    worldSceneHeight = height2D;
1089                    worldSceneWidth = worldSceneHeight * dataAspectRatio;
1090                    // enlarge the scene, so we have rendering margin outside the data cube
1091                    worldSceneHeight /= localPlotCubeScreenRectHeight;
1092                    worldSceneWidth /= (localPlotCubeScreenRectWidth * (dataAspectRatio / plotCubeScreenRectAspectRatio));
1093                }
1094                else
1095                {
1096                    // height >= width
1097                    worldSceneWidth = width2D;
1098                    worldSceneHeight = worldSceneWidth / dataAspectRatio;
1099                    // enlarge the scene, so we have rendering margin outside the data cube
1100                    worldSceneWidth /= localPlotCubeScreenRectWidth;
1101                    worldSceneHeight /= (localPlotCubeScreenRectHeight / (dataAspectRatio / plotCubeScreenRectAspectRatio));
1102                }
1103            }
1104            // one more pixel please...
1105            worldSceneHeight = (worldSceneHeight / ClientSize.Height * (ClientSize.Height + 1));
1106            worldSceneWidth = (worldSceneWidth / ClientSize.Width * (ClientSize.Width + 1));
1107            // if PlotCubeScreenRect is not centered, we move the scene out of center accordingly (..further down)
1108            top = new ILPoint3Df(-m_camera.SinPhi * m_camera.CosRho, m_camera.CosPhi * m_camera.CosRho, m_camera.SinRho);
1109            ILPoint3Df moveX = ILPoint3Df.crossN(m_camera.Position - m_camera.LookAt, top);
1110            offsetX = -(localPlotCubeScreenRectLeft + (localPlotCubeScreenRectWidth / 2f) - 0.5f) * worldSceneWidth;
1111            offsetY = -(localPlotCubeScreenRectTop + (localPlotCubeScreenRectHeight / 2f) - 0.5f) * worldSceneHeight;
1112            moveOffset = top * offsetY + moveX * offsetX;
1113        }
1114        protected virtual void RenderScene(ILRenderProperties p) {
1115            //System.Diagnostics.Debug.Print("m_camera:{0}", m_camera);
1116            if (!DesignMode) {
1117                lock (m_sortingCacheList) {
1118                    iRenderingState1(p); //make current
1119                    // configure axes (determine tick labels in mode 'auto')
1120                    m_axes.XAxis.Configure(p);
1121                    m_axes.YAxis.Configure(p);
1122                    m_axes.ZAxis.Configure(p);
1123
1124
1125                    //computeLayoutData(p);
1126                    float rotatedViewLimitX, rotatedViewLimitY, rotatedViewLimitZ;
1127                    GetTransformedSize(out rotatedViewLimitX, out rotatedViewLimitY, out rotatedViewLimitZ);
1128
1129                    // determine needed margins according to current tic label collections (which are left over from last rendering run or empty)
1130                    Size ticLabelsMargins = GetMaxTicLabelSize(p.Graphics);
1131                    updatePlotCubeScreenRect(rotatedViewLimitX, rotatedViewLimitY, ticLabelsMargins);
1132                    p.PassCount = 0;
1133                    for (; p.PassCount < MAXRENDERPASSES; p.PassCount++) {
1134                        UpdateMatrices(rotatedViewLimitX, rotatedViewLimitY, rotatedViewLimitZ);
1135
1136                        updateTickLabelLines();
1137                        updateLabelPositions(p);
1138                        if (p.PassCount == 0) {
1139                        }
1140                        iRenderingState2(p);  // do the actual drawing
1141                        //iRenderingState3(p);
1142                        #region check if we can fit the plot cube more precisely
1143                        if (m_plotBoxScreenSizeMode == PlotBoxScreenSizeMode.StrictOptimal) {
1144                            float t = m_plotBoxScreenRectF.Top;
1145                            float l = m_plotBoxScreenRectF.Left;
1146                            float r = m_plotBoxScreenRectF.Right;
1147                            float b = m_plotBoxScreenRectF.Bottom, tmp;
1148                            bool resize = false;
1149                            tmp = (float)p.MinX / ClientSize.Width;
1150                            if (tmp < l) {
1151                                if (p.MinX != 0) {
1152                                    l -= tmp;
1153                                    resize = true;
1154                                }
1155                            } else if (l > 0) {
1156                                l = 0;
1157                                resize = true;
1158                            }
1159                            tmp = (float)p.MaxX / ClientSize.Width;
1160                            if (tmp > r) {
1161                                if (p.MaxX != (ClientSize.Width - 1)) {
1162                                    r += (1 - tmp);
1163                                    resize = true;
1164                                }
1165                            } else if (r < 1) {
1166                                r = (float)(ClientSize.Width - 1) / ClientSize.Width;
1167                                resize = true;
1168                            }
1169                            tmp = (float)p.MinY / ClientSize.Height;
1170                            if (tmp < t) {
1171                                if (p.MinY != 0) {
1172                                    t -= tmp;
1173                                    resize = true;
1174                                }
1175                            } else if (t > 0) {
1176                                t = 0;
1177                                resize = true;
1178                            }
1179                            tmp = (float)p.MaxY / ClientSize.Height;
1180                            if (tmp > b) {
1181                                if (p.MaxY != (ClientSize.Height - 1)) {
1182                                    b += (1 - tmp);
1183                                    resize = true;
1184                                }
1185                            } else if (b < 1) {
1186                                b = (float)(ClientSize.Height - 1) / ClientSize.Height;
1187                                resize = true;
1188                            }
1189                            if (resize) {
1190                                // ... there is still room left we can use for enlarging the render cube
1191                                m_plotBoxScreenRectF = new RectangleF(l, t, r - l, b - t);
1192                                p.Reason = RenderReason.RecalcLabels;
1193                                p.MaxY = int.MinValue;
1194                                p.MaxX = int.MinValue;
1195                                p.MinY = int.MaxValue;
1196                                p.MinX = int.MaxValue;
1197                            }
1198                            continue;
1199                        }
1200                        #endregion
1201                        break;
1202                    }
1203                    iRenderingState3(p);
1204                }
1205
1206            }
1207        }
1208        protected abstract void iRenderingState1(ILRenderProperties p);
1209        /// <summary>
1210        /// [internal] Configure this panel, to make it ready for output, set "m_ready = true" at end!
1211        /// </summary>
1212        protected virtual void Configure() {
1213            foreach (ILGraph graph in m_graphs) {
1214                graph.Configure();
1215            }
1216            // update clipping view
1217            m_clipplanes[0] = -1.0; m_clipplanes[3] = m_clippingView.Max.X;
1218            m_clipplanes[4] = 1.0; m_clipplanes[7] = -m_clippingView.Min.X;
1219            m_clipplanes[9] = -1.0; m_clipplanes[11] = m_clippingView.Max.Y;
1220            m_clipplanes[13] = 1.0; m_clipplanes[15] = -m_clippingView.Min.Y;
1221            m_clipplanes[18] = -1.0; m_clipplanes[19] = m_clippingView.Max.Z;
1222            m_clipplanes[22] = 1.0; m_clipplanes[23] = -m_clippingView.Min.Z;
1223
1224            m_ready = true;
1225        }
1226        /// <summary>
1227        /// draw the scene: all axes, graphs, background etc. (device dependant)
1228        /// </summary>
1229        /// <param name="p"></param>
1230        protected abstract void iRenderingState2(ILRenderProperties p);
1231        protected abstract void iRenderingState3(ILRenderProperties p);
1232        protected abstract void UpdateMatrices(float width2D, float height2D, float depth2D);
1233        /// <summary>
1234        /// initialize all device specific classes, first called after the panel has been created
1235        /// </summary>
1236        /// <remarks>derived types should init all devices here</remarks>
1237        protected virtual void Initialize() { }
1238        protected PointF GetXTickLabelLine(out Point start2D, out Point end2D) {
1239            PointF anchor = new PointF(0,0); // TickLabelAlign.left;
1240            ILPoint3Df start = new ILPoint3Df(), end = new ILPoint3Df();
1241            ILTickCollection ticks = m_axes[0].LabeledTicks;
1242            float tickLen = (ticks.Direction == TickDirection.Outside) ?
1243                             ticks.TickFraction : 0f;
1244            float padX = ticks.Padding, padY = padX;
1245            switch (m_camera.Quadrant) {
1246                case CameraQuadrant.TopLeftFront:
1247                    start.X = m_clippingView.Min.X;
1248                    start.Y = m_clippingView.Min.Y - tickLen;
1249                    start.Z = m_clippingView.Min.Z;
1250                    end.X = m_clippingView.Max.X;
1251                    end.Y = start.Y;
1252                    end.Z = start.Z;
1253                    anchor = new PointF(0,0); //TickLabelAlign.left | TickLabelAlign.top;
1254                    padX = -m_camera.SinPhi * padX;
1255                    padY = (m_camera.CosPhi - m_camera.SinRho * m_camera.SinPhi) * (padY) + m_camera.SinPhi * ticks.Font.Height / 2;
1256                    break;
1257                case CameraQuadrant.TopLeftBack:
1258                    start.X = m_clippingView.Min.X;
1259                    start.Y = m_clippingView.Max.Y + tickLen;
1260                    start.Z = m_clippingView.Min.Z;
1261                    end.X = m_clippingView.Max.X;
1262                    end.Y = start.Y;
1263                    end.Z = start.Z;
1264                    anchor = new PointF(1,0); //TickLabelAlign.right | TickLabelAlign.top;
1265                    padX *= m_camera.SinPhi;
1266                    padY = (-m_camera.CosPhi - m_camera.SinRho * m_camera.SinPhi) * padY + m_camera.SinPhi * ticks.Font.Height / 2;
1267                    break;
1268                case CameraQuadrant.TopRightBack:
1269                    start.X = m_clippingView.Min.X;
1270                    start.Y = m_clippingView.Max.Y + tickLen;
1271                    start.Z = m_clippingView.Min.Z;
1272                    end.X = m_clippingView.Max.X;
1273                    end.Y = start.Y;
1274                    end.Z = start.Z;
1275                    anchor = new PointF(0,0); //TickLabelAlign.left | TickLabelAlign.top;
1276                    padX *= m_camera.SinPhi;
1277                    padY = (-m_camera.CosPhi + m_camera.SinRho * m_camera.SinPhi) * padY - m_camera.SinPhi * ticks.Font.Height / 2;
1278                    break;
1279                case CameraQuadrant.TopRightFront:
1280                    start.X = m_clippingView.Min.X;
1281                    start.Y = m_clippingView.Min.Y - tickLen;
1282                    start.Z = m_clippingView.Min.Z;
1283                    end.X = m_clippingView.Max.X;
1284                    end.Y = start.Y;
1285                    end.Z = start.Z;
1286                    if (m_camera.Is2DView) {
1287                        anchor = new PointF(.5f, 0); //TickLabelAlign.center | TickLabelAlign.top;
1288                    } else {
1289                        anchor = new PointF(1,0); //TickLabelAlign.right | TickLabelAlign.top;
1290                    }
1291                    padX *= -m_camera.SinPhi;
1292                    padY = (m_camera.CosPhi + m_camera.SinRho * m_camera.SinPhi) * padY - m_camera.SinPhi * ticks.Font.Height / 2;
1293                    break;
1294                case CameraQuadrant.BottomLeftFront:
1295                    start.X = m_clippingView.Min.X;
1296                    start.Y = m_clippingView.Max.Y + tickLen;
1297                    start.Z = m_clippingView.Min.Z;
1298                    end.X = m_clippingView.Max.X;
1299                    end.Y = start.Y;
1300                    end.Z = start.Z;
1301                    anchor = new PointF(1,0); //TickLabelAlign.right | TickLabelAlign.top;
1302                    padX *= m_camera.SinPhi;
1303                    padY = (m_camera.CosPhi - m_camera.SinRho * m_camera.SinPhi) * padY + m_camera.SinPhi * ticks.Font.Height / 2;
1304                    break;
1305                case CameraQuadrant.BottomLeftBack:
1306                    start.X = m_clippingView.Min.X;
1307                    start.Y = m_clippingView.Min.Y - tickLen;
1308                    start.Z = m_clippingView.Min.Z;
1309                    end.X = m_clippingView.Max.X;
1310                    end.Y = start.Y;
1311                    end.Z = start.Z;
1312                    anchor = new PointF(0,0); //TickLabelAlign.left | TickLabelAlign.top;
1313                    padX *= -m_camera.SinPhi;
1314                    padY = (-m_camera.CosPhi - m_camera.SinRho * m_camera.SinPhi) * padY + m_camera.SinPhi * ticks.Font.Height / 2;
1315                    break;
1316                case CameraQuadrant.BottomRightBack:
1317                    start.X = m_clippingView.Min.X;
1318                    start.Y = m_clippingView.Min.Y - tickLen;
1319                    start.Z = m_clippingView.Min.Z;
1320                    end.X = m_clippingView.Max.X;
1321                    end.Y = start.Y;
1322                    end.Z = start.Z;
1323                    anchor = new PointF(1,0); //TickLabelAlign.right | TickLabelAlign.top;
1324                    padX *= -m_camera.SinPhi;
1325                    padY = (-m_camera.CosPhi + m_camera.SinRho * m_camera.SinPhi) * padY - m_camera.SinPhi * ticks.Font.Height / 2;
1326                    break;
1327                default:    // BottomRightFront
1328                    start.X = m_clippingView.Min.X;
1329                    start.Y = m_clippingView.Max.Y + tickLen;
1330                    start.Z = m_clippingView.Min.Z;
1331                    end.X = m_clippingView.Max.X;
1332                    end.Y = start.Y;
1333                    end.Z = start.Z;
1334                    anchor = new PointF(0,0); //TickLabelAlign.left | TickLabelAlign.top;
1335                    padX *= m_camera.SinPhi;
1336                    padY = (m_camera.CosPhi + m_camera.SinRho * m_camera.SinPhi) * padY - m_camera.SinPhi * ticks.Font.Height / 2;
1337                    break;
1338            }
1339            World2Screen(start, end, out start2D, out end2D);
1340            // align in screen coords
1341//            int offY = (int)((m_camera.SinRho - (m_camera.SinPhi % Math.PI))
1342//                        * m_axes[0].LabeledTicks.Font.Height / 2
1343//                        + padY);
1344            // add padding
1345            //System.Diagnostics.Debug.WriteLine(m_camera.Phi);
1346            start2D.Y += (int)padY + 1;
1347            end2D.Y += (int)padY + 1;
1348            start2D.X += (int)(padX + 1);
1349            end2D.X += (int)(padX + 1);
1350            return anchor;
1351        }
1352        protected PointF GetYTickLabelLine(out Point start2D, out Point end2D) {
1353            PointF anchor; // = new PointF(0,0); // TickLabelAlign.left;
1354            ILPoint3Df start = new ILPoint3Df(), end = new ILPoint3Df();
1355            ILTickCollection ticks = m_axes[1].LabeledTicks;
1356            float tickLen = (ticks.Direction == TickDirection.Outside) ?
1357                ticks.TickFraction : 0f;
1358            float padX = ticks.Padding, padY = padX;
1359            if (m_camera.Is2DView) {
1360                start.X = m_clippingView.Min.X - tickLen;
1361                start.Y = m_clippingView.Min.Y;
1362                start.Z = m_clippingView.Min.Z;
1363                end.X = start.X;
1364                end.Y = m_clippingView.Max.Y;
1365                end.Z = start.Z;
1366                anchor = new PointF(1, 0); // TickLabelAlign.right | TickLabelAlign.top;
1367                padX *= -m_camera.CosPhi;
1368                padY = (-m_camera.SinPhi + m_camera.SinRho * m_camera.CosPhi) * padY - m_camera.CosPhi * ticks.Font.Height / 2;
1369            } else {
1370                switch (m_camera.Quadrant) {
1371                    case CameraQuadrant.TopLeftFront:
1372                        start.X = m_clippingView.Min.X - tickLen;
1373                        start.Y = m_clippingView.Min.Y;
1374                        start.Z = m_clippingView.Min.Z;
1375                        end.X = start.X;
1376                        end.Y = m_clippingView.Max.Y;
1377                        end.Z = start.Z;
1378                        anchor = new PointF(1, 0); // TickLabelAlign.right | TickLabelAlign.top;
1379                        padX *= -m_camera.CosPhi;
1380                        padY = (-m_camera.SinPhi + m_camera.SinRho * m_camera.CosPhi) * padY - m_camera.CosPhi * ticks.Font.Height / 2;
1381                        break;
1382                    case CameraQuadrant.TopLeftBack:
1383                        start.X = m_clippingView.Min.X - tickLen;
1384                        start.Y = m_clippingView.Min.Y;
1385                        start.Z = m_clippingView.Min.Z;
1386                        end.X = start.X;
1387                        end.Y = m_clippingView.Max.Y;
1388                        end.Z = start.Z;
1389                        anchor = new PointF(0, 0); // TickLabelAlign.left | TickLabelAlign.top;
1390                        padX *= -m_camera.CosPhi;
1391                        padY = (-m_camera.SinPhi - m_camera.SinRho * m_camera.CosPhi) * padY + m_camera.CosPhi * ticks.Font.Height / 2;
1392                        break;
1393                    case CameraQuadrant.TopRightBack:
1394                        start.X = m_clippingView.Max.X + tickLen;
1395                        start.Y = m_clippingView.Min.Y;
1396                        start.Z = m_clippingView.Min.Z;
1397                        end.X = start.X;
1398                        end.Y = m_clippingView.Max.Y;
1399                        end.Z = start.Z;
1400                        anchor = new PointF(1,0); // TickLabelAlign.right | TickLabelAlign.top;
1401                        padX *= m_camera.CosPhi;
1402                        padY = (m_camera.SinPhi - m_camera.SinRho * m_camera.CosPhi) * padY + m_camera.CosPhi * ticks.Font.Height / 2;
1403                        break;
1404                    case CameraQuadrant.TopRightFront:
1405                        start.X = m_clippingView.Max.X + tickLen;
1406                        start.Y = m_clippingView.Min.Y;
1407                        start.Z = m_clippingView.Min.Z;
1408                        end.X = start.X;
1409                        end.Y = m_clippingView.Max.Y;
1410                        end.Z = start.Z;
1411                        anchor = new PointF(0,0); // TickLabelAlign.left | TickLabelAlign.top;
1412                        padX *= m_camera.CosPhi;
1413                        padY = (m_camera.SinPhi + m_camera.SinRho * m_camera.CosPhi) * padY - m_camera.CosPhi * ticks.Font.Height / 2;
1414                        break;
1415                    case CameraQuadrant.BottomLeftFront:
1416                        start.X = m_clippingView.Max.X + tickLen;
1417                        start.Y = m_clippingView.Min.Y;
1418                        start.Z = m_clippingView.Min.Z;
1419                        end.X = start.X;
1420                        end.Y = m_clippingView.Max.Y;
1421                        end.Z = start.Z;
1422                        anchor = new PointF(0,0); //  TickLabelAlign.left | TickLabelAlign.top;
1423                        padX *= m_camera.CosPhi;
1424                        padY = (-m_camera.SinPhi + m_camera.SinRho * m_camera.CosPhi) * padY - m_camera.CosPhi * ticks.Font.Height / 2;
1425                        break;
1426                    case CameraQuadrant.BottomLeftBack:
1427                        start.X = m_clippingView.Max.X + tickLen;
1428                        start.Y = m_clippingView.Min.Y;
1429                        start.Z = m_clippingView.Min.Z;
1430                        end.X = start.X;
1431                        end.Y = m_clippingView.Max.Y;
1432                        end.Z = start.Z;
1433                        anchor = new PointF(1,0); // TickLabelAlign.right | TickLabelAlign.top;
1434                        padX *= m_camera.CosPhi;
1435                        padY = (-m_camera.SinPhi - m_camera.SinRho * m_camera.CosPhi) * padY + m_camera.CosPhi * ticks.Font.Height / 2;
1436                        break;
1437                    case CameraQuadrant.BottomRightBack:
1438                        start.X = m_clippingView.Min.X - tickLen;
1439                        start.Y = m_clippingView.Min.Y;
1440                        start.Z = m_clippingView.Min.Z;
1441                        end.X = start.X;
1442                        end.Y = m_clippingView.Max.Y;
1443                        end.Z = start.Z;
1444                        anchor = new PointF(0,0); // TickLabelAlign.left | TickLabelAlign.top;
1445                        padX *= -m_camera.CosPhi;
1446                        padY = (m_camera.SinPhi - m_camera.SinRho * m_camera.CosPhi) * padY + m_camera.CosPhi * ticks.Font.Height / 2;
1447                        break;
1448                    default:    // BottomRightFront
1449                        start.X = m_clippingView.Min.X - tickLen;
1450                        start.Y = m_clippingView.Min.Y;
1451                        start.Z = m_clippingView.Min.Z;
1452                        end.X = start.X;
1453                        end.Y = m_clippingView.Max.Y;
1454                        end.Z = start.Z;
1455                        anchor = new PointF(1,0); // TickLabelAlign.right | TickLabelAlign.top;
1456                        padX *= -m_camera.CosPhi;
1457                        padY = (m_camera.SinPhi + m_camera.SinRho * m_camera.CosPhi) * padY - m_camera.CosPhi * ticks.Font.Height / 2;
1458                        break;
1459                }
1460            }
1461            World2Screen(start, end, out start2D, out end2D);
1462            // align in screen coords
1463            //int offY = (int)(Math.Abs(m_camera.CosPhi) * ticks.Font.Height / 2);
1464            //offY -= (int)(Math.Sin(m_camera.Rho) * ticks.Font.Height / 2);
1465            start2D.Y += (int)padY;
1466            end2D.Y += (int)padY;
1467            start2D.X += (int)padX;
1468            end2D.X += (int)padX;
1469            return anchor;
1470        }
1471        protected PointF GetZTickLabelLine(out Point start2D, out Point end2D) {
1472            PointF anchor = new PointF(1, .5f); // TickLabelAlign.vertCenter | TickLabelAlign.right;
1473            ILPoint3Df start = new ILPoint3Df(), end = new ILPoint3Df();
1474            ILTickCollection ticks = m_axes[2].LabeledTicks;
1475            float tickLen = 0;
1476            if (ticks.Direction == TickDirection.Outside)
1477                tickLen = ticks.TickFraction;
1478            start.Z = m_clippingView.Min.Z;
1479            switch (m_camera.Quadrant) {
1480                case CameraQuadrant.TopLeftFront:
1481                    start.X = m_clippingView.Min.X - tickLen;
1482                    start.Y = m_clippingView.Max.Y + tickLen;
1483                    break;
1484                case CameraQuadrant.TopLeftBack:
1485                    start.X = m_clippingView.Max.X + tickLen;
1486                    start.Y = m_clippingView.Max.Y + tickLen;
1487                    break;
1488                case CameraQuadrant.TopRightBack:
1489                    start.X = m_clippingView.Max.X + tickLen;
1490                    start.Y = m_clippingView.Min.Y - tickLen;
1491                    break;
1492                case CameraQuadrant.TopRightFront:
1493                    start.X = m_clippingView.Min.X - tickLen;
1494                    start.Y = m_clippingView.Min.Y - tickLen;
1495                    break;
1496                case CameraQuadrant.BottomLeftFront:
1497                    start.X = m_clippingView.Min.X - tickLen;
1498                    start.Y = m_clippingView.Max.Y + tickLen;
1499                    break;
1500                case CameraQuadrant.BottomLeftBack:
1501                    start.X = m_clippingView.Max.X + tickLen;
1502                    start.Y = m_clippingView.Max.Y + tickLen;
1503                    break;
1504                case CameraQuadrant.BottomRightBack:
1505                    start.X = m_clippingView.Max.X + tickLen;
1506                    start.Y = m_clippingView.Min.Y - tickLen;
1507                    break;
1508                case CameraQuadrant.BottomRightFront:
1509                    start.X = m_clippingView.Min.X - tickLen;
1510                    start.Y = m_clippingView.Min.Y - tickLen;
1511                    break;
1512                default:
1513                    break;
1514            }
1515            end = start;
1516            end.Z = m_clippingView.Max.Z;
1517            World2Screen(start, end, out start2D, out end2D);
1518            start2D.X -= (ticks.Padding - 1);
1519            end2D.X -= (ticks.Padding - 1);
1520            return anchor;
1521        }
1522        /// <summary>
1523        /// Get size of projected view cube - after (!) rotation but before projection -> world space
1524        /// includes the bounding box, tightly enclosing the current view limits setting
1525        /// No labels, No ticks included!! Just the data cube with roatation!
1526        /// </summary>
1527        /// <param name="x">out, screen size for X</param>
1528        /// <param name="y">out, screen size for Y</param>
1529        /// <param name="z">out, screen size for Z</param>
1530        protected virtual void GetTransformedSize(out float x, out float y, out float z) {
1531            float xSize = m_clippingView.WidthF;   // the unrotated width - without labels size
1532            float ySize = m_clippingView.HeightF;  // dito for height
1533            float zSize = m_clippingView.DepthF;
1534            if (m_camera.Rho != 0.0f || m_camera.Phi != 0.0f) { // standard 2D view?
1535                float cosPhi = Math.Abs(m_camera.CosPhi);
1536                float sinPhi = Math.Abs(m_camera.SinPhi);
1537                x = (cosPhi * xSize + sinPhi * ySize); //zSize * Math.Abs(m_camera.SinRho) + (Math.Abs(m_camera.CosRho) *
1538                y = zSize * Math.Abs(m_camera.SinRho)
1539                          + (Math.Abs(m_camera.CosRho) * (sinPhi * xSize + cosPhi * ySize));
1540                z = zSize * Math.Abs(m_camera.CosRho)
1541                          + (Math.Abs(m_camera.SinRho) * (sinPhi * xSize + cosPhi * ySize));
1542            } else {
1543                x = xSize;
1544                y = ySize;
1545                z = zSize;
1546            }
1547        }
1548
1549        private void axisLabelVertical2D(ILAxis axis) {
1550            ILLabel label = axis.Label;
1551            ILTickCollection ticks = axis.LabeledTicks;
1552            Size tickSize = ticks.Size, labelSize = label.Size;
1553            label.Orientation = TextOrientation.Vertical;
1554            label.Anchor = new PointF(.5f, 0);
1555            label.m_position.X = ticks.m_lineEnd.X - tickSize.Width - ticks.Padding - label.Padding;
1556            switch (label.Alignment) {
1557                case LabelAlign.Center:
1558                    label.m_position.Y = (ticks.m_lineEnd.Y + ticks.m_lineStart.Y) / 2;
1559                    break;
1560                case LabelAlign.Upper:
1561                    label.m_position.Y = ticks.m_lineEnd.Y + labelSize.Width / 2;
1562                    break;
1563                default:        // lower
1564                    label.m_position.Y = ticks.m_lineStart.Y - labelSize.Width / 2;
1565                    break;
1566            }
1567            if (label.m_position.Y < labelSize.Width / 2) {
1568                label.m_position.Y = labelSize.Width / 2;
1569            }
1570            if (label.m_position.Y > ClientSize.Height - 1 - labelSize.Width / 2) {
1571                label.m_position.Y = ClientSize.Height - 1 - labelSize.Width / 2;
1572            }
1573        }
1574        private void positionZAxisLabel(ILAxis axis) {
1575            ILLabel label = axis.Label;
1576            ILTickCollection ticks = axis.LabeledTicks;
1577            Size tickSize = ticks.Size, labelSize = label.Size;
1578            label.Orientation = TextOrientation.Vertical;
1579            label.Anchor = new PointF(.5f, 0);
1580            switch (label.Alignment) {
1581                case LabelAlign.Center:
1582                    label.m_position.Y = (ticks.m_lineStart.Y + ticks.m_lineEnd.Y) / 2;
1583                    break;
1584                case LabelAlign.Upper:
1585                    label.m_position.Y = ticks.m_lineEnd.Y - labelSize.Width / 2;
1586                    break;
1587                default:        // lower
1588                    label.m_position.Y = ticks.m_lineStart.Y + labelSize.Width / 2 ;
1589                    break;
1590            }
1591            label.m_position.X = ticks.m_lineStart.X - tickSize.Width - ticks.Padding - label.Padding;
1592            if (label.m_position.Y < labelSize.Width / 2) {
1593                label.m_position.Y = labelSize.Width / 2;
1594            }
1595            if (label.m_position.Y > ClientSize.Height - 1 - labelSize.Width / 2) {
1596                label.m_position.Y = ClientSize.Height - 1 - labelSize.Width / 2;
1597                //label.Orientation = TextOrientation.Horizontal;
1598                //label.m_position.X = label.Padding;
1599                //label.m_position.Y = label.Padding;
1600            }
1601        }
1602        private void axisLabel_BottomRightTopLeft(ILRenderProperties p, ILAxis axis) {
1603            ILLabel label = axis.Label;
1604            ILTickCollection ticks = axis.LabeledTicks;
1605            Size tickSize = ticks.Size, labelSize = label.Size;
1606            label.Anchor = new PointF(.5f, 0);
1607            bool horiz = decideLabelHorizontalOrientation(p, m_camera, axis);
1608            if (horiz) {
1609                #region Horizontal
1610                label.Orientation = TextOrientation.Horizontal;
1611                switch (label.Alignment) {
1612                    case LabelAlign.Center:
1613                        label.m_position.X = (ticks.m_lineStart.X + ticks.m_lineEnd.X) / 2;
1614                        break;
1615                    case LabelAlign.Upper:
1616                        label.m_position.X = ticks.m_lineEnd.X + labelSize.Width / 2;
1617                        break;
1618                    default:        // lower
1619                        label.m_position.X = ticks.m_lineStart.X - labelSize.Width / 2;
1620                        break;
1621                }
1622                label.m_position.Y = ticks.m_lineStart.Y + tickSize.Height + ticks.Padding + label.Padding;
1623                if (label.m_position.X < labelSize.Width / 2) {
1624                    label.m_position.X = labelSize.Width / 2;
1625                }
1626                #endregion
1627            } else {
1628                #region Vertical
1629                label.Orientation = TextOrientation.Vertical;
1630                switch (label.Alignment) {
1631                    case LabelAlign.Center:
1632                        label.m_position.Y = (ticks.m_lineStart.Y + ticks.m_lineEnd.Y) / 2;
1633                        break;
1634                    case LabelAlign.Upper:
1635                        label.m_position.Y = ticks.m_lineEnd.Y + labelSize.Width / 2;
1636                        break;
1637                    default:        // lower
1638                        label.m_position.Y = ticks.m_lineStart.Y - labelSize.Width / 2;
1639                        break;
1640                }
1641                label.m_position.X = ticks.m_lineEnd.X - tickSize.Width - label.Padding - ticks.Padding;
1642                if (label.m_position.Y < labelSize.Width / 2)
1643                    label.m_position.Y = labelSize.Width / 2;
1644                if (label.m_position.Y > ClientSize.Height - 1 - labelSize.Width / 2) {
1645                    label.m_position.Y = ClientSize.Height - 1 - labelSize.Width / 2;
1646                }
1647                #endregion
1648            }
1649        }
1650        private void axisLabel_BottomLeftTopRight(ILRenderProperties p,  ILAxis axis) {
1651            ILLabel label = axis.Label;
1652            ILTickCollection ticks = axis.LabeledTicks;
1653            Size tickSize = ticks.Size, labelSize = label.Size;
1654            bool horiz = decideLabelHorizontalOrientation(p, m_camera, axis);
1655            if (horiz) {
1656                #region Horizontal
1657                label.Orientation = TextOrientation.Horizontal;
1658                label.Anchor = new PointF(0.5f,0);
1659                switch (label.Alignment) {
1660                    case LabelAlign.Center:
1661                        label.m_position.X = (ticks.m_lineEnd.X + ticks.m_lineStart.X) / 2;
1662                        break;
1663                    case LabelAlign.Upper:
1664                        label.m_position.X = ticks.m_lineEnd.X - label.Size.Width / 2;
1665                        break;
1666                    default:        // lower
1667                        label.m_position.X = ticks.m_lineStart.X + label.Size.Width / 2;
1668                        break;
1669                }
1670                label.m_position.Y = ticks.m_lineStart.Y + tickSize.Height + ticks.Padding + label.Padding;
1671                if (label.m_position.X > ClientSize.Width - labelSize.Width / 2) {
1672                    label.m_position.X = ClientSize.Width - labelSize.Width / 2;
1673                }
1674                #endregion
1675            } else {
1676                #region Vertical
1677                label.Orientation = TextOrientation.Vertical;
1678                label.Anchor = new PointF(0.5f, 1);
1679                switch (label.Alignment) {
1680                    case LabelAlign.Center:
1681                        label.m_position.Y = (ticks.m_lineEnd.Y + ticks.m_lineStart.Y) / 2;
1682                        break;
1683                    case LabelAlign.Upper:
1684                        label.m_position.Y = ticks.m_lineEnd.Y + labelSize.Width / 2;
1685                        break;
1686                    default:        // lower
1687                        label.m_position.Y = ticks.m_lineStart.Y - labelSize.Width / 2;
1688                        break;
1689                }
1690                label.m_position.X = ticks.m_lineEnd.X + tickSize.Width + ticks.Padding + label.Padding;
1691                if (label.m_position.Y > ClientSize.Height - 1 - labelSize.Width / 2) {
1692                    label.m_position.Y = ClientSize.Height - 1 - labelSize.Width / 2;
1693                }
1694                #endregion
1695            }
1696        }
1697        private void axisLabel_TopRightBottomLeft(ILRenderProperties p, ILAxis axis) {
1698            ILLabel label = axis.Label;
1699            ILTickCollection ticks = axis.LabeledTicks;
1700            Size tickSize = ticks.Size, labelSize = label.Size;
1701            bool horiz = decideLabelHorizontalOrientation(p, m_camera, axis);
1702            label.Anchor = new PointF(.5f, 0);
1703            if (horiz) {
1704                #region Horizontal
1705                label.Orientation = TextOrientation.Horizontal;
1706                switch (label.Alignment) {
1707                    case LabelAlign.Center:
1708                        label.m_position.X = (ticks.m_lineEnd.X + ticks.m_lineStart.X) / 2;
1709                        break;
1710                    case LabelAlign.Upper:
1711                        label.m_position.X = ticks.m_lineEnd.X + labelSize.Width / 2;
1712                        break;
1713                    default:        // lower
1714                        label.m_position.X = ticks.m_lineStart.X - labelSize.Width / 2;
1715                        break;
1716                }
1717                label.m_position.Y = ticks.m_lineEnd.Y + tickSize.Height + ticks.Padding + label.Padding;
1718                if (label.m_position.X < labelSize.Width / 2)
1719                    label.m_position.X = labelSize.Width / 2;
1720                if (label.m_position.X > ClientSize.Width - labelSize.Width / 2 - 1)
1721                    label.m_position.X = ClientSize.Width - labelSize.Width / 2 - 1;
1722                #endregion
1723            } else {
1724                #region Vertical
1725                label.Orientation = TextOrientation.Vertical;
1726                switch (label.Alignment) {
1727                    case LabelAlign.Center:
1728                        label.m_position.Y = (ticks.m_lineEnd.Y + ticks.m_lineStart.Y) / 2;
1729                        break;
1730                    case LabelAlign.Upper:
1731                        label.m_position.Y = ticks.m_lineEnd.Y - labelSize.Width / 2;
1732                        break;
1733                    default:        // lower
1734                        label.m_position.Y = ticks.m_lineStart.Y + labelSize.Width / 2;
1735                        break;
1736                }
1737                label.m_position.X = ticks.m_lineStart.X + tickSize.Width + ticks.Padding + label.Padding;
1738                if (label.m_position.Y < labelSize.Width / 2) {
1739                    label.m_position.Y = labelSize.Width / 2;
1740                }
1741                if (label.m_position.Y > ClientSize.Height - 1 - labelSize.Width  / 2) {
1742                    label.m_position.Y = ClientSize.Height - 1 - labelSize.Width  / 2;
1743                }
1744                #endregion
1745            }
1746        }
1747        private void axisLabel_TopLeftBottomRight(ILRenderProperties p, ILAxis axis) {
1748            ILLabel label = axis.Label;
1749            ILTickCollection ticks = axis.LabeledTicks;
1750            Size tickSize = ticks.Size, labelSize = label.Size;
1751            bool horiz = decideLabelHorizontalOrientation(p, m_camera, axis);
1752            label.Anchor = new PointF(.5f, 0);
1753            if (horiz) {
1754                #region Horizontal
1755                label.Orientation = TextOrientation.Horizontal;
1756                switch (label.Alignment) {
1757                    case LabelAlign.Center:
1758                        label.m_position.X = (ticks.m_lineEnd.X + ticks.m_lineStart.X) / 2;
1759                        break;
1760                    case LabelAlign.Upper:
1761                        label.m_position.X = ticks.m_lineEnd.X - labelSize.Width / 2;
1762                        break;
1763                    default:        // lower
1764                        label.m_position.X = ticks.m_lineStart.X + labelSize.Width / 2;
1765                        break;
1766                }
1767                label.m_position.Y = ticks.m_lineEnd.Y + tickSize.Height + ticks.Padding + label.Padding;
1768                if (label.m_position.X < labelSize.Width / 2) {
1769                    label.m_position.X = labelSize.Width / 2;
1770                }
1771                #endregion
1772            } else {
1773                #region Vertical
1774                label.Orientation = TextOrientation.Vertical;
1775                switch (label.Alignment) {
1776                    case LabelAlign.Center:
1777                        label.m_position.Y = (ticks.m_lineEnd.Y + ticks.m_lineStart.Y) / 2;
1778                        break;
1779                    case LabelAlign.Upper:
1780                        label.m_position.Y = ticks.m_lineEnd.Y - labelSize.Width / 2;
1781                        break;
1782                    default:        // lower
1783                        label.m_position.Y = ticks.m_lineStart.Y + labelSize.Width / 2;
1784                        break;
1785                }
1786                label.m_position.X = ticks.m_lineStart.X - tickSize.Width - ticks.Padding - label.Padding;
1787                if (label.m_position.Y < labelSize.Width / 2) {
1788                    label.m_position.Y = labelSize.Width / 2;
1789                }
1790                if (label.m_position.Y > ClientSize.Height - 1 - labelSize.Width / 2) {
1791                    label.m_position.Y = ClientSize.Height - 1 - labelSize.Width / 2;
1792                }
1793                #endregion
1794            }
1795        }
1796
1797        // return true if the label needs horizontal orientation
1798        private bool decideLabelHorizontalOrientation(ILRenderProperties p, ILCamera m_camera, ILAxis axis) {
1799            if (p.Reason == RenderReason.RecalcLabels) {
1800                return axis.Label.Orientation == TextOrientation.Horizontal;
1801            }
1802            float offX = axis.LabeledTicks.m_lineStart.X - axis.LabeledTicks.m_lineEnd.X;
1803            float offY = axis.LabeledTicks.m_lineStart.Y - axis.LabeledTicks.m_lineEnd.Y;
1804            return offY * offY < offX * offX; 
1805            //if (axis.Index == 0) {
1806            //    b = (float)((1.0 - m_camera.SinRho * 0.9) * Math.Sin(m_camera.Phi * 2.0f));
1807            //} else if (axis.Index == 1) {
1808
1809            //}
1810            //return (m_camera.SinRho >= LABELS_VERTICAL_MIN_RHO
1811            //    || Math.Sign(Math.Cos(m_camera.Phi * 2.0)) != (axis.Index * 2 - 1));
1812        }
1813        private int GetMargin4OptimalLabelX() {
1814            return 0;
1815        }
1816        private int GetMargin4OptimalLabelY() {
1817            return 0;
1818        }
1819        private Size GetMaxTicLabelSize(Graphics gr) {
1820            Size ret = m_axes.MeasureMaxTickLabelSize(gr);   
1821            // add label sizes
1822            int maxHeight = 0;
1823            if (m_axes[0].Label.Visible && !String.IsNullOrEmpty(m_axes[0].Label.Text)) {
1824                maxHeight = m_axes[0].Label.Size.Height;
1825            }
1826            if (m_axes[1].Label.Visible && !String.IsNullOrEmpty(m_axes[1].Label.Text)) {
1827                if (maxHeight < m_axes[1].Label.Size.Height)
1828                    maxHeight = m_axes[1].Label.Size.Height;
1829            }
1830            if (m_axes[2].Label.Visible && !String.IsNullOrEmpty(m_axes[2].Label.Text)) {
1831                if (maxHeight < m_axes[2].Label.Size.Height)
1832                    maxHeight = m_axes[2].Label.Size.Height;
1833            }
1834            ret = new Size(ret.Width + maxHeight, ret.Height + maxHeight);
1835            return ret;
1836        }
1837
1838        /// <summary>
1839        /// calculate the real pixels of the plot cube rectangle for drawing into
1840        /// </summary>
1841        /// <param name="xSize"></param>
1842        /// <param name="ySize"></param>
1843        private void updatePlotCubeScreenRect(float xSize, float ySize, Size tickLabelMargins) {
1844            switch (PlotBoxScreenSizeMode) {
1845                //case PlotCubeScreenSizeMode.Maximum: // <- will be done in PlotCubeScreenSizeMode.set()
1846                //    m_plotCubeScreenRectF = new RectangleF(0.0f, 0.0f, 1.0f, 1.0f);
1847                //    break;
1848                case PlotBoxScreenSizeMode.Optimal:
1849                case PlotBoxScreenSizeMode.StrictOptimal:
1850                    float saveX, saveY;
1851                    saveX = ((float)tickLabelMargins.Width / ClientSize.Width);
1852                    if (saveX < 0) saveX = 0;
1853                    if (saveX > 1) saveX = 1;
1854                    saveY = ((float)tickLabelMargins.Height / ClientSize.Height);
1855                    if (saveY < 0) saveY = 0;
1856                    if (saveY > 1) saveY = 1;
1857                    m_plotBoxScreenRectF = new RectangleF(saveX, saveY, 1f - (2 * saveX), 1f - (2 * saveY));
1858                    break;
1859                default: // manual: use predefined PlotCubeScreenRectF
1860                    break;
1861            }
1862        }
1863
1864        private void updateLabelPositions(ILRenderProperties p) {
1865            positionZAxisLabel(m_axes[2]);
1866            switch (m_camera.Quadrant) {
1867                case CameraQuadrant.TopRightFront:
1868                    axisLabel_TopLeftBottomRight(p, m_axes[0]);
1869                    // special case: 2D view?
1870                    if (m_camera.SinPhi < 1e-5 && m_camera.SinRho < 1e-5) {
1871                        axisLabelVertical2D(m_axes[1]);
1872                    } else {
1873                        axisLabel_BottomLeftTopRight(p, m_axes[1]);
1874                    }
1875                    break;
1876                case CameraQuadrant.TopRightBack:
1877                    axisLabel_TopRightBottomLeft(p, m_axes[0]);
1878                    axisLabel_TopLeftBottomRight(p, m_axes[1]);
1879                    break;
1880                case CameraQuadrant.TopLeftFront:
1881                    axisLabel_BottomLeftTopRight(p, m_axes[0]);
1882                    axisLabel_BottomRightTopLeft(p, m_axes[1]);
1883                    break;
1884                case CameraQuadrant.TopLeftBack:
1885                    axisLabel_BottomRightTopLeft(p, m_axes[0]);
1886                    axisLabel_TopRightBottomLeft(p, m_axes[1]);
1887                    break;
1888                case CameraQuadrant.BottomLeftFront:
1889                    axisLabel_TopLeftBottomRight(p, m_axes[0]);
1890                    axisLabel_TopRightBottomLeft(p, m_axes[1]);
1891                    break;
1892                case CameraQuadrant.BottomLeftBack:
1893                    axisLabel_TopRightBottomLeft(p, m_axes[0]);
1894                    axisLabel_BottomRightTopLeft(p, m_axes[1]);
1895                    break;
1896                case CameraQuadrant.BottomRightBack:
1897                    axisLabel_BottomRightTopLeft(p, m_axes[0]);
1898                    axisLabel_BottomLeftTopRight(p, m_axes[1]);
1899                    break;
1900                case CameraQuadrant.BottomRightFront:
1901                    axisLabel_BottomLeftTopRight(p, m_axes[0]);
1902                    axisLabel_TopLeftBottomRight(p, m_axes[1]);
1903                    break;
1904                default:
1905                    break;
1906            }
1907        }
1908
1909        private void updateTickLabelLines() {
1910            // determine tick label lines
1911            ILTickCollection ticks = m_axes[2].LabeledTicks;
1912            ticks.m_anchor = GetZTickLabelLine(out ticks.m_lineStart, out ticks.m_lineEnd);
1913            ticks = m_axes[1].LabeledTicks;
1914            ticks.m_anchor = GetYTickLabelLine(out ticks.m_lineStart, out ticks.m_lineEnd);
1915            ticks = m_axes[0].LabeledTicks;
1916            ticks.m_anchor = GetXTickLabelLine(out ticks.m_lineStart, out ticks.m_lineEnd);
1917        }
1918        #endregion
1919
1920        #region factory member
1921
1922        /// <summary>
1923        /// create OpenGL panel
1924        /// </summary>
1925        /// <returns>OpenGL panel</returns>
1926        public static ILPanel Create () {
1927            return Create(GraphicDeviceType.OpenGL);
1928        }
1929        /// <summary>
1930        /// create graphic device specific panel
1931        /// </summary>
1932        /// <param name="type">specify GL type. Supported are: OpenGL (recommended) or Direct3D (alpha state)</param>
1933        /// <returns>GL specific panel</returns>
1934        public static ILPanel Create (GraphicDeviceType type) {
1935            ILPanel ret; Type panelType; Assembly assembly;
1936            string myPath = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
1937            switch (type) {
1938                case GraphicDeviceType.Direct3D:
1939                    //must create DXPanel dynamically ?
1940                    // actually not, because DX is split into individual assembly
1941                    // but under mono it seems the runtime tries to load the d3d part
1942                    // anyway, so we do without a compile time reference.
1943                    assembly = Assembly.LoadFile(Path.Combine(myPath,"ILNumerics.DrawingD3D.dll"));
1944                    panelType = assembly.GetType("ILNumerics.Drawing.Platform.OpenGL.ILDXPanel");
1945                    ret = (ILPanel)panelType.InvokeMember("ILDXPanel",
1946                            BindingFlags.DeclaredOnly | BindingFlags.Public
1947                            | BindingFlags.NonPublic | BindingFlags.Instance
1948                            | BindingFlags.CreateInstance,
1949                            null, null, null);
1950                    return ret;
1951                default:
1952                    // the default is to use OpenGL, which is included into the main assembly (this one)
1953                    assembly = Assembly.GetExecutingAssembly();
1954                    panelType = assembly.GetType("ILNumerics.Drawing.Platform.OpenGL.ILOGLPanel");
1955                    ret = (ILPanel)panelType.InvokeMember("ILOGLPanel",
1956                            BindingFlags.DeclaredOnly | BindingFlags.Public
1957                            | BindingFlags.NonPublic | BindingFlags.Instance
1958                            | BindingFlags.CreateInstance,
1959                            null, null, null);
1960                    return ret;
1961            }
1962        }
1963
1964        /// <summary>
1965        /// Create GL dependend graph factory
1966        /// </summary>
1967        /// <returns>ILGraphFactory,will be used for creating all graphs</returns>
1968        /// <remarks>derived types may return GL dependend factory</remarks>
1969        internal abstract IILCreationFactory GetCreationFactory();
1970        #endregion
1971
1972
1973    }
1974}
Note: See TracBrowser for help on using the repository browser.