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