/// /// This file is part of ILNumerics Community Edition. /// /// ILNumerics Community Edition - high performance computing for applications. /// Copyright (C) 2006 - 2012 Haymo Kutschbach, http://ilnumerics.net /// /// ILNumerics Community Edition is free software: you can redistribute it and/or modify /// it under the terms of the GNU General Public License version 3 as published by /// the Free Software Foundation. /// /// ILNumerics Community Edition is distributed in the hope that it will be useful, /// but WITHOUT ANY WARRANTY; without even the implied warranty of /// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the /// GNU General Public License for more details. /// /// You should have received a copy of the GNU General Public License /// along with ILNumerics Community Edition. See the file License.txt in the root /// of your distribution package. If not, see . /// /// In addition this software uses the following components and/or licenses: /// /// ================================================================================= /// The Open Toolkit Library License /// /// Copyright (c) 2006 - 2009 the Open Toolkit library. /// /// Permission is hereby granted, free of charge, to any person obtaining a copy /// of this software and associated documentation files (the "Software"), to deal /// in the Software without restriction, including without limitation the rights to /// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of /// the Software, and to permit persons to whom the Software is furnished to do /// so, subject to the following conditions: /// /// The above copyright notice and this permission notice shall be included in all /// copies or substantial portions of the Software. /// /// ================================================================================= /// #pragma warning disable 1591 using System; using System.Collections.Generic; using System.Text; using System.Drawing; using ILNumerics.Drawing.Interfaces; using ILNumerics.Exceptions; using ILNumerics.Drawing.Collections; using ILNumerics.Drawing.Labeling; using ILNumerics.Drawing; namespace ILNumerics.Drawing { /// /// Axis object for ILPanel /// public abstract class ILAxis : IDisposable { #region attributes public event EventHandler Changed; protected ILTickCollection m_labeledTicks; protected ICollection m_unLabeledTicks; protected ILLineProperties m_grid; protected ILLineProperties m_nearLines; protected ILLineProperties m_farLines; protected ILClippingData m_clipping; protected ILLabel m_label; protected AxisType m_axisType; protected AxisNames m_axisName; protected bool m_visible = true; protected bool m_invalidated = true; protected ILLayoutData m_layoutData; private ILLabeledTickProvider m_labelProvider; protected ILPanel m_panel; #endregion #region properties /// /// Panel hosting the axis (readonly) /// ILPanel Panel { get { return m_panel; } } /// /// Used to retrieve/specify the delegate computing nice labels for axis /// /// One can replace the default tick provider by a user /// defined labeled tick computation function. Therefore simply set this property to /// your own ILLabeledTickProvider function. /// public ILLabeledTickProvider LabeledTickProvider { get { return m_labelProvider; } set { if (value == null) return; m_labelProvider = value; } } /// /// get properties for far axis lines (opposite label side) or sets it /// public ILLineProperties FarLines { get { return m_farLines; } set { m_farLines = value; OnChange(); } } /// /// get properties for near axis lines (opposite label side) or sets it /// public ILLineProperties NearLines { get { return m_nearLines; } set { m_nearLines = value; OnChange(); } } /// /// label to be displayed next to this axis /// public ILLabel Label { get { return m_label; } set { m_label = value; OnChange(); } } /// /// Switch visibility on/ off /// public bool Visible { get { return m_visible; } set { m_visible = value; OnChange(); } } /// /// axis type /// public AxisType AxisType { get { return m_axisType; } set { m_axisType = value; OnChange(); } } /// /// Gives access to the collection of labeled ticks /// public ILTickCollection LabeledTicks { get { return m_labeledTicks; } } /// /// access to the collection of unlabeled ticks (not used) /// public ICollection UnlabeledTicks { get { return m_unLabeledTicks; } } /// /// access to a specific axis by number /// public int Index { get { return (int)m_axisName; } } /// /// access grid lines properties /// public ILLineProperties Grid { get { return m_grid; } } /// /// access axis limits /// public ILClippingData Limits { get { return m_clipping; } } #endregion #region Event handling /// /// fires a changed event /// protected void OnChange() { Invalidate(); if (Changed != null) { Changed(this,null); } } /// /// occures if the registered clipping data have changed /// /// ILClipping data /// clipping changed event args void m_clipping_Changed(object sender, ClippingChangedEventArgs e) { Invalidate(); } void m_labeledTicks_Changed(object sender, ILAxisChangedEventArgs args) { Invalidate(); } void m_grid_Changed(object sender, EventArgs e) { Invalidate(); } void m_label_Changed(object sender, EventArgs e) { Invalidate(); } #endregion #region constructor /// /// construct ILAxis object. This contructor is not to be called directly. /// /// type of the axis: XAxis,YAxis,ZAxis /// Clipping data to be registered into the axis. /// additional layout data, does currently only contain the camera [depricated] /// panel hosting the scene /// ILAxis objects are created GL-device dependend by use of a device dependend ILPanel instance's /// member ILPanel.CreateAxis(). This acts like a factory pattern. The specific axis derivate will be /// created by the derived ILPanel object (ILDXPanel or ILOGLPanel). public ILAxis (AxisNames name, ILClippingData clippingView, ILLayoutData layoutData,ILPanel panel) { m_panel = panel; m_axisName = name; m_labeledTicks = new ILTickCollection(panel,m_axisName); m_layoutData = layoutData; m_labelProvider = null; m_labeledTicks.Changed += new AxisChangedEventHandler(m_labeledTicks_Changed); m_unLabeledTicks = new List(10); m_grid = new ILLineProperties(); m_grid.Style = LineStyle.Dashed; m_grid.Color = Color.FromArgb(220, 220, 225); m_grid.Width = 1; m_grid.Changed += new EventHandler(m_grid_Changed); m_clipping = clippingView; m_axisType = AxisType.Linear; m_nearLines = new ILLineProperties(); m_nearLines.Color = Color.DarkBlue; m_nearLines.Width = 1; m_nearLines.Antialiasing = true; m_nearLines.Changed +=new EventHandler(m_grid_Changed); m_farLines = new ILLineProperties(); m_farLines.Color = Color.DarkBlue; m_farLines.Width = 1; m_farLines.Antialiasing = true; m_farLines.Changed +=new EventHandler(m_grid_Changed); m_label = new ILLabel(panel); m_label.Changed += new EventHandler(m_label_Changed); m_clipping.Changed += new ILClippingDataChangedEvent(m_clipping_Changed); m_invalidated = true; } #endregion #region abstract interface /// /// this function does the drawing of the axis lines /// /// render properties /// true: draw background only, false: draw foreground only /// This function is called in the general rendering algorithm. I.e. before the surface buffers has been swapped. protected abstract void iDrawAxis(ILRenderProperties p, bool background); /// /// (internal use) do the drawing of axis' label /// /// render properties /// When this function is called, depends on the DrawAfterBufferSwaped setting /// of the current TextRenderer. protected virtual void iDrawLabel(ILRenderProperties p) { if (m_visible) m_label.Draw(p); } /// /// (internal use) draw tick labels /// /// render properties protected virtual void iDrawTickLabels(ILRenderProperties p) { if (m_visible) m_labeledTicks.Draw(p,m_clipping.Min[Index],m_clipping.Max[Index]); } /// /// Do all rendering for the grid of the axis /// protected abstract void drawGrid(); /// /// draw this axis in the back (behind the graphs) /// /// render properties /// This method is used internally. There should be no need to call it directly. internal virtual void RenderState1(ILRenderProperties p) { if (m_invalidated) { Configure(p); p.Canceled = true; } if (!m_labeledTicks.Renderer.DrawAfterBufferSwapped) iDrawTickLabels(p); if (!m_label.Renderer.DrawAfterBufferSwapped) iDrawLabel(p); iDrawAxis(p,true); } /// /// Do rendering of foreground (before the graphs) /// /// render properties public virtual void RenderState2(ILRenderProperties p) { //if (m_invalidated) // Configure(p); iDrawAxis(p,false); } /// /// do rendering after the buffers have been swapped /// /// render properties public virtual void RenderState3(ILRenderProperties p) { if (m_labeledTicks.Renderer.DrawAfterBufferSwapped) iDrawTickLabels(p); if (m_label.Renderer.DrawAfterBufferSwapped) iDrawLabel(p); } /// /// update axis (recalculate number & position of labels in auto mode, recreate vertices) /// /// render properties /// This method is used internally. There should be no need to call it directly. internal virtual void Configure(ILRenderProperties p) { if (m_clipping.Min.IsEmtpy() || m_clipping.Max.IsEmtpy()) return; if (p.PassCount > 0) return; if (m_labeledTicks.Mode == TickMode.Auto) { int tickCount = GetMaxTickCount(p); if (m_labelProvider != null) { string format = String.Format("g{0}",m_labeledTicks.Precision); m_labeledTicks.Replace( m_labelProvider(m_clipping.Min[Index],m_clipping.Max[Index],tickCount)); } else { m_labeledTicks.CreateAuto(m_clipping.Min[Index],m_clipping.Max[Index],tickCount); } } PrepareMeshes(p); PrepareLabels(p); m_invalidated = false; } /// /// recreate vertices /// /// render properties public abstract void PrepareMeshes(ILRenderProperties p); /// /// recreate labels /// /// render properties public virtual void PrepareLabels(ILRenderProperties p) { // prepare textrenderer } /// /// number of ticks optimally fitting on screen /// /// render properties /// optimal number of ticks for this axis internal int GetMaxTickCount(ILRenderProperties p) { //System.Diagnostics.Debug.Assert(m_labeledTicks.Mode == TickMode.Auto); SizeF rect = m_labeledTicks.Size; Point s = new Point(),e = new Point(); s = m_labeledTicks.m_lineStart; e = m_labeledTicks.m_lineEnd; s.X = (int)(Math.Floor((float)Math.Abs(e.X - s.X) / (float)(rect.Width + m_labeledTicks.Padding))); s.Y = (int)(Math.Floor((float) Math.Abs(e.Y - s.Y) / (float)(rect.Height + m_labeledTicks.Padding))); return (int)Math.Floor(Math.Max((double)s.X,s.Y) + 1); } /// /// determine number of primitives (lines) to be drawn for this axis /// /// number of primitives internal int countPrimitves() { return (m_visible)? (m_labeledTicks.Count + 1 + m_unLabeledTicks.Count) * 4 : 4; } /// /// Invalidate this axis, causes recreation on next render /// public virtual void Invalidate() { m_invalidated = true; } /// /// (internal use) dispose off this axis' elements /// public virtual void Dispose() { if (m_labeledTicks != null) m_labeledTicks.Dispose(); if (m_label != null) { m_label.Dispose(); } } #endregion #region private helper #endregion } }