This revision is NPlot-Gtk 0.9.9.2 and is the Gtk wrapper of NPlot 0.9.9.2.

svn path=/trunk/nplot-gtk/; revision=65798
This commit is contained in:
Carlos Ble 2006-09-21 21:56:05 +00:00
Коммит c209bfbce5
104 изменённых файлов: 29556 добавлений и 0 удалений

4
ChangeLog Normal file
Просмотреть файл

@ -0,0 +1,4 @@
2006-09-21 Carlos Ble <carlosble@shidix.com>
* updating the whole software to NPlot 0.9.9.2

9
Makefile Normal file
Просмотреть файл

@ -0,0 +1,9 @@
all:
(cd lib; make all)
install:
@if test x$$prefix = x; then \
echo -e "\nError, usage is:\n\n\t make install prefix=INSTALLPREFIX\n"; \
exit 1; \
fi;
(cd lib; make install prefix=$$prefix)

Двоичные данные
NPlot.dll Normal file

Двоичный файл не отображается.

18
README Normal file
Просмотреть файл

@ -0,0 +1,18 @@
The first version of NPlot-Gtk was made by Miguel de Icaza, and was
a wrapper of NPlot 0.9.8.5.
Now the wrapper of version 0.9.9.2 has just an NPlot upgrade and
a few hacks over the work of Miguel (Carlos)
------------------------
This version of NPlot has been extended to support Gtk# on Linux.
The version is based on NPlot 0.9.9.2
To build, type `make'
The Gtk# demo is in lib/mf.exe and lib/test.exe
Notice that you must include in your distirbution not only the .dll
files, but also the .config files.

Двоичные данные
lib/.Gtk.PlotSurface2D.cs.swp Normal file

Двоичный файл не отображается.

767
lib/AdapterUtils.cs Normal file
Просмотреть файл

@ -0,0 +1,767 @@
/*
NPlot - A charting library for .NET
AdapterUtils.cs
Copyright (C) 2003-2005
Matt Howlett
Redistribution and use of NPlot or parts there-of in source and
binary forms, with or without modification, are permitted provided
that the following conditions are met:
1. Re-distributions in source form must retain at the head of each
source file the above copyright notice, this list of conditions
and the following disclaimer.
2. Any product ("the product") that makes use NPlot or parts
there-of must either:
(a) allow any user of the product to obtain a complete machine-
readable copy of the corresponding source code for the
product and the version of NPlot used for a charge no more
than your cost of physically performing source distribution,
on a medium customarily used for software interchange, or:
(b) reproduce the following text in the documentation, about
box or other materials intended to be read by human users
of the product that is provided to every human user of the
product:
"This product includes software developed as
part of the NPlot library project available
from: http://www.nplot.com/"
The words "This product" may optionally be replace with
the actual name of the product.
------------------------------------------------------------------------
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
using System;
using System.Collections;
using System.Data;
namespace NPlot
{
/// <summary>
/// Encapsulates functionality relating to exposing data in various
/// different data structures in a consistent way.
/// </summary>
/// <remarks>It would be more efficient to have iterator style access
/// to the data, rather than index based, and Count.</remarks>
public class AdapterUtils
{
#region AxisSuggesters
/// <summary>
/// Interface for classes that can suggest an axis for data they contain.
/// </summary>
public interface IAxisSuggester
{
/// <summary>
/// Calculates a suggested axis for the data contained by the implementing class.
/// </summary>
/// <returns>the suggested axis</returns>
Axis Get();
}
/// <summary>
/// Implements functionality for suggesting an axis suitable for charting
/// data in multiple columns of a DataRowCollection.
/// </summary>
/// <remarks>This is currently not used.</remarks>
public class AxisSuggester_MultiColumns : IAxisSuggester
{
DataRowCollection rows_;
string abscissaName_;
/// <summary>
/// Constructor
/// </summary>
/// <param name="rows">The DataRowCollection containing the data.</param>
/// <param name="abscissaName">the column with this name is not considered</param>
public AxisSuggester_MultiColumns(DataRowCollection rows, string abscissaName)
{
rows_ = rows;
abscissaName_ = abscissaName;
}
/// <summary>
/// Calculates a suggested axis for the DataRowCollection data.
/// </summary>
/// <returns>the suggested axis</returns>
public Axis Get()
{
double t_min = double.MaxValue;
double t_max = double.MinValue;
System.Collections.IEnumerator en = rows_[0].Table.Columns.GetEnumerator();
while (en.MoveNext())
{
string colName = ((DataColumn)en.Current).Caption;
if (colName == abscissaName_)
{
continue;
}
double min;
double max;
if (Utils.RowArrayMinMax(rows_, out min, out max, colName))
{
if (min < t_min)
{
t_min = min;
}
if (max > t_max)
{
t_max = max;
}
}
}
return new LinearAxis(t_min, t_max);
}
}
/// <summary>
/// This class gets an axis suitable for plotting the data contained in an IList.
/// </summary>
public class AxisSuggester_IList : IAxisSuggester
{
private IList data_;
/// <summary>
/// Constructor.
/// </summary>
/// <param name="data">the data we want to find a suitable axis for.</param>
public AxisSuggester_IList(IList data)
{
data_ = data;
}
/// <summary>
/// Calculates a suggested axis for the IList data.
/// </summary>
/// <returns>the suggested axis</returns>
public Axis Get()
{
double min;
double max;
if (Utils.ArrayMinMax(data_, out min, out max))
{
if (data_[0] is DateTime)
{
return new DateTimeAxis(min, max);
}
else
{
return new LinearAxis(min, max);
}
// perhaps return LogAxis here if range large enough
// + other constraints?
}
return new LinearAxis(0.0, 1.0);
}
}
/// <summary>
/// This class is responsible for supplying a default axis via the IAxisSuggester interface.
/// </summary>
public class AxisSuggester_Null : IAxisSuggester
{
/// <summary>
/// Returns a default axis.
/// </summary>
/// <returns>the suggested axis</returns>
public Axis Get()
{
return new LinearAxis(0.0, 1.0);
}
}
/// <summary>
/// This class gets an axis corresponding to a StartStep object. The data on
/// the orthogonal axis is of course also needed to calculate this.
/// </summary>
public class AxisSuggester_StartStep : IAxisSuggester
{
StartStep abscissaData_;
IList ordinateData_;
/// <summary>
/// Constructor
/// </summary>
/// <param name="axisOfInterest">StartStep object corresponding to axis of interest</param>
/// <param name="otherAxisData">data of other axis (needed to get count value)</param>
public AxisSuggester_StartStep(StartStep axisOfInterest, IList otherAxisData)
{
ordinateData_ = otherAxisData;
abscissaData_ = axisOfInterest;
}
/// <summary>
/// Calculates a suggested axis given the data specified in the constructor.
/// </summary>
/// <returns>the suggested axis</returns>
public Axis Get()
{
return new LinearAxis(
abscissaData_.Start,
abscissaData_.Start + (double)(ordinateData_.Count - 1) * abscissaData_.Step);
}
}
/// <summary>
/// Provides default axis if only data corresponding to orthogonal axis is provided.
/// </summary>
public class AxisSuggester_Auto : IAxisSuggester
{
IList ordinateData_;
/// <summary>
/// Constructor
/// </summary>
/// <param name="ordinateData">Data corresponding to orthogonal axis.</param>
public AxisSuggester_Auto(IList ordinateData)
{
ordinateData_ = ordinateData;
}
/// <summary>
/// Calculates a suggested axis given the data specified in the constructor.
/// </summary>
/// <returns>the suggested axis</returns>
public Axis Get()
{
return new LinearAxis(0, ordinateData_.Count - 1);
}
}
/// <summary>
/// Provides default axis if only data corresponding to orthogonal axis is provided.
/// </summary>
public class AxisSuggester_RowAuto : IAxisSuggester
{
DataRowCollection ordinateData_;
/// <summary>
/// Construbtor
/// </summary>
/// <param name="ordinateData">Data corresponding to orthogonal axis.</param>
public AxisSuggester_RowAuto(DataRowCollection ordinateData)
{
ordinateData_ = ordinateData;
}
/// <summary>
/// Calculates a suggested axis given the data specified in the constructor.
/// </summary>
/// <returns>the suggested axis</returns>
public Axis Get()
{
return new LinearAxis(0, ordinateData_.Count - 1);
}
}
/// <summary>
/// Provides axis for data in a given column of a DataRowCollection.
/// </summary>
public class AxisSuggester_Rows : IAxisSuggester
{
DataRowCollection rows_;
string columnName_;
/// <summary>
/// Constructor
/// </summary>
/// <param name="rows">DataRowCollection containing the data to suggest axis for.</param>
/// <param name="columnName">the column to get data.</param>
public AxisSuggester_Rows(DataRowCollection rows, string columnName)
{
rows_ = rows;
columnName_ = columnName;
}
/// <summary>
/// Calculates a suggested axis given the data specified in the constructor.
/// </summary>
/// <returns>the suggested axis</returns>
public Axis Get()
{
double min;
double max;
if (Utils.RowArrayMinMax(rows_, out min, out max, columnName_))
{
if ((rows_[0])[columnName_] is DateTime)
{
return new DateTimeAxis(min, max);
}
else
{
return new LinearAxis(min, max);
}
}
return new LinearAxis(0.0, 1.0);
}
}
/// <summary>
/// Provides axis suggestion for data in a particular column of a DataView.
/// </summary>
public class AxisSuggester_DataView : IAxisSuggester
{
DataView data_;
string columnName_;
/// <summary>
/// Constructor
/// </summary>
/// <param name="data">DataView that contains data to suggest axis for</param>
/// <param name="columnName">the column of interest in the DataView</param>
public AxisSuggester_DataView(DataView data, string columnName)
{
data_ = data;
columnName_ = columnName;
}
/// <summary>
/// Calculates a suggested axis given the data specified in the constructor.
/// </summary>
/// <returns>the suggested axis</returns>
public Axis Get()
{
double min;
double max;
if (Utils.DataViewArrayMinMax(data_, out min, out max, columnName_))
{
if ((data_[0])[columnName_] is DateTime)
{
return new DateTimeAxis(min, max);
}
else
{
return new LinearAxis(min, max);
}
}
return new LinearAxis(0.0, 1.0);
}
}
#endregion
#region Counters
/// <summary>
/// Interface that enables a dataholding class to report how many data items it holds.
/// </summary>
public interface ICounter
{
/// <summary>
/// Number of data items in container.
/// </summary>
/// <value>Number of data items in container.</value>
int Count { get; }
}
/// <summary>
/// Class that provides the number of items in an IList via the ICounter interface.
/// </summary>
public class Counter_IList : ICounter
{
private IList data_;
/// <summary>
/// Constructor
/// </summary>
/// <param name="data">the IList data to provide count of</param>
public Counter_IList(IList data)
{
data_ = data;
}
/// <summary>
/// Number of data items in container.
/// </summary>
/// <value>Number of data items in container.</value>
public int Count
{
get
{
return data_.Count;
}
}
}
/// <summary>
/// Class that returns 0 via the ICounter interface.
/// </summary>
public class Counter_Null : ICounter
{
/// <summary>
/// Number of data items in container.
/// </summary>
/// <value>Number of data items in container.</value>
public int Count
{
get
{
return 0;
}
}
}
/// <summary>
/// Class that provides the number of items in a DataRowCollection via the ICounter interface.
/// </summary>
public class Counter_Rows : ICounter
{
DataRowCollection rows_;
/// <summary>
/// Constructor
/// </summary>
/// <param name="rows">the DataRowCollection data to provide count of number of rows of.</param>
public Counter_Rows(DataRowCollection rows)
{
rows_ = rows;
}
/// <summary>
/// Number of data items in container.
/// </summary>
/// <value>Number of data items in container.</value>
public int Count
{
get
{
return rows_.Count;
}
}
}
/// <summary>
/// Class that provides the number of items in a DataView via the ICounter interface.
/// </summary>
public class Counter_DataView : ICounter
{
DataView dataView_;
/// <summary>
/// Constructor
/// </summary>
/// <param name="dataView">the DataBiew data to provide count of number of rows of.</param>
public Counter_DataView(DataView dataView)
{
dataView_ = dataView;
}
/// <summary>
/// Number of data items in container.
/// </summary>
/// <value>Number of data items in container.</value>
public int Count
{
get
{
return dataView_.Count;
}
}
}
#endregion
#region DataGetters
/// <summary>
/// Interface for data holding classes that allows users to get the ith value.
/// </summary>
/// <remarks>
/// TODO: should change this to GetNext() and Reset() for more generality.
/// </remarks>
public interface IDataGetter
{
/// <summary>
/// Gets the ith data value.
/// </summary>
/// <param name="i">sequence number of data to get.</param>
/// <returns>ith data value.</returns>
double Get(int i);
}
/// <summary>
/// Provides data in an IList via the IDataGetter interface.
/// </summary>
public class DataGetter_IList : IDataGetter
{
private IList data_;
/// <summary>
/// Constructor
/// </summary>
/// <param name="data">IList that contains the data</param>
public DataGetter_IList(IList data)
{
data_ = data;
}
/// <summary>
/// Gets the ith data value.
/// </summary>
/// <param name="i">sequence number of data to get.</param>
/// <returns>ith data value.</returns>
public double Get(int i)
{
return Utils.ToDouble(data_[i]);
}
}
/// <summary>
/// Provides data in an array of doubles via the IDataGetter interface.
/// </summary>
/// <remarks>
/// A speed-up version of DataDetter_IList; no boxing/unboxing overhead.
/// </remarks>
public class DataGetter_DoublesArray : IDataGetter
{
private double[] data_;
/// <summary>
/// Constructor
/// </summary>
/// <param name="data">array of doubles that contains the data</param>
public DataGetter_DoublesArray(double[] data)
{
data_ = data;
}
/// <summary>
/// Gets the ith data value.
/// </summary>
/// <param name="i">sequence number of data to get.</param>
/// <returns>ith data value.</returns>
public double Get(int i)
{
return data_[i];
}
}
/// <summary>
/// Provides no data.
/// </summary>
public class DataGetter_Null : IDataGetter
{
/// <summary>
/// Gets the ith data value.
/// </summary>
/// <param name="i">sequence number of data to get.</param>
/// <returns>ith data value.</returns>
public double Get(int i)
{
throw new NPlotException( "No Data!" );
}
}
/// <summary>
/// Provides data points from a StartStep object via the IDataGetter interface.
/// </summary>
public class DataGetter_StartStep : IDataGetter
{
StartStep data_;
/// <summary>
/// Constructor
/// </summary>
/// <param name="data">StartStep to derive data from.</param>
public DataGetter_StartStep(StartStep data)
{
data_ = data;
}
/// <summary>
/// Gets the ith data value.
/// </summary>
/// <param name="i">sequence number of data to get.</param>
/// <returns>ith data value.</returns>
public double Get(int i)
{
return data_.Start + (double)(i) * data_.Step;
}
}
/// <summary>
/// Provides the natural numbers (and 0) via the IDataGetter interface.
/// </summary>
public class DataGetter_Count : IDataGetter
{
/// <summary>
/// Gets the ith data value.
/// </summary>
/// <param name="i">sequence number of data to get.</param>
/// <returns>ith data value.</returns>
public double Get(int i)
{
return (double)i;
}
}
/// <summary>
/// Provides data in a DataRowCollection via the IDataGetter interface.
/// </summary>
public class DataGetter_Rows : IDataGetter
{
private DataRowCollection rows_;
private string columnName_;
/// <summary>
/// Constructor
/// </summary>
/// <param name="rows">DataRowCollection to get data from</param>
/// <param name="columnName">Get data in this column</param>
public DataGetter_Rows(DataRowCollection rows, string columnName)
{
rows_ = rows;
columnName_ = columnName;
}
/// <summary>
/// Gets the ith data value.
/// </summary>
/// <param name="i">sequence number of data to get.</param>
/// <returns>ith data value.</returns>
public double Get(int i)
{
return Utils.ToDouble((rows_[i])[columnName_]);
}
}
/// <summary>
/// Provides data in a DataView via the IDataGetter interface.
/// </summary>
public class DataGetter_DataView : IDataGetter
{
private DataView data_;
private string columnName_;
/// <summary>
/// Constructor
/// </summary>
/// <param name="data">DataView to get data from.</param>
/// <param name="columnName">Get data in this column</param>
public DataGetter_DataView(DataView data, string columnName)
{
data_ = data;
columnName_ = columnName;
}
/// <summary>
/// Gets the ith data value.
/// </summary>
/// <param name="i">sequence number of data to get.</param>
/// <returns>ith data value.</returns>
public double Get(int i)
{
return Utils.ToDouble((data_[i])[columnName_]);
}
}
/// <summary>
/// Gets data
/// </summary>
/// <remarks>Note: Does not implement IDataGetter... Currently this class is not used.</remarks>
public class DataGetter_MultiRows
{
DataRowCollection rows_;
string abscissaName_;
int abscissaColumnNumber_;
/// <summary>
/// Constructor
/// </summary>
/// <param name="rows">DataRowCollection to get data from.</param>
/// <param name="omitThisColumn">don't get data from this column</param>
public DataGetter_MultiRows(DataRowCollection rows, string omitThisColumn )
{
rows_ = rows;
abscissaName_ = omitThisColumn;
abscissaColumnNumber_ = rows_[0].Table.Columns.IndexOf( omitThisColumn );
if (abscissaColumnNumber_ < 0)
throw new NPlotException( "invalid column name" );
}
/// <summary>
/// Number of data points
/// </summary>
public int Count
{
get
{
return rows_[0].Table.Columns.Count-1;
}
}
/// <summary>
/// Gets data at a given index, in the given series (column number).
/// </summary>
/// <param name="index">index in the series to get data for</param>
/// <param name="seriesIndex">series number (column number) to get data for.</param>
/// <returns>the required data point.</returns>
public double PointAt( int index, int seriesIndex )
{
if (seriesIndex < abscissaColumnNumber_)
return Utils.ToDouble( rows_[index][seriesIndex] );
else
return Utils.ToDouble( rows_[index][seriesIndex+1] );
}
}
#endregion
}
}

455
lib/ArrowItem.cs Normal file
Просмотреть файл

@ -0,0 +1,455 @@
/*
NPlot - A charting library for .NET
ArrowItem.cs
Copyright (C) 2003
Matt Howlett
Redistribution and use of NPlot or parts there-of in source and
binary forms, with or without modification, are permitted provided
that the following conditions are met:
1. Re-distributions in source form must retain at the head of each
source file the above copyright notice, this list of conditions
and the following disclaimer.
2. Any product ("the product") that makes use NPlot or parts
there-of must either:
(a) allow any user of the product to obtain a complete machine-
readable copy of the corresponding source code for the
product and the version of NPlot used for a charge no more
than your cost of physically performing source distribution,
on a medium customarily used for software interchange, or:
(b) reproduce the following text in the documentation, about
box or other materials intended to be read by human users
of the product that is provided to every human user of the
product:
"This product includes software developed as
part of the NPlot library project available
from: http://www.nplot.com/"
The words "This product" may optionally be replace with
the actual name of the product.
------------------------------------------------------------------------
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
using System;
using System.Drawing;
namespace NPlot
{
/// <summary>
/// An Arrow IDrawable, with a text label that is automatically
/// nicely positioned at the non-pointy end of the arrow. Future
/// feature idea: have constructor that takes a dataset, and have
/// the arrow know how to automatically set it's angle to avoid
/// the data.
/// </summary>
public class ArrowItem : IDrawable
{
private void Init()
{
FontFamily fontFamily = new FontFamily("Arial");
font_ = new Font(fontFamily, 10, FontStyle.Regular, GraphicsUnit.Pixel);
}
/// <summary>
/// Default constructor :
/// text = ""
/// angle = 45 degrees anticlockwise from horizontal.
/// </summary>
/// <param name="position">The position the arrow points to.</param>
public ArrowItem( PointD position )
{
to_ = position;
Init();
}
/// <summary>
/// Constructor
/// </summary>
/// <param name="position">The position the arrow points to.</param>
/// <param name="angle">angle of arrow with respect to x axis.</param>
public ArrowItem( PointD position, double angle )
{
to_ = position;
angle_ = -angle;
Init();
}
/// <summary>
/// Constructor
/// </summary>
/// <param name="position">The position the arrow points to.</param>
/// <param name="angle">angle of arrow with respect to x axis.</param>
/// <param name="text">The text associated with the arrow.</param>
public ArrowItem( PointD position, double angle, string text )
{
to_ = position;
angle_ = -angle;
text_ = text;
Init();
}
/// <summary>
/// Text associated with the arrow.
/// </summary>
public string Text
{
get
{
return text_;
}
set
{
text_ = value;
}
}
private string text_ = "";
/// <summary>
/// Angle of arrow anti-clockwise to right horizontal in degrees.
/// </summary>
/// <remarks>The code relating to this property in the Draw method is
/// a bit weird. Internally, all rotations are clockwise [this is by
/// accient, I wasn't concentrating when I was doing it and was half
/// done before I realised]. The simplest way to make angle represent
/// anti-clockwise rotation (as it is normal to do) is to make the
/// get and set methods negate the provided value.</remarks>
public double Angle
{
get
{
return -angle_;
}
set
{
angle_ = -value;
}
}
private double angle_ = -45.0;
/// <summary>
/// Physical length of the arrow.
/// </summary>
public float PhysicalLength
{
get
{
return physicalLength_;
}
set
{
physicalLength_ = value;
}
}
private float physicalLength_ = 40.0f;
/// <summary>
/// The point the arrow points to.
/// </summary>
public PointD To
{
get
{
return to_;
}
set
{
to_ = value;
}
}
private PointD to_;
/// <summary>
/// Size of the arrow head sides in pixels.
/// </summary>
public float HeadSize
{
get
{
return headSize_;
}
set
{
headSize_ = value;
}
}
private float headSize_ = 10.0f;
/// <summary>
/// angle between sides of arrow head in degrees
/// </summary>
public float HeadAngle
{
get
{
return headAngle_;
}
set
{
headAngle_ = value;
}
}
private float headAngle_ = 40.0f;
/// <summary>
/// Draws the arrow on a plot surface.
/// </summary>
/// <param name="g">graphics surface on which to draw</param>
/// <param name="xAxis">The X-Axis to draw against.</param>
/// <param name="yAxis">The Y-Axis to draw against.</param>
public void Draw( System.Drawing.Graphics g, PhysicalAxis xAxis, PhysicalAxis yAxis )
{
if (this.To.X > xAxis.Axis.WorldMax || this.To.X < xAxis.Axis.WorldMin)
return;
if (this.To.Y > yAxis.Axis.WorldMax || this.To.Y < yAxis.Axis.WorldMin)
return;
double angle = this.angle_;
if (this.angle_ < 0.0)
{
int mul = -(int)(this.angle_ / 360.0) + 2;
angle = angle_ + 360.0 * (double)mul;
}
double normAngle = (double)angle % 360.0; // angle in range 0 -> 360.
Point toPoint = new Point(
(int)xAxis.WorldToPhysical( to_.X, true ).X,
(int)yAxis.WorldToPhysical( to_.Y, true ).Y );
float xDir = (float)Math.Cos( normAngle * 2.0 * Math.PI / 360.0 );
float yDir = (float)Math.Sin( normAngle * 2.0 * Math.PI / 360.0 );
toPoint.X += (int)(xDir*headOffset_);
toPoint.Y += (int)(yDir*headOffset_);
float xOff = physicalLength_ * xDir;
float yOff = physicalLength_ * yDir;
Point fromPoint = new Point(
(int)(toPoint.X + xOff),
(int)(toPoint.Y + yOff) );
g.DrawLine( pen_, toPoint, fromPoint );
Point[] head = new Point[3];
head[0] = toPoint;
xOff = headSize_ * (float)Math.Cos( (normAngle-headAngle_/2.0f) * 2.0 * Math.PI / 360.0 );
yOff = headSize_ * (float)Math.Sin( (normAngle-headAngle_/2.0f) * 2.0 * Math.PI / 360.0 );
head[1] = new Point(
(int)(toPoint.X + xOff),
(int)(toPoint.Y + yOff) );
float xOff2 = headSize_ * (float)Math.Cos( (normAngle+headAngle_/2.0f) * 2.0 * Math.PI / 360.0 );
float yOff2 = headSize_ * (float)Math.Sin( (normAngle+headAngle_/2.0f) * 2.0 * Math.PI / 360.0 );
head[2] = new Point(
(int)(toPoint.X + xOff2),
(int)(toPoint.Y + yOff2) );
g.FillPolygon( arrowBrush_, head );
SizeF textSize = g.MeasureString( text_, font_ );
SizeF halfSize = new SizeF( textSize.Width / 2.0f, textSize.Height / 2.0f );
float quadrantSlideLength = halfSize.Width + halfSize.Height;
float quadrantF = (float)normAngle / 90.0f; // integer part gives quadrant.
int quadrant = (int)quadrantF; // quadrant in.
float prop = quadrantF - (float)quadrant; // proportion of way through this qadrant.
float dist = prop * quadrantSlideLength; // distance along quarter of bounds rectangle.
// now find the offset from the middle of the text box that the
// rear end of the arrow should end at (reverse this to get position
// of text box with respect to rear end of arrow).
//
// There is almost certainly an elgant way of doing this involving
// trig functions to get all the signs right, but I'm about ready to
// drop off to sleep at the moment, so this blatent method will have
// to do.
PointF offsetFromMiddle = new PointF( 0.0f, 0.0f );
switch (quadrant)
{
case 0:
if (dist > halfSize.Height)
{
dist -= halfSize.Height;
offsetFromMiddle = new PointF( -halfSize.Width + dist, halfSize.Height );
}
else
{
offsetFromMiddle = new PointF( -halfSize.Width, - dist );
}
break;
case 1:
if (dist > halfSize.Width)
{
dist -= halfSize.Width;
offsetFromMiddle = new PointF( halfSize.Width, halfSize.Height - dist );
}
else
{
offsetFromMiddle = new PointF( dist, halfSize.Height );
}
break;
case 2:
if (dist > halfSize.Height)
{
dist -= halfSize.Height;
offsetFromMiddle = new PointF( halfSize.Width - dist, -halfSize.Height );
}
else
{
offsetFromMiddle = new PointF( halfSize.Width, -dist );
}
break;
case 3:
if (dist > halfSize.Width)
{
dist -= halfSize.Width;
offsetFromMiddle = new PointF( -halfSize.Width, -halfSize.Height + dist );
}
else
{
offsetFromMiddle = new PointF( -dist, -halfSize.Height );
}
break;
default:
throw new NPlotException( "Programmer error." );
}
g.DrawString(
text_, font_, textBrush_,
(int)(fromPoint.X - halfSize.Width - offsetFromMiddle.X),
(int)(fromPoint.Y - halfSize.Height + offsetFromMiddle.Y) );
}
/// <summary>
/// The brush used to draw the text associated with the arrow.
/// </summary>
public Brush TextBrush
{
get
{
return textBrush_;
}
set
{
textBrush_ = value;
}
}
/// <summary>
/// Set the text to be drawn with a solid brush of this color.
/// </summary>
public Color TextColor
{
set
{
textBrush_ = new SolidBrush( value );
}
}
/// <summary>
/// The color of the pen used to draw the arrow.
/// </summary>
public Color ArrowColor
{
get
{
return pen_.Color;
}
set
{
pen_.Color = value;
arrowBrush_ = new SolidBrush( value );
}
}
/// <summary>
/// The font used to draw the text associated with the arrow.
/// </summary>
public Font TextFont
{
get
{
return this.font_;
}
set
{
this.font_ = value;
}
}
/// <summary>
/// Offset the whole arrow back in the arrow direction this many pixels from the point it's pointing to.
/// </summary>
public int HeadOffset
{
get
{
return headOffset_;
}
set
{
headOffset_ = value;
}
}
private int headOffset_ = 2;
private Brush arrowBrush_ = new SolidBrush( Color.Black );
private Brush textBrush_ = new SolidBrush( Color.Black );
private Pen pen_ = new Pen( Color.Black );
private Font font_;
}
}

68
lib/AssemblyInfo.cs Normal file
Просмотреть файл

@ -0,0 +1,68 @@
/*
NPlot - A charting library for .NET
AssemblyInfo.cs
Copyright (C) 2003
Matt Howlett
Redistribution and use of NPlot or parts there-of in source and
binary forms, with or without modification, are permitted provided
that the following conditions are met:
1. Re-distributions in source form must retain at the head of each
source file the above copyright notice, this list of conditions
and the following disclaimer.
2. Any product ("the product") that makes use NPlot or parts
there-of must either:
(a) allow any user of the product to obtain a complete machine-
readable copy of the corresponding source code for the
product and the version of NPlot used for a charge no more
than your cost of physically performing source distribution,
on a medium customarily used for software interchange, or:
(b) reproduce the following text in the documentation, about
box or other materials intended to be read by human users
of the product that is provided to every human user of the
product:
"This product includes software developed as
part of the NPlot library project available
from: http://www.nplot.com/"
The words "This product" may optionally be replace with
the actual name of the product.
------------------------------------------------------------------------
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
using System;
using System.Reflection;
using System.Runtime.CompilerServices;
[assembly: AssemblyTitle("NPlot")]
[assembly: AssemblyDescription("NPlot Charting Library")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("netcontrols")]
[assembly: AssemblyProduct("")]
[assembly: AssemblyCopyright("")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
[assembly: AssemblyVersion("0.9.9.2")]
[assembly: CLSCompliant(true)]
[assembly: AssemblyKeyFile("StrongName.snk")]

519
lib/AxesConstraint.cs Normal file
Просмотреть файл

@ -0,0 +1,519 @@
/*
NPlot - A charting library for .NET
AxesConstraint.cs
Copyright (C) 2003
Matt Howlett
Redistribution and use of NPlot or parts there-of in source and
binary forms, with or without modification, are permitted provided
that the following conditions are met:
1. Re-distributions in source form must retain at the head of each
source file the above copyright notice, this list of conditions
and the following disclaimer.
2. Any product ("the product") that makes use NPlot or parts
there-of must either:
(a) allow any user of the product to obtain a complete machine-
readable copy of the corresponding source code for the
product and the version of NPlot used for a charge no more
than your cost of physically performing source distribution,
on a medium customarily used for software interchange, or:
(b) reproduce the following text in the documentation, about
box or other materials intended to be read by human users
of the product that is provided to every human user of the
product:
"This product includes software developed as
part of the NPlot library project available
from: http://www.nplot.com/"
The words "This product" may optionally be replace with
the actual name of the product.
------------------------------------------------------------------------
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
using System;
using System.Drawing;
using System.Drawing.Drawing2D;
namespace NPlot
{
/// <summary>
/// Classes derived from this abstract base class define and can apply
/// some form of constraint to the positioning and length of one or more
/// of the four axes of a PlotSurface2D.
/// </summary>
public abstract class AxesConstraint
{
/// <summary>
/// Defines an AxisConstraint that forces the world length corresponding
/// to one pixel on the bottom x-axis to be a certain value.
///
/// TODO: Allow the pixel world length to be set for the top axis.
/// </summary>
public class XPixelWorldLength : AxesConstraint
{
private double pWorldLength_ = 0.0f;
private object holdFixedY_ = null;
/// <summary>
/// Constructor, which defines the world pixel length only. Both
/// y-axes will be moved by equal amounts in order to force this
/// constraint.
/// </summary>
/// <param name="p">The world pixel length</param>
public XPixelWorldLength( double p )
{
this.pWorldLength_ = p;
}
/// <summary>
/// Constructor, which defines the world pixel length together with
/// the y-axis that should be held constant when forcing this
/// constraint [the other y-axis only will be moved].
/// </summary>
/// <param name="p">The world pixel length</param>
/// <param name="holdFixedY">The position of this y-axis will be
/// held constant. The other y-axis will be moved in order to
/// force the constraint.</param>
public XPixelWorldLength( double p, PlotSurface2D.YAxisPosition holdFixedY )
{
this.pWorldLength_ = p;
this.holdFixedY_ = holdFixedY;
}
/// <summary>
/// Applies the constraint to the axes.
/// </summary>
/// <param name="pXAxis1">The bottom x-axis.</param>
/// <param name="pYAxis1">The left y-axis.</param>
/// <param name="pXAxis2">The top x-axis.</param>
/// <param name="pYAxis2">The right y-axis.</param>
public override void ApplyConstraint(
PhysicalAxis pXAxis1, PhysicalAxis pYAxis1,
PhysicalAxis pXAxis2, PhysicalAxis pYAxis2 )
{
int desiredLength = (int)(pXAxis1.Axis.WorldLength / (double)this.pWorldLength_);
int currentLength = pXAxis1.PhysicalLength;
int delta = currentLength - desiredLength;
int changeLeft = delta / 2;
int changeRight = delta / 2;
if (this.holdFixedY_ != null)
{
if ( (PlotSurface2D.YAxisPosition)this.holdFixedY_ == PlotSurface2D.YAxisPosition.Left )
{
changeLeft = 0;
changeRight = delta;
}
else
{
changeLeft = delta;
changeRight = 0;
}
}
pXAxis1.PhysicalMin = new Point( pXAxis1.PhysicalMin.X+changeLeft, pXAxis1.PhysicalMin.Y );
pXAxis1.PhysicalMax = new Point( pXAxis1.PhysicalMax.X-changeRight, pXAxis1.PhysicalMax.Y );
pXAxis2.PhysicalMin = new Point( pXAxis2.PhysicalMin.X+changeLeft, pXAxis2.PhysicalMin.Y );
pXAxis2.PhysicalMax = new Point( pXAxis2.PhysicalMax.X-changeRight, pXAxis2.PhysicalMax.Y );
pYAxis1.PhysicalMin = new Point( pYAxis1.PhysicalMin.X+changeLeft, pYAxis1.PhysicalMin.Y );
pYAxis1.PhysicalMax = new Point( pYAxis1.PhysicalMax.X+changeLeft, pYAxis1.PhysicalMax.Y );
pYAxis2.PhysicalMin = new Point( pYAxis2.PhysicalMin.X-changeRight, pYAxis2.PhysicalMin.Y );
pYAxis2.PhysicalMax = new Point( pYAxis2.PhysicalMax.X-changeRight, pYAxis2.PhysicalMax.Y );
}
}
/// <summary>
/// Defines an AxisConstraint that forces the world length corresponding
/// to one pixel on the left y-axis to be a certain value.
///
/// TODO: Allow the pixel world length to be set for the right axis.
/// </summary>
public class YPixelWorldLength : AxesConstraint
{
private double pWorldLength_ = 0.0;
private object holdFixedX_ = null;
/// <summary>
/// Constructor, which defines the world pixel length only. Both
/// x-axes will be moved by equal amounts in order to force this
/// constraint.
/// </summary>
/// <param name="p">The world pixel length</param>
public YPixelWorldLength( double p )
{
this.pWorldLength_ = p;
}
/// <summary>
/// Constructor, which defines the world pixel length together with
/// the x-axis that should be held constant when forcing this
/// constraint [the other x-axis only will be moved].
/// </summary>
/// <param name="p">The world pixel length</param>
/// <param name="holdFixedX">The position of this x-axis will be held constant. The other x-axis will be moved in order to force the constraint.</param>
public YPixelWorldLength( double p, PlotSurface2D.XAxisPosition holdFixedX )
{
this.pWorldLength_ = p;
this.holdFixedX_ = holdFixedX;
}
/// <summary>
/// Applies the constraint to the axes.
/// </summary>
/// <param name="pXAxis1">The bottom x-axis.</param>
/// <param name="pYAxis1">The left y-axis.</param>
/// <param name="pXAxis2">The top x-axis.</param>
/// <param name="pYAxis2">The right y-axis.</param>
public override void ApplyConstraint(
PhysicalAxis pXAxis1, PhysicalAxis pYAxis1,
PhysicalAxis pXAxis2, PhysicalAxis pYAxis2 )
{
int desiredLength = (int)(pYAxis1.Axis.WorldLength / this.pWorldLength_);
int currentLength = pYAxis1.PhysicalLength;
int delta = currentLength - desiredLength;
int changeBottom = -delta / 2;
int changeTop = -delta / 2;
if (this.holdFixedX_ != null)
{
if ( (PlotSurface2D.XAxisPosition)this.holdFixedX_ == PlotSurface2D.XAxisPosition.Bottom )
{
changeBottom = 0;
changeTop = -delta;
}
else
{
changeBottom = -delta;
changeTop = 0;
}
}
pYAxis1.PhysicalMin = new Point( pYAxis1.PhysicalMin.X, pYAxis1.PhysicalMin.Y+changeBottom );
pYAxis1.PhysicalMax = new Point( pYAxis1.PhysicalMax.X, pYAxis1.PhysicalMax.Y-changeTop );
pYAxis2.PhysicalMin = new Point( pYAxis2.PhysicalMin.X, pYAxis2.PhysicalMin.Y+changeBottom );
pYAxis2.PhysicalMax = new Point( pYAxis2.PhysicalMax.X, pYAxis2.PhysicalMax.Y-changeTop );
pXAxis1.PhysicalMin = new Point( pXAxis1.PhysicalMin.X, pXAxis1.PhysicalMin.Y+changeBottom );
pXAxis1.PhysicalMax = new Point( pXAxis1.PhysicalMax.X, pXAxis1.PhysicalMax.Y+changeBottom );
pXAxis2.PhysicalMin = new Point( pXAxis2.PhysicalMin.X, pXAxis2.PhysicalMin.Y-changeTop );
pXAxis2.PhysicalMax = new Point( pXAxis2.PhysicalMax.X, pXAxis2.PhysicalMax.Y-changeTop );
}
}
/// <summary>
/// Defines an AxisConstraint that forces the specified axis to be placed at a
/// specific physical position. The position of the axis opposite is held
/// constant.
/// </summary>
public class AxisPosition : AxesConstraint
{
private object xAxisPosition_;
private object yAxisPosition_;
private int position_;
/// <summary>
/// Constructor, which defines an horizontal axis and the physical
/// y position it should be drawn at.
/// </summary>
/// <param name="axis">The x-axis for which the y position is to be specified.</param>
/// <param name="yPosition">The [physical] y position of the axis.</param>
public AxisPosition( PlotSurface2D.XAxisPosition axis, int yPosition )
{
position_ = yPosition;
xAxisPosition_ = axis;
}
/// <summary>
/// Constructor, which defines a vertical axis and the physical
/// x position it should be drawn at.
/// </summary>
/// <param name="axis">The y-axis for which the x position is to be specified.</param>
/// <param name="xPosition">The [physical] x position of the axis.</param>
public AxisPosition( PlotSurface2D.YAxisPosition axis, int xPosition )
{
position_ = xPosition;
yAxisPosition_ = axis;
}
/// <summary>
/// Applies the constraint to the axes.
/// </summary>
/// <param name="pXAxis1">The bottom x-axis.</param>
/// <param name="pYAxis1">The left y-axis.</param>
/// <param name="pXAxis2">The top x-axis.</param>
/// <param name="pYAxis2">The right y-axis.</param>
public override void ApplyConstraint(
PhysicalAxis pXAxis1, PhysicalAxis pYAxis1,
PhysicalAxis pXAxis2, PhysicalAxis pYAxis2 )
{
if ( xAxisPosition_ != null )
{
if ((PlotSurface2D.XAxisPosition)xAxisPosition_ == PlotSurface2D.XAxisPosition.Bottom)
{
pXAxis1.PhysicalMin = new Point( pXAxis1.PhysicalMin.X, position_ );
pXAxis1.PhysicalMax = new Point( pXAxis1.PhysicalMax.X, position_ );
pYAxis1.PhysicalMin = new Point( pYAxis1.PhysicalMin.X, position_ );
pYAxis2.PhysicalMin = new Point( pYAxis2.PhysicalMin.X, position_ );
}
else
{
pXAxis2.PhysicalMin = new Point( pXAxis2.PhysicalMin.X, position_ );
pXAxis2.PhysicalMax = new Point( pXAxis2.PhysicalMax.X, position_ );
pYAxis1.PhysicalMax = new Point( pYAxis1.PhysicalMax.X, position_ );
pYAxis2.PhysicalMax = new Point( pYAxis2.PhysicalMax.X, position_ );
}
}
else if (yAxisPosition_ != null )
{
if ((PlotSurface2D.YAxisPosition)yAxisPosition_ == PlotSurface2D.YAxisPosition.Left)
{
pYAxis1.PhysicalMin = new Point( position_, pYAxis1.PhysicalMin.Y );
pYAxis1.PhysicalMax = new Point( position_, pYAxis1.PhysicalMax.Y );
pXAxis1.PhysicalMin = new Point( position_, pXAxis1.PhysicalMin.Y );
pXAxis2.PhysicalMin = new Point( position_, pXAxis2.PhysicalMin.Y );
}
else
{
pYAxis2.PhysicalMin = new Point( position_, pYAxis2.PhysicalMin.Y );
pYAxis2.PhysicalMax = new Point( position_, pYAxis2.PhysicalMax.Y );
pXAxis1.PhysicalMax = new Point( position_, pXAxis1.PhysicalMax.Y );
pXAxis2.PhysicalMax = new Point( position_, pXAxis2.PhysicalMax.Y );
}
}
}
}
/// <summary>
/// Defines an axes constraint that forces the world width and height pixel lengths
/// to be at the provided ratio. For example, an aspect ratio of 3:2 or
/// 1.5 indicates that there should be 1.5 times as many pixels per fixed
/// world length along the x direction than for the same world length along
/// the y direction. In other words, the world length of one pixel along
/// the x direction is 2/3rds that of the world length of one pixel height
/// in the y direction.
/// </summary>
/// <remarks>
/// This class will never increase the size of the plot bounding box. It
/// will always be made smaller.
/// </remarks>
public class AspectRatio : AxesConstraint
{
private double a_;
private object holdFixedX_ = null;
private object holdFixedY_ = null;
/// <summary>
/// Constructor.
/// </summary>
/// <param name="a">Aspect Ratio</param>
public AspectRatio( double a )
{
this.a_ = a;
}
/// <summary>
/// Constructor
/// </summary>
/// <param name="a">Aspect Ratio</param>
/// <param name="holdFixedX">
/// When adjusting the position of axes, the specified axis will never
/// be moved.
/// </param>
public AspectRatio( double a, PlotSurface2D.XAxisPosition holdFixedX )
{
this.a_ = a;
this.holdFixedX_ = holdFixedX;
}
/// <summary>
/// Constructor
/// </summary>
/// <param name="a">Aspect Ratio</param>
/// <param name="holdFixedY">
/// When adjusting the position of axes, the
/// specified axis will never be moved.
/// </param>
public AspectRatio( double a, PlotSurface2D.YAxisPosition holdFixedY )
{
this.a_ = a;
this.holdFixedY_ = holdFixedY;
}
/// <summary>
/// Constructor
/// </summary>
/// <param name="a">Aspect Ratio</param>
/// <param name="holdFixedX">When adjusting the position of axes, the specified axis will never be moved.</param>
/// <param name="holdFixedY">When adjusting the position of axes, the specified axis will never be moved.</param>
public AspectRatio(
double a,
PlotSurface2D.XAxisPosition holdFixedX,
PlotSurface2D.YAxisPosition holdFixedY )
{
this.a_ = a;
this.holdFixedX_ = holdFixedX;
this.holdFixedY_ = holdFixedY;
}
/// <summary>
/// Applies the constraint to the axes.
/// </summary>
/// <param name="pXAxis1">The bottom x-axis.</param>
/// <param name="pYAxis1">The left y-axis.</param>
/// <param name="pXAxis2">The top x-axis.</param>
/// <param name="pYAxis2">The right y-axis.</param>
public override void ApplyConstraint(
PhysicalAxis pXAxis1, PhysicalAxis pYAxis1,
PhysicalAxis pXAxis2, PhysicalAxis pYAxis2 )
{
double xWorldRange = Math.Abs( pXAxis1.Axis.WorldMax - pXAxis1.Axis.WorldMin );
double xPhysicalRange = Math.Abs( pXAxis1.PhysicalMax.X - pXAxis1.PhysicalMin.X );
double xDirPixelSize = xWorldRange / xPhysicalRange;
double yWorldRange = Math.Abs( pYAxis1.Axis.WorldMax - pYAxis1.Axis.WorldMin );
double yPhysicalRange = Math.Abs( pYAxis1.PhysicalMax.Y - pYAxis1.PhysicalMin.Y );
double yDirPixelSize = yWorldRange / yPhysicalRange;
double currentAspectRatio = yDirPixelSize / xDirPixelSize;
// we want to change the current aspect ratio to be the desired.
// to do this, we may only add the world pixel lengths.
if ( this.a_ > currentAspectRatio )
{
// want to increase aspect ratio. Therefore, want to add some amount
// to yDirPixelSize (numerator).
double toAdd = ( this.a_ - currentAspectRatio ) * xDirPixelSize;
int newHeight =
(int)( Math.Abs(pYAxis1.Axis.WorldMax - pYAxis1.Axis.WorldMin) / (yDirPixelSize + toAdd) );
int changeInHeight = (int)yPhysicalRange - newHeight;
int changeBottom = changeInHeight/2;
int changeTop = changeInHeight/2;
if (this.holdFixedX_ != null)
{
if ( (PlotSurface2D.XAxisPosition)this.holdFixedX_ == PlotSurface2D.XAxisPosition.Bottom )
{
changeBottom = 0;
changeTop = changeInHeight;
}
else
{
changeBottom = changeInHeight;
changeTop = 0;
}
}
pYAxis1.PhysicalMin = new Point( pYAxis1.PhysicalMin.X, pYAxis1.PhysicalMin.Y-changeBottom );
pYAxis1.PhysicalMax = new Point( pYAxis1.PhysicalMax.X, pYAxis1.PhysicalMax.Y+changeTop );
pYAxis2.PhysicalMin = new Point( pYAxis2.PhysicalMin.X, pYAxis2.PhysicalMin.Y-changeBottom );
pYAxis2.PhysicalMax = new Point( pYAxis2.PhysicalMax.X, pYAxis2.PhysicalMax.Y+changeTop );
pXAxis1.PhysicalMin = new Point( pXAxis1.PhysicalMin.X, pXAxis1.PhysicalMin.Y-changeBottom );
pXAxis1.PhysicalMax = new Point( pXAxis1.PhysicalMax.X, pXAxis1.PhysicalMax.Y-changeBottom );
pXAxis2.PhysicalMin = new Point( pXAxis2.PhysicalMin.X, pXAxis2.PhysicalMin.Y+changeTop );
pXAxis2.PhysicalMax = new Point( pXAxis2.PhysicalMax.X, pXAxis2.PhysicalMax.Y+changeTop );
}
else
{
// want to decrease aspect ratio. Therefore, want to add some amount
// to xDirPixelSize (denominator).
double toAdd = yDirPixelSize / this.a_ - xDirPixelSize;
int newWidth =
(int)( Math.Abs(pXAxis1.Axis.WorldMax - pXAxis1.Axis.WorldMin) / (xDirPixelSize + toAdd) );
int changeInWidth = (int)xPhysicalRange - newWidth;
int changeLeft = changeInWidth / 2;
int changeRight = changeInWidth / 2;
if (this.holdFixedY_ != null)
{
if ( (PlotSurface2D.YAxisPosition)this.holdFixedY_ == PlotSurface2D.YAxisPosition.Left )
{
changeLeft = 0;
changeRight = changeInWidth;
}
else
{
changeLeft = changeInWidth;
changeRight = 0;
}
}
pXAxis1.PhysicalMin = new Point( pXAxis1.PhysicalMin.X+changeLeft, pXAxis1.PhysicalMin.Y );
pXAxis1.PhysicalMax = new Point( pXAxis1.PhysicalMax.X-changeRight, pXAxis1.PhysicalMax.Y );
pXAxis2.PhysicalMin = new Point( pXAxis2.PhysicalMin.X+changeLeft, pXAxis2.PhysicalMin.Y );
pXAxis2.PhysicalMax = new Point( pXAxis2.PhysicalMax.X-changeRight, pXAxis2.PhysicalMax.Y );
pYAxis1.PhysicalMin = new Point( pYAxis1.PhysicalMin.X+changeLeft, pYAxis1.PhysicalMin.Y );
pYAxis1.PhysicalMax = new Point( pYAxis1.PhysicalMax.X+changeLeft, pYAxis1.PhysicalMax.Y );
pYAxis2.PhysicalMin = new Point( pYAxis2.PhysicalMin.X-changeRight, pYAxis2.PhysicalMin.Y );
pYAxis2.PhysicalMax = new Point( pYAxis2.PhysicalMax.X-changeRight, pYAxis2.PhysicalMax.Y );
}
}
}
/// <summary>
/// Applies the constraint to the axes. Must be overriden.
/// </summary>
/// <param name="pXAxis1">The bottom x-axis.</param>
/// <param name="pYAxis1">The left y-axis.</param>
/// <param name="pXAxis2">The top x-axis.</param>
/// <param name="pYAxis2">The right y-axis.</param>
public abstract void ApplyConstraint(
PhysicalAxis pXAxis1, PhysicalAxis pYAxis1,
PhysicalAxis pXAxis2, PhysicalAxis pYAxis2 );
}
}

1654
lib/Axis.cs Normal file

Разница между файлами не показана из-за своего большого размера Загрузить разницу

298
lib/BarPlot.cs Normal file
Просмотреть файл

@ -0,0 +1,298 @@
/*
NPlot - A charting library for .NET
BarPlot.cs
Copyright (C) 2003
Matt Howlett
Redistribution and use of NPlot or parts there-of in source and
binary forms, with or without modification, are permitted provided
that the following conditions are met:
1. Re-distributions in source form must retain at the head of each
source file the above copyright notice, this list of conditions
and the following disclaimer.
2. Any product ("the product") that makes use NPlot or parts
there-of must either:
(a) allow any user of the product to obtain a complete machine-
readable copy of the corresponding source code for the
product and the version of NPlot used for a charge no more
than your cost of physically performing source distribution,
on a medium customarily used for software interchange, or:
(b) reproduce the following text in the documentation, about
box or other materials intended to be read by human users
of the product that is provided to every human user of the
product:
"This product includes software developed as
part of the NPlot library project available
from: http://www.nplot.com/"
The words "This product" may optionally be replace with
the actual name of the product.
------------------------------------------------------------------------
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
using System;
using System.Drawing;
namespace NPlot
{
/// <summary>
/// Draws
/// </summary>
public class BarPlot : BasePlot, IPlot, IDrawable
{
/// <summary>
/// Default Constructor
/// </summary>
public BarPlot()
{
}
/// <summary>
/// Gets or sets the data, or column name for the ordinate [y] axis.
/// </summary>
public object OrdinateDataTop
{
get
{
return this.ordinateDataTop_;
}
set
{
this.ordinateDataTop_ = value;
}
}
private object ordinateDataTop_ = null;
/// <summary>
/// Gets or sets the data, or column name for the ordinate [y] axis.
/// </summary>
public object OrdinateDataBottom
{
get
{
return this.ordinateDataBottom_;
}
set
{
this.ordinateDataBottom_ = value;
}
}
private object ordinateDataBottom_ = null;
/// <summary>
/// Gets or sets the data, or column name for the abscissa [x] axis.
/// </summary>
public object AbscissaData
{
get
{
return this.abscissaData_;
}
set
{
this.abscissaData_ = value;
}
}
private object abscissaData_ = null;
/// <summary>
/// Draws the line plot on a GDI+ surface against the provided x and y axes.
/// </summary>
/// <param name="g">The GDI+ surface on which to draw.</param>
/// <param name="xAxis">The X-Axis to draw against.</param>
/// <param name="yAxis">The Y-Axis to draw against.</param>
public void Draw( Graphics g, PhysicalAxis xAxis, PhysicalAxis yAxis )
{
SequenceAdapter dataTop =
new SequenceAdapter( this.DataSource, this.DataMember, this.OrdinateDataTop, this.AbscissaData );
SequenceAdapter dataBottom =
new SequenceAdapter( this.DataSource, this.DataMember, this.OrdinateDataBottom, this.AbscissaData );
ITransform2D t = Transform2D.GetTransformer( xAxis, yAxis );
for (int i=0; i<dataTop.Count; ++i)
{
PointF physicalBottom = t.Transform( dataBottom[i] );
PointF physicalTop = t.Transform( dataTop[i] );
if (physicalBottom != physicalTop)
{
Rectangle r = new Rectangle( (int)(physicalBottom.X - BarWidth/2), (int)physicalTop.Y,
(int)BarWidth, (int)(physicalBottom.Y - physicalTop.Y) );
g.FillRectangle( this.rectangleBrush_.Get(r), r );
g.DrawRectangle( borderPen_, r );
}
}
}
/// <summary>
/// Returns an x-axis that is suitable for drawing this plot.
/// </summary>
/// <returns>A suitable x-axis.</returns>
public Axis SuggestXAxis()
{
SequenceAdapter dataBottom_ =
new SequenceAdapter( this.DataSource, this.DataMember, this.OrdinateDataBottom, this.AbscissaData );
SequenceAdapter dataTop_ =
new SequenceAdapter( this.DataSource, this.DataMember, this.OrdinateDataTop, this.AbscissaData );
Axis axis = dataTop_.SuggestXAxis();
axis.LUB(dataBottom_.SuggestXAxis());
return axis;
}
/// <summary>
/// Returns a y-axis that is suitable for drawing this plot.
/// </summary>
/// <returns>A suitable y-axis.</returns>
public Axis SuggestYAxis()
{
SequenceAdapter dataBottom_ =
new SequenceAdapter( this.DataSource, this.DataMember, this.OrdinateDataBottom, this.AbscissaData );
SequenceAdapter dataTop_ =
new SequenceAdapter( this.DataSource, this.DataMember, this.OrdinateDataTop, this.AbscissaData );
Axis axis = dataTop_.SuggestYAxis();
axis.LUB(dataBottom_.SuggestYAxis());
return axis;
}
/// <summary>
/// Draws a representation of this plot in the legend.
/// </summary>
/// <param name="g">The graphics surface on which to draw.</param>
/// <param name="startEnd">A rectangle specifying the bounds of the area in the legend set aside for drawing.</param>
public virtual void DrawInLegend(Graphics g, Rectangle startEnd)
{
int smallerHeight = (int)(startEnd.Height * 0.5f);
int heightToRemove = (int)(startEnd.Height * 0.5f);
Rectangle newRectangle = new Rectangle( startEnd.Left, startEnd.Top + smallerHeight / 2, startEnd.Width, smallerHeight );
g.FillRectangle( rectangleBrush_.Get( newRectangle ), newRectangle );
g.DrawRectangle( borderPen_, newRectangle );
}
/// <summary>
/// The pen used to draw the plot
/// </summary>
public System.Drawing.Pen BorderPen
{
get
{
return borderPen_;
}
set
{
borderPen_ = value;
}
}
private System.Drawing.Pen borderPen_ = new Pen(Color.Black);
/// <summary>
/// The color of the pen used to draw lines in this plot.
/// </summary>
public System.Drawing.Color BorderColor
{
set
{
if (borderPen_ != null)
{
borderPen_.Color = value;
}
else
{
borderPen_ = new Pen(value);
}
}
get
{
return borderPen_.Color;
}
}
/// <summary>
/// Set/Get the fill brush
/// </summary>
public IRectangleBrush FillBrush
{
get
{
return rectangleBrush_;
}
set
{
rectangleBrush_ = value;
}
}
private IRectangleBrush rectangleBrush_ = new RectangleBrushes.Solid( Color.LightGray );
/// <summary>
/// Set/Get the width of the bar in physical pixels.
/// </summary>
public float BarWidth
{
get
{
return barWidth_;
}
set
{
barWidth_ = value;
}
}
private float barWidth_ = 8;
/// <summary>
/// Write data associated with the plot as text.
/// </summary>
/// <param name="sb">the string builder to write to.</param>
/// <param name="region">Only write out data in this region if onlyInRegion is true.</param>
/// <param name="onlyInRegion">If true, only data in region is written, else all data is written.</param>
/// <remarks>TODO: not implemented.</remarks>
public void WriteData( System.Text.StringBuilder sb, RectangleD region, bool onlyInRegion )
{
sb.Append( "Write data not implemented yet for BarPlot\r\n" );
}
}
}

138
lib/BasePlot.cs Normal file
Просмотреть файл

@ -0,0 +1,138 @@
/*
NPlot - A charting library for .NET
BasePlot.cs
Copyright (C) 2003
Matt Howlett
Redistribution and use of NPlot or parts there-of in source and
binary forms, with or without modification, are permitted provided
that the following conditions are met:
1. Re-distributions in source form must retain at the head of each
source file the above copyright notice, this list of conditions
and the following disclaimer.
2. Any product ("the product") that makes use NPlot or parts
there-of must either:
(a) allow any user of the product to obtain a complete machine-
readable copy of the corresponding source code for the
product and the version of NPlot used for a charge no more
than your cost of physically performing source distribution,
on a medium customarily used for software interchange, or:
(b) reproduce the following text in the documentation, about
box or other materials intended to be read by human users
of the product that is provided to every human user of the
product:
"This product includes software developed as
part of the NPlot library project available
from: http://www.nplot.com/"
The words "This product" may optionally be replace with
the actual name of the product.
------------------------------------------------------------------------
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
using System;
using System.Drawing;
namespace NPlot
{
/// <summary>
/// Supplies implementation of basic legend handling properties, and
/// basic data specifying properties which are used by all plots.
/// </summary>
/// <remarks>If C# had multiple inheritance, the heirachy would be different.</remarks>
public abstract class BasePlot
{
/// <summary>
/// A label to associate with the plot - used in the legend.
/// </summary>
public string Label
{
get
{
return label_;
}
set
{
this.label_ = value;
}
}
private string label_ = "";
/// <summary>
/// Whether or not to include an entry for this plot in the legend if it exists.
/// </summary>
public bool ShowInLegend
{
get
{
return showInLegend_;
}
set
{
this.showInLegend_ = value;
}
}
private bool showInLegend_ = true;
/// <summary>
/// Gets or sets the source containing a list of values used to populate the plot object.
/// </summary>
public object DataSource
{
get
{
return this.dataSource_;
}
set
{
this.dataSource_ = value;
}
}
private object dataSource_ = null;
/// <summary>
/// Gets or sets the specific data member in a multimember data source to get data from.
/// </summary>
public string DataMember
{
get
{
return this.dataMember_;
}
set
{
this.dataMember_ = value;
}
}
private string dataMember_ = null;
}
}

96
lib/BasePlot3D.cs Normal file
Просмотреть файл

@ -0,0 +1,96 @@
// ******** experimental ********
/*
using System;
namespace NPlot
{
/// <summary>
/// Functionality shared amoungst all 3D plots. TODO: Not implemented.
/// </summary>
public class BasePlot3D
{
/// <summary>
/// Constructor.
/// </summary>
public BasePlot3D()
{
}
// DATA SPECIFIERS
// in first instance I think just have a DataSource, with
// the only way of specifying points as an ArrayList of
// point3s
/// <summary>
/// Gets or sets the source containing a list of values used to populate the plot object.
/// </summary>
public object DataSource
{
get
{
return dataSource_;
}
set
{
dataSource_ = value;
}
}
object dataSource_ = null;
need a SequenceAdapter3D to interpret all this crap -
probably build on SequenceAdapter.
public string DataMember
{
get
{
return dataMember_;
}
set
{
dataMember_ = value;
}
}
string dataMember_ = null;
// these are needed for access to table columns.
public object XData
{
get
{
}
set
{
}
}
public object YData
{
get
{
}
set
{
}
}
public object ZData
{
get
{
}
set
{
}
}
}
}
*/

Просмотреть файл

@ -0,0 +1,69 @@
using System;
using System.Drawing;
namespace NPlot
{
/// <summary>
/// supplies implementation of basic functionality for plots based on drawing
/// lines [line, step and histogram].
/// </summary>
/// <remarks>If C# had multiple inheritance, the heirachy would be different. The way it is isn't very nice.</remarks>
public class BaseSequenceLinePlot : BaseSequencePlot, ISequencePlot
{
/// <summary>
/// Draws a representation of this plot in the legend.
/// </summary>
/// <param name="g">The graphics surface on which to draw.</param>
/// <param name="startEnd">A rectangle specifying the bounds of the area in the legend set aside for drawing.</param>
public virtual void DrawInLegend( Graphics g, Rectangle startEnd )
{
g.DrawLine( pen_, startEnd.Left, (startEnd.Top + startEnd.Bottom)/2,
startEnd.Right, (startEnd.Top + startEnd.Bottom)/2 );
}
/// <summary>
/// The pen used to draw the plot
/// </summary>
public System.Drawing.Pen Pen
{
get
{
return pen_;
}
set
{
pen_ = value;
}
}
private System.Drawing.Pen pen_ = new Pen( Color.Black );
/// <summary>
/// The color of the pen used to draw lines in this plot.
/// </summary>
public System.Drawing.Color Color
{
set
{
if (pen_ != null)
{
pen_.Color = value;
}
else
{
pen_ = new Pen( value );
}
}
get
{
return pen_.Color;
}
}
}
}

118
lib/BaseSequencePlot.cs Normal file
Просмотреть файл

@ -0,0 +1,118 @@
/*
NPlot - A charting library for .NET
BaseSequencePlot.cs
Copyright (C) 2003
Matt Howlett
Redistribution and use of NPlot or parts there-of in source and
binary forms, with or without modification, are permitted provided
that the following conditions are met:
1. Re-distributions in source form must retain at the head of each
source file the above copyright notice, this list of conditions
and the following disclaimer.
2. Any product ("the product") that makes use NPlot or parts
there-of must either:
(a) allow any user of the product to obtain a complete machine-
readable copy of the corresponding source code for the
product and the version of NPlot used for a charge no more
than your cost of physically performing source distribution,
on a medium customarily used for software interchange, or:
(b) reproduce the following text in the documentation, about
box or other materials intended to be read by human users
of the product that is provided to every human user of the
product:
"This product includes software developed as
part of the NPlot library project available
from: http://www.nplot.com/"
The words "This product" may optionally be replace with
the actual name of the product.
------------------------------------------------------------------------
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
using System;
namespace NPlot
{
/// <summary>
/// Adds additional basic functionality to BasePlot that is common to all
/// plots that implement the ISequencePlot interface.
/// </summary>
/// <remarks>If C# had multiple inheritance, the heirachy would be different. The way it is isn't very nice.</remarks>
public class BaseSequencePlot : BasePlot, ISequencePlot
{
/// <summary>
/// Gets or sets the data, or column name for the ordinate [y] axis.
/// </summary>
public object OrdinateData
{
get
{
return this.ordinateData_;
}
set
{
this.ordinateData_ = value;
}
}
private object ordinateData_ = null;
/// <summary>
/// Gets or sets the data, or column name for the abscissa [x] axis.
/// </summary>
public object AbscissaData
{
get
{
return this.abscissaData_;
}
set
{
this.abscissaData_ = value;
}
}
private object abscissaData_ = null;
/// <summary>
/// Writes text data of the plot object to the supplied string builder. It is
/// possible to specify that only data in the specified range be written.
/// </summary>
/// <param name="sb">the StringBuilder object to write to.</param>
/// <param name="region">a region used if onlyInRegion is true.</param>
/// <param name="onlyInRegion">If true, only data enclosed in the provided region will be written.</param>
public void WriteData( System.Text.StringBuilder sb, RectangleD region, bool onlyInRegion )
{
SequenceAdapter data_ =
new SequenceAdapter( this.DataSource, this.DataMember, this.OrdinateData, this.AbscissaData );
sb.Append( "Label: " );
sb.Append( this.Label );
sb.Append( "\r\n" );
data_.WriteData( sb, region, onlyInRegion );
}
}
}

541
lib/Bitmap.PlotSurface2D.cs Normal file
Просмотреть файл

@ -0,0 +1,541 @@
/*
NPlot - A charting library for .NET
Bitmap.PlotSurface2D.cs
Copyright (C) 2003
Matt Howlett
Redistribution and use of NPlot or parts there-of in source and
binary forms, with or without modification, are permitted provided
that the following conditions are met:
1. Re-distributions in source form must retain at the head of each
source file the above copyright notice, this list of conditions
and the following disclaimer.
2. Any product ("the product") that makes use NPlot or parts
there-of must either:
(a) allow any user of the product to obtain a complete machine-
readable copy of the corresponding source code for the
product and the version of NPlot used for a charge no more
than your cost of physically performing source distribution,
on a medium customarily used for software interchange, or:
(b) reproduce the following text in the documentation, about
box or other materials intended to be read by human users
of the product that is provided to every human user of the
product:
"This product includes software developed as
part of the NPlot library project available
from: http://www.nplot.com/"
The words "This product" may optionally be replace with
the actual name of the product.
------------------------------------------------------------------------
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
using System;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Collections;
namespace NPlot
{
namespace Bitmap
{
/// <summary>
/// Wrapper around NPlot.PlotSurface2D that provides extra functionality
/// specific to drawing to Bitmaps.
/// </summary>
public class PlotSurface2D: IPlotSurface2D
{
/// <summary>
/// Constructor.
/// </summary>
/// <param name="width">width of the bitmap.</param>
/// <param name="height">height of the bitmap.</param>
public PlotSurface2D( int width, int height )
{
b_ = new System.Drawing.Bitmap( width, height );
ps_ = new NPlot.PlotSurface2D();
}
/// <summary>
/// Constructor.
/// </summary>
/// <param name="b">The Bitmap where the plot is to be rendered.</param>
public PlotSurface2D( System.Drawing.Bitmap b )
{
b_ = b;
ps_ = new NPlot.PlotSurface2D();
}
/// <summary>
/// Renders the plot.
/// </summary>
/// <param name="g">The graphics surface.</param>
/// <param name="bounds">The rectangle storing the bounds for rendering.</param>
public void Draw( Graphics g, Rectangle bounds )
{
ps_.Draw( g, bounds );
}
/// <summary>
/// Clears the plot.
/// </summary>
public void Clear()
{
ps_.Clear();
}
/// <summary>
/// Adds a drawable object to the plot surface. If the object is an IPlot,
/// the PlotSurface2D axes will also be updated.
/// </summary>
/// <param name="p">The IDrawable object to add to the plot surface.</param>
public void Add( IDrawable p )
{
ps_.Add( p );
}
/// <summary>
/// Adds a drawable object to the plot surface against the specified axes. If
/// the object is an IPlot, the PlotSurface2D axes will also be updated.
/// </summary>
/// <param name="p">the IDrawable object to add to the plot surface</param>
/// <param name="xp">the x-axis to add the plot against.</param>
/// <param name="yp">the y-axis to add the plot against.</param>
public void Add( IDrawable p, NPlot.PlotSurface2D.XAxisPosition xp, NPlot.PlotSurface2D.YAxisPosition yp )
{
ps_.Add( p, xp, yp );
}
/// <summary>
/// Adds a drawable object to the plot surface. If the object is an IPlot,
/// the PlotSurface2D axes will also be updated.
/// </summary>
/// <param name="p">The IDrawable object to add to the plot surface.</param>
/// <param name="zOrder">The z-ordering when drawing (objects with lower numbers are drawn first)</param>
public void Add( IDrawable p, int zOrder )
{
ps_.Add( p, zOrder );
}
/// <summary>
/// Adds a drawable object to the plot surface against the specified axes. If
/// the object is an IPlot, the PlotSurface2D axes will also be updated.
/// </summary>
/// <param name="p">the IDrawable object to add to the plot surface</param>
/// <param name="xp">the x-axis to add the plot against.</param>
/// <param name="yp">the y-axis to add the plot against.</param>
/// <param name="zOrder">The z-ordering when drawing (objects with lower numbers are drawn first)</param>
public void Add( IDrawable p, NPlot.PlotSurface2D.XAxisPosition xp,
NPlot.PlotSurface2D.YAxisPosition yp, int zOrder )
{
ps_.Add( p, xp, yp , zOrder);
}
/// <summary>
/// The plot surface title.
/// </summary>
public string Title
{
get
{
return ps_.Title;
}
set
{
ps_.Title = value;
}
}
/// <summary>
/// The plot title font.
/// </summary>
public Font TitleFont
{
get
{
return ps_.TitleFont;
}
set
{
ps_.TitleFont = value;
}
}
/// <summary>
/// The distance in pixels to leave between of the edge of the bounding rectangle
/// supplied to the Draw method, and the markings that make up the plot.
/// </summary>
public int Padding
{
get
{
return ps_.Padding;
}
set
{
ps_.Padding = value;
}
}
/// <summary>
/// The bottom abscissa axis.
/// </summary>
public Axis XAxis1
{
get
{
return ps_.XAxis1;
}
set
{
ps_.XAxis1 = value;
}
}
/// <summary>
/// The left ordinate axis.
/// </summary>
public Axis YAxis1
{
get
{
return ps_.YAxis1;
}
set
{
ps_.YAxis1 = value;
}
}
/// <summary>
/// The top abscissa axis.
/// </summary>
public Axis XAxis2
{
get
{
return ps_.XAxis2;
}
set
{
ps_.XAxis2 = value;
}
}
/// <summary>
/// The right ordinate axis.
/// </summary>
public Axis YAxis2
{
get
{
return ps_.YAxis2;
}
set
{
ps_.YAxis2 = value;
}
}
/// <summary>
/// Gets or Sets the legend to use with this plot surface.
/// </summary>
public NPlot.Legend Legend
{
get
{
return ps_.Legend;
}
set
{
ps_.Legend = value;
}
}
/// <summary>
/// Gets or Sets the legend z-order.
/// </summary>
public int LegendZOrder
{
get
{
return ps_.LegendZOrder;
}
set
{
ps_.LegendZOrder = value;
}
}
/// <summary>
/// A color used to paint the plot background. Mutually exclusive with PlotBackImage and PlotBackBrush
/// </summary>
public System.Drawing.Color PlotBackColor
{
set
{
ps_.PlotBackColor = value;
}
}
/// <summary>
/// An imaged used to paint the plot background. Mutually exclusive with PlotBackColor and PlotBackBrush
/// </summary>
public System.Drawing.Bitmap PlotBackImage
{
set
{
ps_.PlotBackImage = value;
}
}
/// <summary>
/// A Rectangle brush used to paint the plot background. Mutually exclusive with PlotBackColor and PlotBackBrush
/// </summary>
public IRectangleBrush PlotBackBrush
{
set
{
ps_.PlotBackBrush = value;
}
}
/// <summary>
/// Smoothing mode to use when drawing plots.
/// </summary>
public System.Drawing.Drawing2D.SmoothingMode SmoothingMode
{
get
{
return ps_.SmoothingMode;
}
set
{
ps_.SmoothingMode = value;
}
}
/// <summary>
/// The bitmap width
/// </summary>
public int Width
{
get
{
return b_.Width;
}
}
/// <summary>
/// The bitmap height
/// </summary>
public int Height
{
get
{
return b_.Height;
}
}
/// <summary>
/// Renders the bitmap to a MemoryStream. Useful for returning the bitmap from
/// an ASP.NET page.
/// </summary>
/// <returns>The MemoryStream object.</returns>
public System.IO.MemoryStream ToStream( System.Drawing.Imaging.ImageFormat imageFormat )
{
System.IO.MemoryStream stream = new System.IO.MemoryStream();
ps_.Draw(Graphics.FromImage(this.Bitmap),new System.Drawing.Rectangle(0,0,b_.Width,b_.Height));
this.Bitmap.Save(stream, imageFormat);
return stream;
}
/// <summary>
/// The bitmap to use as the drawing surface.
/// </summary>
public System.Drawing.Bitmap Bitmap
{
get
{
return b_;
}
set
{
b_ = value;
}
}
/// <summary>
/// The bitmap background color outside the bounds of the plot surface.
/// </summary>
public Color BackColor
{
set
{
backColor_ = value;
}
}
object backColor_ = null;
/// <summary>
/// Refreshes (draws) the plot.
/// </summary>
public void Refresh()
{
if (this.backColor_!=null)
{
Graphics g = Graphics.FromImage( b_ );
g.FillRectangle( (new Pen( (Color)this.backColor_)).Brush,0,0,b_.Width,b_.Height );
}
ps_.Draw( Graphics.FromImage(b_), new System.Drawing.Rectangle(0,0,b_.Width,b_.Height) );
}
private NPlot.PlotSurface2D ps_;
private System.Drawing.Bitmap b_;
/// <summary>
/// Add an axis constraint to the plot surface. Axis constraints can
/// specify relative world-pixel scalings, absolute axis positions etc.
/// </summary>
/// <param name="c">The axis constraint to add.</param>
public void AddAxesConstraint( AxesConstraint c )
{
ps_.AddAxesConstraint( c );
}
/// <summary>
/// Whether or not the title will be scaled according to size of the plot
/// surface.
/// </summary>
public bool AutoScaleTitle
{
get
{
return ps_.AutoScaleTitle;
}
set
{
ps_.AutoScaleTitle = value;
}
}
/// <summary>
/// When plots are added to the plot surface, the axes they are attached to
/// are immediately modified to reflect data of the plot. If
/// AutoScaleAutoGeneratedAxes is true when a plot is added, the axes will
/// be turned in to auto scaling ones if they are not already [tick marks,
/// tick text and label size scaled to size of plot surface]. If false,
/// axes will not be autoscaling.
/// </summary>
public bool AutoScaleAutoGeneratedAxes
{
get
{
return ps_.AutoScaleAutoGeneratedAxes;
}
set
{
ps_.AutoScaleAutoGeneratedAxes = value;
}
}
/// <summary>
/// Sets the title to be drawn using a solid brush of this color.
/// </summary>
public Color TitleColor
{
set
{
ps_.TitleColor = value;
}
}
/// <summary>
/// The brush used for drawing the title.
/// </summary>
public Brush TitleBrush
{
get
{
return ps_.TitleBrush;
}
set
{
ps_.TitleBrush = value;
}
}
/// <summary>
/// Remove a drawable object from the plot surface.
/// </summary>
/// <param name="p">the drawable to remove</param>
/// <param name="updateAxes">whether or not to update the axes after removing the idrawable.</param>
public void Remove(IDrawable p, bool updateAxes)
{
ps_.Remove(p, updateAxes);
}
/// <summary>
/// Gets an array list containing all drawables currently added to the PlotSurface2D.
/// </summary>
public ArrayList Drawables
{
get
{
return ps_.Drawables;
}
}
}
}
}

72
lib/BubblePlot.cs Normal file
Просмотреть файл

@ -0,0 +1,72 @@
using System;
/*
namespace NPlot
{
/// <summary>
/// Summary description for BubblePlot.
/// </summary>
public class BubblePlot : BasePlot, IPlot
{
/// <summary>
/// Constructor
/// </summary>
public BubblePlot()
{
}
public void DrawInLegend(System.Drawing.Graphics g, System.Drawing.Rectangle startEnd)
{
// TODO: Add BubblePlot.DrawInLegend implementation
}
public string Label
{
get
{
// TODO: Add BubblePlot.Label getter implementation
return null;
}
set
{
// TODO: Add BubblePlot.Label setter implementation
}
}
public bool ShowInLegend
{
get
{
// TODO: Add BubblePlot.ShowInLegend getter implementation
return false;
}
set
{
// TODO: Add BubblePlot.ShowInLegend setter implementation
}
}
public Axis SuggestXAxis()
{
// TODO: Add BubblePlot.SuggestXAxis implementation
return null;
}
public Axis SuggestYAxis()
{
// TODO: Add BubblePlot.SuggestYAxis implementation
return null;
}
public void Draw(System.Drawing.Graphics g, PhysicalAxis xAxis, PhysicalAxis yAxis)
{
// TODO: Add BubblePlot.Draw implementation
}
}
}
*/

891
lib/CandlePlot.cs Normal file
Просмотреть файл

@ -0,0 +1,891 @@
/*
NPlot - A charting library for .NET
CandlePlot.cs
Copyright (C) 2003
Matt Howlett
Pawel Konieczny
Redistribution and use of NPlot or parts there-of in source and
binary forms, with or without modification, are permitted provided
that the following conditions are met:
1. Re-distributions in source form must retain at the head of each
source file the above copyright notice, this list of conditions
and the following disclaimer.
2. Any product ("the product") that makes use NPlot or parts
there-of must either:
(a) allow any user of the product to obtain a complete machine-
readable copy of the corresponding source code for the
product and the version of NPlot used for a charge no more
than your cost of physically performing source distribution,
on a medium customarily used for software interchange, or:
(b) reproduce the following text in the documentation, about
box or other materials intended to be read by human users
of the product that is provided to every human user of the
product:
"This product includes software developed as
part of the NPlot library project available
from: http://www.nplot.com/"
The words "This product" may optionally be replace with
the actual name of the product.
------------------------------------------------------------------------
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
using System;
using System.Drawing;
using System.Data;
namespace NPlot
{
/// <summary>
/// Encapsulates open, low, high and close values useful for specifying financial data
/// over a time period, together with a [single] x-value indicating the time [period] the
/// data corresponds to.
/// </summary>
public class PointOLHC
{
/// <summary>
/// Constructor
/// </summary>
/// <param name="x">value representing the time period that the financial values refer to</param>
/// <param name="open">The value at open of time period.</param>
/// <param name="low">The low value over the time period</param>
/// <param name="high">The high value over the time period.</param>
/// <param name="close">The value at close of time period.</param>
public PointOLHC( double x, double open, double low, double high, double close )
{
this.x_ = x;
this.open_ = open;
this.close_ = close;
this.low_ = low;
this.high_ = high;
}
/// <summary>
/// value representing the time period that the financial values apply to.
/// </summary>
public double X
{
get
{
return x_;
}
set
{
this.x_ = value;
}
}
private double x_;
/// <summary>
/// The value at open of time period.
/// </summary>
public double Open
{
get
{
return open_;
}
set
{
open_ = value;
}
}
private double open_;
/// <summary>
/// The value at close of time period.
/// </summary>
public double Close
{
get
{
return close_;
}
set
{
close_ = value;
}
}
private double close_;
/// <summary>
/// Low value of the time period.
/// </summary>
public double Low
{
get
{
return low_;
}
set
{
low_ = value;
}
}
private double low_;
/// <summary>
/// High value of the time period.
/// </summary>
public double High
{
get
{
return high_;
}
set
{
high_ = value;
}
}
private double high_;
}
/// <summary>
/// Encapsulates functionality for drawing finacial candle charts.
/// </summary>
public class CandlePlot : BasePlot, IPlot
{
/// <summary>
///
/// </summary>
public abstract class CandleStyle
{
/// <summary>
///
/// </summary>
/// <param name="d"></param>
/// <returns></returns>
public abstract CandleStyle Create(CandleDataAdapter d);
}
/// <summary>
///
/// </summary>
public class Stick : CandleStyle
{
private Stick() { }
/// <summary>
///
/// </summary>
/// <param name="d"></param>
/// <returns></returns>
public override CandleStyle Create(CandleDataAdapter d)
{
return new Stick();
}
}
/// <summary>
/// This class is responsible for interpreting the various ways you can
/// specify data to CandlePlot objects
/// </summary>
public class CandleDataAdapter
{
private object openData_;
private object lowData_;
private object highData_;
private object closeData_;
private object abscissaData_;
private object dataSource_;
private string dataMember_;
DataRowCollection rows_ = null;
// speed optimizations if data is double.
private double[] openDataArray_;
private double[] lowDataArray_;
private double[] highDataArray_;
private double[] closeDataArray_;
private double[] abscissaDataArray_;
private bool useDoublesArrays_;
/// <summary>
/// Constructor
/// </summary>
/// <param name="dataSource"></param>
/// <param name="dataMember"></param>
/// <param name="abscissaData"></param>
/// <param name="openData"></param>
/// <param name="lowData"></param>
/// <param name="highData"></param>
/// <param name="closeData"></param>
public CandleDataAdapter(
object dataSource, string dataMember, object abscissaData,
object openData, object lowData, object highData, object closeData )
{
this.openData_ = openData;
this.lowData_ = lowData;
this.highData_ = highData;
this.closeData_ = closeData;
this.abscissaData_ = abscissaData;
this.dataSource_ = dataSource;
this.dataMember_ = dataMember;
if (dataSource_ != null)
{
if ( dataSource_ is DataSet )
{
if (dataMember_ != null)
{
rows_ = ((DataTable)((DataSet)dataSource_).Tables[dataMember_]).Rows;
}
else
{
rows_ = ((DataTable)((DataSet)dataSource_).Tables[0]).Rows;
}
}
else if (dataSource_ is DataTable )
{
rows_ = ((DataTable)dataSource_).Rows;
}
else
{
throw new NPlotException ( "not implemented yet" );
}
}
openDataArray_ = openData_ as System.Double[];
lowDataArray_ = lowData_ as System.Double[];
highDataArray_ = highData_ as System.Double[];
closeDataArray_ = closeData_ as System.Double[];
abscissaDataArray_ = abscissaData_ as System.Double[];
useDoublesArrays_ = (
openDataArray_ != null &&
lowDataArray_ != null &&
highDataArray_ != null &&
lowDataArray_ != null &&
abscissaDataArray_ != null
);
}
/// <summary>
/// Gets the ith point in the candle adapter
/// </summary>
/// <param name="i">index of datapoint to get</param>
/// <returns>the datapoint.</returns>
public PointOLHC this[int i]
{
get
{
// try a fast track first
if (useDoublesArrays_)
{
return new PointOLHC(
abscissaDataArray_[i],
openDataArray_[i],
lowDataArray_[i],
highDataArray_[i],
closeDataArray_[i]);
}
// is the data coming from a data source?
else if (rows_ != null)
{
double x = Utils.ToDouble(((DataRow)(rows_[i]))[(string)abscissaData_]);
double open = Utils.ToDouble(((DataRow)(rows_[i]))[(string)openData_]);
double low = Utils.ToDouble(((DataRow)(rows_[i]))[(string)lowData_]);
double high = Utils.ToDouble(((DataRow)(rows_[i]))[(string)highData_]);
double close = Utils.ToDouble(((DataRow)(rows_[i]))[(string)closeData_]);
return new PointOLHC(x, open, low, high, close);
}
// the data is coming from individual arrays.
else if (abscissaData_ is Array && openData_ is Array && lowData_ is Array && highData_ is Array && closeData_ is Array)
{
double x = Utils.ToDouble(((Array)abscissaData_).GetValue(i));
double open = Utils.ToDouble(((Array)openData_).GetValue(i));
double low = Utils.ToDouble(((Array)lowData_).GetValue(i));
double high = Utils.ToDouble(((Array)highData_).GetValue(i));
double close = Utils.ToDouble(((Array)closeData_).GetValue(i));
return new PointOLHC(x, open, low, high, close);
}
else
{
throw new NPlotException("not implemented yet");
}
}
}
/// <summary>
/// The number of datapoints available via the candle adapter.
/// </summary>
/// <value>the number of datapoints available.</value>
public int Count
{
get
{
// this is inefficient [could set up delegates in constructor].
if (useDoublesArrays_)
{
return openDataArray_.Length;
}
if (openData_ == null)
{
return 0;
}
if (rows_ != null)
{
return rows_.Count;
}
if (openData_ is Array)
{
int size = ((Array)openData_).Length;
if (size != ((Array)closeData_).Length)
throw new NPlotException("open and close arrays are not of same length");
if (size != ((Array)lowData_).Length)
throw new NPlotException("open and close arrays are not of same length");
if (size != ((Array)highData_).Length)
throw new NPlotException("open and close arrays are not of same length");
return size;
}
throw new NPlotException( "data not in correct format" );
}
}
/// <summary>
/// Returns an x-axis that is suitable for drawing the data.
/// </summary>
/// <returns>A suitable x-axis.</returns>
public Axis SuggestXAxis()
{
double min;
double max;
double minStep = 0.0;
if (this.rows_ == null)
{
Utils.ArrayMinMax((System.Collections.IList)this.abscissaData_, out min, out max);
if (((System.Collections.IList)abscissaData_).Count > 1)
{
double first = Utils.ToDouble(((Array)abscissaData_).GetValue(0));
double second = Utils.ToDouble(((Array)abscissaData_).GetValue(1));
minStep = Math.Abs(second - first);
}
if (((System.Collections.IList)abscissaData_).Count > 2)
{
double first = Utils.ToDouble(((Array)abscissaData_).GetValue(1));
double second = Utils.ToDouble(((Array)abscissaData_).GetValue(2));
if (Math.Abs(second - first) < minStep)
minStep = Math.Abs(second - first);
}
if (((System.Collections.IList)abscissaData_)[0] is DateTime)
{
return new DateTimeAxis(min - minStep / 2.0, max + minStep / 2.0);
}
else
{
return new LinearAxis(min - minStep / 2.0, max + minStep / 2.0);
}
}
else
{
Utils.RowArrayMinMax(this.rows_, out min, out max, (string)this.abscissaData_);
if (rows_.Count > 1)
{
double first = Utils.ToDouble(rows_[0][(string)abscissaData_]);
double second = Utils.ToDouble(rows_[1][(string)abscissaData_]);
minStep = Math.Abs(second - first);
}
if (rows_.Count > 2)
{
double first = Utils.ToDouble(rows_[1][(string)abscissaData_]);
double second = Utils.ToDouble(rows_[2][(string)abscissaData_]);
if (Math.Abs(second - first) < minStep)
minStep = Math.Abs(second - first);
}
if ((rows_[0])[(string)abscissaData_] is DateTime)
{
return new DateTimeAxis(min - minStep / 2.0, max + minStep / 2.0);
}
else
{
return new LinearAxis(min - minStep / 2.0, max + minStep / 2.0);
}
}
}
/// <summary>
/// Returns a y-axis that is suitable for drawing the data.
/// </summary>
/// <returns>A suitable y-axis.</returns>
public Axis SuggestYAxis()
{
double min_l;
double max_l;
double min_h;
double max_h;
if (this.rows_ == null)
{
Utils.ArrayMinMax((System.Collections.IList)lowData_, out min_l, out max_l);
Utils.ArrayMinMax((System.Collections.IList)highData_, out min_h, out max_h);
}
else
{
Utils.RowArrayMinMax(this.rows_, out min_l, out max_l, (string)this.lowData_);
Utils.RowArrayMinMax(this.rows_, out min_h, out max_h, (string)this.highData_);
}
Axis a = new LinearAxis( min_l, max_h );
a.IncreaseRange( 0.08 );
return a;
}
}
/// <summary>
/// Default constructor.
/// </summary>
public CandlePlot()
{
}
/// <summary>
/// Calculates the physical (not world) separation between abscissa values.
/// </summary>
/// <param name="cd">Candle adapter containing data</param>
/// <param name="xAxis">Physical x axis the data is plotted against.</param>
/// <returns>physical separation between abscissa values.</returns>
private static float CalculatePhysicalSeparation( CandleDataAdapter cd, PhysicalAxis xAxis )
{
if (cd.Count > 1)
{
int xPos1 = (int)(xAxis.WorldToPhysical( ((PointOLHC)cd[0]).X, false )).X;
int xPos2 = (int)(xAxis.WorldToPhysical( ((PointOLHC)cd[1]).X, false )).X;
int minDist = xPos2 - xPos1;
if (cd.Count > 2)
{ // to be pretty sure we get the smallest gap.
int xPos3 = (int)(xAxis.WorldToPhysical(((PointOLHC)cd[2]).X, false)).X;
if (xPos3 - xPos2 < minDist) minDist = xPos3 - xPos2;
if (cd.Count > 3)
{
int xPos4 = (int)(xAxis.WorldToPhysical(((PointOLHC)cd[3]).X, false)).X;
if (xPos4 - xPos3 < minDist) minDist = xPos4 - xPos3;
}
}
return minDist;
}
return 0.0f;
}
/// <summary>
/// Draws the candle plot on a GDI+ surface agains the provided x and y axes.
/// </summary>
/// <param name="g">The GDI+ surface on which to draw.</param>
/// <param name="xAxis">The X-Axis to draw against.</param>
/// <param name="yAxis">The Y-Axis to draw against.</param>
public void Draw( Graphics g, PhysicalAxis xAxis, PhysicalAxis yAxis )
{
CandleDataAdapter cd = new CandleDataAdapter( this.DataSource, this.DataMember,
this.AbscissaData, this.OpenData, this.LowData, this.HighData, this.CloseData );
Brush bearishBrush = new SolidBrush( BearishColor );
Brush bullishBrush = new SolidBrush( BullishColor );
uint offset = 0;
if (this.centered_)
{
offset = (uint)(CalculatePhysicalSeparation(cd,xAxis) / 2.0f);
}
uint addAmount = (uint)StickWidth/2;
uint stickWidth = (uint)StickWidth;
if (StickWidth == AutoScaleStickWidth)
{
// default
addAmount = 2;
stickWidth = 4;
float minDist = CalculatePhysicalSeparation( cd, xAxis );
addAmount = (uint)(minDist / 3);
stickWidth = addAmount * 2;
}
Pen p = new Pen(this.color_);
/*
// brant hyatt proposed.
if (this.Style == Styles.Stick)
{
p.Width = stickWidth;
addAmount = stickWidth + 2;
}
*/
for (int i=0; i<cd.Count; ++i)
{
PointOLHC point = (PointOLHC)cd[i];
if ( (!double.IsNaN (point.Open)) && (!double.IsNaN(point.High)) && (!double.IsNaN (point.Low)) && (!double.IsNaN(point.Close)) )
{
int xPos = (int)(xAxis.WorldToPhysical( point.X, false )).X;
if (xPos + offset + addAmount < xAxis.PhysicalMin.X || xAxis.PhysicalMax.X < xPos + offset - addAmount)
continue;
int yPos1 = (int)(yAxis.WorldToPhysical( point.Low, false )).Y;
int yPos2 = (int)(yAxis.WorldToPhysical( point.High, false )).Y;
int yPos3 = (int)(yAxis.WorldToPhysical( point.Open, false )).Y;
int yPos4 = (int)(yAxis.WorldToPhysical( point.Close, false )).Y;
if (this.Style == Styles.Stick)
{
/*
// brant hyatt proposed.
if (i > 0)
{
if ( ((PointOLHC)cd[i]).Close > ((PointOLHC)cd[i-1]).Close)
{
p.Color = BullishColor;
}
else
{
p.Color = BearishColor;
}
}
*/
g.DrawLine( p, xPos+offset, yPos1, xPos+offset, yPos2 );
g.DrawLine( p, xPos-addAmount+offset, yPos3, xPos+offset, yPos3 );
g.DrawLine( p, xPos+offset, yPos4, xPos+addAmount+offset, yPos4 );
}
else if (this.Style == Styles.Filled)
{
g.DrawLine( p, xPos+offset, yPos1, xPos+offset, yPos2 );
if (yPos3 > yPos4)
{
g.FillRectangle( bullishBrush, xPos-addAmount+offset, yPos4, stickWidth, yPos3 - yPos4 );
g.DrawRectangle( p, xPos-addAmount+offset, yPos4, stickWidth, yPos3 - yPos4 );
}
else if (yPos3 < yPos4)
{
g.FillRectangle( bearishBrush, xPos-addAmount+offset, yPos3, stickWidth, yPos4 - yPos3 );
g.DrawRectangle( p, xPos-addAmount+offset, yPos3, stickWidth, yPos4 - yPos3 );
}
else
{
g.DrawLine( p, xPos-addAmount+offset, yPos3, xPos-addAmount+stickWidth+offset, yPos3 );
}
}
}
}
}
/// <summary>
/// Returns an x-axis that is suitable for drawing this plot.
/// </summary>
/// <returns>A suitable x-axis.</returns>
public Axis SuggestXAxis()
{
CandleDataAdapter candleData = new CandleDataAdapter( this.DataSource, this.DataMember,
this.AbscissaData, this.OpenData, this.LowData, this.HighData, this.CloseData );
return candleData.SuggestXAxis();
}
/// <summary>
/// Returns a y-axis that is suitable for drawing this plot.
/// </summary>
/// <returns>A suitable y-axis.</returns>
public Axis SuggestYAxis()
{
CandleDataAdapter candleData = new CandleDataAdapter( this.DataSource, this.DataMember,
this.AbscissaData, this.OpenData, this.LowData, this.HighData, this.CloseData );
return candleData.SuggestYAxis();
}
/// <summary>
/// Gets or sets the data, or column name for the open values.
/// </summary>
public object OpenData
{
get
{
return openData_;
}
set
{
openData_ = value;
}
}
private object openData_ = null;
/// <summary>
/// Gets or sets the data, or column name for the interval low values.
/// </summary>
public object LowData
{
get
{
return lowData_;
}
set
{
lowData_ = value;
}
}
private object lowData_ = null;
/// <summary>
/// Gets or sets the data, or column name for the interval high values.
/// </summary>
public object HighData
{
get
{
return highData_;
}
set
{
highData_ = value;
}
}
private object highData_ = null;
/// <summary>
/// Gets or sets the data, or column name for the close values.
/// </summary>
public object CloseData
{
get
{
return closeData_;
}
set
{
closeData_ = value;
}
}
private object closeData_ = null;
/// <summary>
/// Gets or sets the data, or column name for the abscissa [x] axis.
/// </summary>
public object AbscissaData
{
get
{
return abscissaData_;
}
set
{
abscissaData_ = value;
}
}
private object abscissaData_ = null;
/// <summary>
/// Draws a representation of this plot in the legend.
/// </summary>
/// <param name="g">The graphics surface on which to draw.</param>
/// <param name="startEnd">A rectangle specifying the bounds of the area in the legend set aside for drawing.</param>
public virtual void DrawInLegend( Graphics g, Rectangle startEnd )
{
Pen p = new Pen(this.color_);
g.DrawLine( p, startEnd.Left, (startEnd.Top + startEnd.Bottom)/2,
startEnd.Right, (startEnd.Top + startEnd.Bottom)/2 );
}
/// <summary>
/// Color of this plot [excluding interior of filled boxes if Style is fill]. To
/// change the Bullish and Bearish colours in Filled mode, use the BullishColor
/// and BearishColor properties.
/// </summary>
public System.Drawing.Color Color
{
get
{
return color_;
}
set
{
color_ = value;
}
}
Color color_ = Color.Black;
/// <summary>
/// Possible CandleStick styles.
/// </summary>
public enum Styles
{
/// <summary>
/// Draw vertical line between low and high, tick on left for open and tick on right for close.
/// </summary>
Stick,
/// <summary>
/// Draw vertical line between low and high and place on top of this a box with bottom
/// and top determined by open and high values. The box is filled using the colors specified
/// in BullishColor and BearishColor properties.
/// </summary>
Filled
}
/// <summary>
/// Specifies the CandleStick style to use.
/// </summary>
public Styles Style = Styles.Filled;
/// <summary>
/// If CandlePlot.Style is Filled, then bullish open-close moves are displayed in this color.
/// </summary>
public Color BullishColor = Color.White;
/// <summary>
/// If CandlePlot.Style is Filled, then bearish moves are displayed in this color.
/// </summary>
public Color BearishColor = Color.Black;
/// <summary>
/// Width of each stick in pixels. It is best if this is an odd number.
/// </summary>
public int StickWidth
{
get
{
return stickWidth_;
}
set
{
if (value < 1)
{
throw new NPlotException( "Stick width must be greater than 0." );
}
stickWidth_ = value;
}
}
private int stickWidth_ = AutoScaleStickWidth;
/// <summary>
/// If stick width is set equal to this value, the width will be
/// automatically scaled dependant on the space between sticks.
/// </summary>
public const int AutoScaleStickWidth = 0;
/// <summary>
/// If true (default), bars will be centered on the abscissa times.
/// If false, bars will be drawn between the corresponding abscissa time
/// and the next abscissa time.
/// </summary>
/// <value></value>
public bool Centered
{
get
{
return centered_;
}
set
{
centered_ = value;
}
}
private bool centered_ = true;
/// <summary>
/// Write data associated with the plot as text.
/// </summary>
/// <param name="sb">the string builder to write to.</param>
/// <param name="region">Only write out data in this region if onlyInRegion is true.</param>
/// <param name="onlyInRegion">If true, only data in region is written, else all data is written.</param>
/// <remarks>TODO: not implemented.</remarks>
public void WriteData( System.Text.StringBuilder sb, RectangleD region, bool onlyInRegion )
{
}
}
}

702
lib/DateTimeAxis.cs Normal file
Просмотреть файл

@ -0,0 +1,702 @@
/*
NPlot - A charting library for .NET
DateTimeAxis.cs
Copyright (C) 2003
Matt Howlett
Redistribution and use of NPlot or parts there-of in source and
binary forms, with or without modification, are permitted provided
that the following conditions are met:
1. Re-distributions in source form must retain at the head of each
source file the above copyright notice, this list of conditions
and the following disclaimer.
2. Any product ("the product") that makes use NPlot or parts
there-of must either:
(a) allow any user of the product to obtain a complete machine-
readable copy of the corresponding source code for the
product and the version of NPlot used for a charge no more
than your cost of physically performing source distribution,
on a medium customarily used for software interchange, or:
(b) reproduce the following text in the documentation, about
box or other materials intended to be read by human users
of the product that is provided to every human user of the
product:
"This product includes software developed as
part of the NPlot library project available
from: http://www.nplot.com/"
The words "This product" may optionally be replace with
the actual name of the product.
------------------------------------------------------------------------
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
using System;
using System.Drawing;
using System.Collections;
using System.Globalization;
// TODO: More control over how labels are displayed.
// TODO: SkipWeekends property.
// TODO: Make a relative (as opposed to absolute) TimeAxis.
namespace NPlot
{
/// <summary>
/// The DateTimeAxis class
/// </summary>
public class DateTimeAxis : Axis
{
#region Clone implementation
/// <summary>
/// Deep copy of DateTimeAxis.
/// </summary>
/// <returns>A copy of the DateTimeAxis Class.</returns>
public override object Clone()
{
DateTimeAxis a = new DateTimeAxis();
// ensure that this isn't being called on a derived type. If it is, then oh no!
if (this.GetType() != a.GetType())
{
throw new NPlotException( "Clone not defined in derived type. Help!" );
}
DoClone( this, a );
return a;
}
/// <summary>
/// Helper method for Clone.
/// </summary>
/// <param name="a">The original object to clone.</param>
/// <param name="b">The cloned object.</param>
protected static void DoClone( DateTimeAxis b, DateTimeAxis a )
{
Axis.DoClone( b, a );
}
#endregion
private void Init()
{
}
/// <summary>
/// Constructor
/// </summary>
/// <param name="a">Axis to construct from</param>
public DateTimeAxis( Axis a )
: base( a )
{
this.Init();
this.NumberFormat = null;
}
/// <summary>
/// Default Constructor
/// </summary>
public DateTimeAxis()
: base()
{
this.Init();
}
/// <summary>
/// Constructor
/// </summary>
/// <param name="worldMin">World min of axis</param>
/// <param name="worldMax">World max of axis</param>
public DateTimeAxis( double worldMin, double worldMax )
: base( worldMin, worldMax )
{
this.Init();
}
/// <summary>
/// Constructor
/// </summary>
/// <param name="worldMin">World min of axis</param>
/// <param name="worldMax">World max of axis</param>
public DateTimeAxis( long worldMin, long worldMax )
: base( (double)worldMin, (double)worldMax )
{
this.Init();
}
/// <summary>
/// Constructor
/// </summary>
/// <param name="worldMin">World min of axis</param>
/// <param name="worldMax">World max of axis</param>
public DateTimeAxis( DateTime worldMin, DateTime worldMax )
: base( (double)worldMin.Ticks, (double)worldMax.Ticks )
{
this.Init();
}
/// <summary>
/// Draw the ticks.
/// </summary>
/// <param name="g">The drawing surface on which to draw.</param>
/// <param name="physicalMin">The minimum physical extent of the axis.</param>
/// <param name="physicalMax">The maximum physical extent of the axis.</param>
/// <param name="boundingBox">out: smallest box that completely encompasses all of the ticks and tick labels.</param>
/// <param name="labelOffset">out: a suitable offset from the axis to draw the axis label.</param>
protected override void DrawTicks(
Graphics g,
Point physicalMin,
Point physicalMax,
out object labelOffset,
out object boundingBox )
{
// TODO: Look at offset and bounding box logic again here. why temp and other vars?
Point tLabelOffset;
Rectangle tBoundingBox;
labelOffset = this.getDefaultLabelOffset( physicalMin, physicalMax );
boundingBox = null;
ArrayList largeTicks;
ArrayList smallTicks;
this.WorldTickPositions( physicalMin, physicalMax, out largeTicks, out smallTicks );
// draw small ticks.
for (int i=0; i<smallTicks.Count; ++i)
{
this.DrawTick( g, (double)smallTicks[i],
this.SmallTickSize, "", new Point(0, 0),
physicalMin, physicalMax,
out tLabelOffset, out tBoundingBox );
// assume label offset and bounding box unchanged by small tick bounds.
}
// draw large ticks.
for (int i=0; i<largeTicks.Count; ++i)
{
DateTime tickDate = new DateTime( (long)((double)largeTicks[i]) );
string label = LargeTickLabel(tickDate);
this.DrawTick( g, (double)largeTicks[i],
this.LargeTickSize, label, new Point( 0, 0 ),
physicalMin, physicalMax, out tLabelOffset, out tBoundingBox );
Axis.UpdateOffsetAndBounds( ref labelOffset, ref boundingBox, tLabelOffset, tBoundingBox );
}
}
/// <summary>
/// Get the label corresponding to the provided date time
/// </summary>
/// <param name="tickDate">the date time to get the label for</param>
/// <returns>label for the provided DateTime</returns>
protected virtual string LargeTickLabel(DateTime tickDate)
{
string label = "";
if(this.NumberFormat == null || this.NumberFormat == String.Empty)
{
if ( this.LargeTickLabelType_ == LargeTickLabelType.year )
{
label = tickDate.Year.ToString();
}
else if ( this.LargeTickLabelType_ == LargeTickLabelType.month )
{
label = tickDate.ToString("MMM");
label += " ";
label += tickDate.Year.ToString().Substring(2,2);
}
else if ( this.LargeTickLabelType_ == LargeTickLabelType.day )
{
label = (tickDate.Day).ToString();
label += " ";
label += tickDate.ToString("MMM");
}
else if ( this.LargeTickLabelType_ == LargeTickLabelType.hourMinute )
{
string minutes = tickDate.Minute.ToString();
if (minutes.Length == 1)
{
minutes = "0" + minutes;
}
label = tickDate.Hour.ToString() + ":" + minutes;
}
else if ( this.LargeTickLabelType_ == LargeTickLabelType.hourMinuteSeconds )
{
string minutes = tickDate.Minute.ToString();
string seconds = tickDate.Second.ToString();
if (seconds.Length == 1)
{
seconds = "0" + seconds;
}
if (minutes.Length == 1)
{
minutes = "0" + minutes;
}
label = tickDate.Hour.ToString() + ":" + minutes + "." + seconds;
}
}
else
{
label = tickDate.ToString(NumberFormat);
}
return label;
}
/// <summary>
/// Enumerates the different types of tick label possible.
/// </summary>
protected enum LargeTickLabelType
{
/// <summary>
/// default - no tick labels.
/// </summary>
none = 0,
/// <summary>
/// tick labels should be years
/// </summary>
year = 1,
/// <summary>
/// Tick labels should be month names
/// </summary>
month = 2,
/// <summary>
/// Tick labels should be day names
/// </summary>
day = 3,
/// <summary>
/// Tick labels should be hour / minutes.
/// </summary>
hourMinute = 4,
/// <summary>
/// tick labels should be hour / minute / second.
/// </summary>
hourMinuteSeconds = 5
}
/// <summary>
/// this gets set after a get LargeTickPositions.
/// </summary>
protected LargeTickLabelType LargeTickLabelType_;
/// <summary>
/// Determines the positions, in world coordinates, of the large ticks. No
/// small tick marks are currently calculated by this method.
///
/// </summary>
/// <param name="physicalMin">The physical position corresponding to the world minimum of the axis.</param>
/// <param name="physicalMax">The physical position corresponding to the world maximum of the axis.</param>
/// <param name="largeTickPositions">ArrayList containing the positions of the large ticks.</param>
/// <param name="smallTickPositions">null</param>
internal override void WorldTickPositions_FirstPass(
Point physicalMin,
Point physicalMax,
out ArrayList largeTickPositions,
out ArrayList smallTickPositions
)
{
smallTickPositions = null;
largeTickPositions = new ArrayList();
const int daysInMonth = 30;
TimeSpan timeLength = new TimeSpan( (long)(WorldMax-WorldMin));
DateTime worldMinDate = new DateTime( (long)this.WorldMin );
DateTime worldMaxDate = new DateTime( (long)this.WorldMax );
if(largeTickStep_ == TimeSpan.Zero)
{
// if less than 10 minutes, then large ticks on second spacings.
if ( timeLength < new TimeSpan(0,0,2,0,0) )
{
this.LargeTickLabelType_ = LargeTickLabelType.hourMinuteSeconds;
double secondsSkip;
if (timeLength < new TimeSpan( 0,0,0,10,0 ) )
secondsSkip = 1.0;
else if ( timeLength < new TimeSpan(0,0,0,20,0) )
secondsSkip = 2.0;
else if ( timeLength < new TimeSpan(0,0,0,50,0) )
secondsSkip = 5.0;
else if ( timeLength < new TimeSpan(0,0,2,30,0) )
secondsSkip = 15.0;
else
secondsSkip = 30.0;
int second = worldMinDate.Second;
second -= second % (int)secondsSkip;
DateTime currentTickDate = new DateTime(
worldMinDate.Year,
worldMinDate.Month,
worldMinDate.Day,
worldMinDate.Hour,
worldMinDate.Minute,
second,0 );
while ( currentTickDate < worldMaxDate )
{
double world = (double)currentTickDate.Ticks;
if ( world >= this.WorldMin && world <= this.WorldMax )
{
largeTickPositions.Add( world );
}
currentTickDate = currentTickDate.AddSeconds( secondsSkip );
}
}
// Less than 2 hours, then large ticks on minute spacings.
else if ( timeLength < new TimeSpan(0,2,0,0,0) )
{
this.LargeTickLabelType_ = LargeTickLabelType.hourMinute;
double minuteSkip;
if ( timeLength < new TimeSpan(0,0,10,0,0) )
minuteSkip = 1.0;
else if ( timeLength < new TimeSpan(0,0,20,0,0) )
minuteSkip = 2.0;
else if ( timeLength < new TimeSpan(0,0,50,0,0) )
minuteSkip = 5.0;
else if ( timeLength < new TimeSpan(0,2,30,0,0) )
minuteSkip = 15.0;
else //( timeLength < new TimeSpan( 0,5,0,0,0) )
minuteSkip = 30.0;
int minute = worldMinDate.Minute;
minute -= minute % (int)minuteSkip;
DateTime currentTickDate = new DateTime(
worldMinDate.Year,
worldMinDate.Month,
worldMinDate.Day,
worldMinDate.Hour,
minute,0,0 );
while ( currentTickDate < worldMaxDate )
{
double world = (double)currentTickDate.Ticks;
if ( world >= this.WorldMin && world <= this.WorldMax )
{
largeTickPositions.Add( world );
}
currentTickDate = currentTickDate.AddMinutes( minuteSkip );
}
}
// Less than 2 days, then large ticks on hour spacings.
else if ( timeLength < new TimeSpan(2,0,0,0,0) )
{
this.LargeTickLabelType_ = LargeTickLabelType.hourMinute;
double hourSkip;
if ( timeLength < new TimeSpan(0,10,0,0,0) )
hourSkip = 1.0;
else if ( timeLength < new TimeSpan(0,20,0,0,0) )
hourSkip = 2.0;
else
hourSkip = 6.0;
int hour = worldMinDate.Hour;
hour -= hour % (int)hourSkip;
DateTime currentTickDate = new DateTime(
worldMinDate.Year,
worldMinDate.Month,
worldMinDate.Day,
hour,0,0,0 );
while ( currentTickDate < worldMaxDate )
{
double world = (double)currentTickDate.Ticks;
if ( world >= this.WorldMin && world <= this.WorldMax )
{
largeTickPositions.Add( world );
}
currentTickDate = currentTickDate.AddHours( hourSkip );
}
}
// less than 5 months, then large ticks on day spacings.
else if ( timeLength < new TimeSpan(daysInMonth*4,0,0,0,0))
{
this.LargeTickLabelType_ = LargeTickLabelType.day;
double daySkip;
if ( timeLength < new TimeSpan(10,0,0,0,0) )
daySkip = 1.0;
else if (timeLength < new TimeSpan(20,0,0,0,0) )
daySkip = 2.0;
else if (timeLength < new TimeSpan(7*10,0,0,0,0) )
daySkip = 7.0;
else
daySkip = 14.0;
DateTime currentTickDate = new DateTime(
worldMinDate.Year,
worldMinDate.Month,
worldMinDate.Day );
if (daySkip == 2.0)
{
TimeSpan timeSinceBeginning = currentTickDate - DateTime.MinValue;
if (timeSinceBeginning.Days % 2 == 1)
currentTickDate = currentTickDate.AddDays(-1.0);
}
if (daySkip == 7 || daySkip == 14.0)
{
DayOfWeek dow = currentTickDate.DayOfWeek;
switch (dow)
{
case DayOfWeek.Monday:
break;
case DayOfWeek.Tuesday:
currentTickDate = currentTickDate.AddDays(-1.0);
break;
case DayOfWeek.Wednesday:
currentTickDate = currentTickDate.AddDays(-2.0);
break;
case DayOfWeek.Thursday:
currentTickDate = currentTickDate.AddDays(-3.0);
break;
case DayOfWeek.Friday:
currentTickDate = currentTickDate.AddDays(-4.0);
break;
case DayOfWeek.Saturday:
currentTickDate = currentTickDate.AddDays(-5.0);
break;
case DayOfWeek.Sunday:
currentTickDate = currentTickDate.AddDays(-6.0);
break;
}
}
if (daySkip == 14.0f)
{
TimeSpan timeSinceBeginning = currentTickDate - DateTime.MinValue;
if ((timeSinceBeginning.Days / 7) % 2 == 1)
{
currentTickDate = currentTickDate.AddDays(-7.0);
}
}
while ( currentTickDate < worldMaxDate )
{
double world = (double)currentTickDate.Ticks;
if ( world >= this.WorldMin && world <= this.WorldMax )
{
largeTickPositions.Add( world );
}
currentTickDate = currentTickDate.AddDays(daySkip);
}
}
// else ticks on month or year spacings.
else if ( timeLength >= new TimeSpan(daysInMonth*4,0,0,0,0) )
{
int monthSpacing = 0;
if ( timeLength.Days < daysInMonth*(12*3+6) )
{
LargeTickLabelType_ = LargeTickLabelType.month;
if ( timeLength.Days < daysInMonth*10 )
monthSpacing = 1;
else if ( timeLength.Days < daysInMonth*(12*2) )
monthSpacing = 3;
else // if ( timeLength.Days < daysInMonth*(12*3+6) )
monthSpacing = 6;
}
else
{
LargeTickLabelType_ = LargeTickLabelType.year;
if (timeLength.Days < daysInMonth * (12 * 6))
monthSpacing = 12;
else if (timeLength.Days < daysInMonth * (12 * 12))
monthSpacing = 24;
else if (timeLength.Days < daysInMonth * (12 * 30))
monthSpacing = 60;
else
monthSpacing = 120;
//LargeTickLabelType_ = LargeTickLabelType.none;
}
// truncate start
DateTime currentTickDate = new DateTime(
worldMinDate.Year,
worldMinDate.Month,
1 );
if (monthSpacing > 1)
{
currentTickDate = currentTickDate.AddMonths(
-(currentTickDate.Month-1)%monthSpacing );
}
// Align on 2 or 5 year boundaries if necessary.
if (monthSpacing >= 24)
{
currentTickDate = currentTickDate.AddYears(
-(currentTickDate.Year)%(monthSpacing/12) );
}
//this.firstLargeTick_ = (double)currentTickDate.Ticks;
if ( LargeTickLabelType_ != LargeTickLabelType.none )
{
while ( currentTickDate < worldMaxDate )
{
double world = (double)currentTickDate.Ticks;
if ( world >= this.WorldMin && world <= this.WorldMax )
{
largeTickPositions.Add( world );
}
currentTickDate = currentTickDate.AddMonths( monthSpacing );
}
}
}
}
else
{
for (DateTime date = worldMinDate; date < worldMaxDate; date += largeTickStep_)
{
largeTickPositions.Add((double)date.Ticks);
}
}
}
/// <summary>
/// Compute the small tick positions for largetick size of one or more years.
/// - inside the domain or the large tick positons, is take the mid-point of pairs of large ticks
/// - outside the large tick range, check if a half tick is inside the world min/max
/// This method works only if there are atleast 2 large ticks,
/// since we don't know if its minutes, hours, month, or yearly divisor.
/// </summary>
/// <param name="physicalMin">The physical position corresponding to the world minimum of the axis.</param>
/// <param name="physicalMax">The physical position corresponding to the world maximum of the axis.</param>
/// <param name="largeTickPositions">Read in the large tick positions</param>
/// <param name="smallTickPositions">Fill in the corresponding small tick positions</param>
/// <remarks>Added by Rosco Hill</remarks>
internal override void WorldTickPositions_SecondPass(
Point physicalMin,
Point physicalMax,
ArrayList largeTickPositions,
ref ArrayList smallTickPositions
)
{
if (largeTickPositions.Count < 2 || !(LargeTickLabelType_.Equals(LargeTickLabelType.year)))
{
smallTickPositions = new ArrayList(); ;
}
else
{
smallTickPositions = new ArrayList();
double diff = 0.5 * (((double)largeTickPositions[1]) - ((double)largeTickPositions[0]));
if (((double)largeTickPositions[0] - diff) > this.WorldMin)
{
smallTickPositions.Add((double)largeTickPositions[0] - diff);
}
for (int i = 0; i < largeTickPositions.Count - 1; i++)
{
smallTickPositions.Add(((double)largeTickPositions[i]) + diff);
}
if (((double)largeTickPositions[largeTickPositions.Count - 1] + diff) < this.WorldMax)
{
smallTickPositions.Add((double)largeTickPositions[largeTickPositions.Count - 1] + diff);
}
}
}
/// <summary>
/// The distance between large ticks. If this is set to Zero [default],
/// this distance will be calculated automatically.
/// </summary>
public TimeSpan LargeTickStep
{
set
{
largeTickStep_ = value;
}
get
{
return largeTickStep_;
}
}
private TimeSpan largeTickStep_ = TimeSpan.Zero;
}
}

179
lib/ErrorHandler.cs Normal file
Просмотреть файл

@ -0,0 +1,179 @@
/*
NPlot - A charting library for .NET
ErrorHandler.cs
Copyright (C) 2004
Matt Howlett
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the following text in
the documentation and / or other materials provided with the
distribution:
"This product includes software developed as part of
the NPlot charting library project available from:
http://www.nplot.com/"
------------------------------------------------------------------------
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
$Id: ErrorHandler.cs,v 1.2 2004/11/04 12:18:24 mhowlett Exp $
*/
using System;
using System.Diagnostics;
namespace NPlot
{
/// <summary>
/// Error class that
/// (a) adds source of problem.
/// (b) by default throws exception.
/// (c) default behaviour can be overridden.
/// </summary>
public class ErrorHandler
{
/// <summary>
/// The singular ErrorHandler instance
/// </summary>
public static readonly ErrorHandler Instance = new ErrorHandler();
/// <summary>
/// Defines the allowed message levels.
/// </summary>
public enum Level
{
/// <summary>
/// Debugging Message. Note it's best not to use the general
/// handle method to emit these - use the conditional Debug
/// function.
/// </summary>
Debug = 0,
/// <summary>
/// Something went wrong, but code execution can continue.
/// </summary>
Continuing = 1,
/// <summary>
/// Something wend wrong, and code execution can not continue.
/// </summary>
Critical = 2
}
private delegate void HandlerDelegate( string message );
private HandlerDelegate[] handlers_;
private void HandleError( string message )
{
throw new System.Exception( message );
}
private void NullHandler( string message )
{
// do nothing.
}
private ErrorHandler()
{
// set up default
handlers_ = new HandlerDelegate[3];
handlers_[0] = new HandlerDelegate(HandleError);
handlers_[1] = new HandlerDelegate(HandleError);
handlers_[2] = new HandlerDelegate(HandleError);
}
/// <summary>
/// Handles a debug message.
/// </summary>
/// <param name="message">message to handle</param>
[Conditional("DEBUG")]
public void DebugError( string message )
{
handlers_[(int)Level.Debug]( GetPrepend() + message );
}
/// <summary>
/// Handles a continuing error.
/// </summary>
/// <param name="message">message to handle</param>
public void ContinuingError( string message )
{
handlers_[(int)Level.Continuing]( GetPrepend() + message );
}
/// <summary>
/// Handles a critical error.
/// </summary>
/// <param name="message">message to handle</param>
public void CriticalError( string message )
{
handlers_[(int)Level.Critical]( GetPrepend() + message );
}
/// <summary>
/// Handles a message of the given level.
/// </summary>
/// <param name="level">The message level.</param>
/// <param name="message">The message to handle.</param>
public void Handle( Level level, string message )
{
handlers_[(int)level]( GetPrepend() + message );
}
/// <summary>
/// Get text to prepend to log message to describe its origin. This is the first
/// place in stack outside Cts.Library.MessageLog.
/// </summary>
/// <returns>string to prepend to messages detailing its origin.</returns>
private string GetPrepend()
{
System.Diagnostics.StackTrace st = new StackTrace();
System.Diagnostics.StackFrame sf = null;
string prepend = "";
int i = 0;
while (i < st.FrameCount)
{
sf = st.GetFrame(i);
if ( sf.GetMethod().ReflectedType != this.GetType() )
{
break;
}
i += 1;
}
sf = st.GetFrame(i);
prepend =
"[" +
sf.GetMethod().ReflectedType +
"." +
sf.GetMethod().Name +
"] ";
return prepend;
}
}
}

203
lib/FilledRegion.cs Normal file
Просмотреть файл

@ -0,0 +1,203 @@
/*
NPlot - A charting library for .NET
FilledRegion.cs
Copyright (C) 2004
Matt Howlett
Redistribution and use of NPlot or parts there-of in source and
binary forms, with or without modification, are permitted provided
that the following conditions are met:
1. Re-distributions in source form must retain at the head of each
source file the above copyright notice, this list of conditions
and the following disclaimer.
2. Any product ("the product") that makes use NPlot or parts
there-of must either:
(a) allow any user of the product to obtain a complete machine-
readable copy of the corresponding source code for the
product and the version of NPlot used for a charge no more
than your cost of physically performing source distribution,
on a medium customarily used for software interchange, or:
(b) reproduce the following text in the documentation, about
box or other materials intended to be read by human users
of the product that is provided to every human user of the
product:
"This product includes software developed as
part of the NPlot library project available
from: http://www.nplot.com/"
The words "This product" may optionally be replace with
the actual name of the product.
------------------------------------------------------------------------
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
using System;
using System.Drawing;
namespace NPlot
{
/// <summary>
/// A quick and dirty Filled region plottable object
/// </summary>
public class FilledRegion : IDrawable
{
/// <summary>
/// Constructor
/// </summary>
/// <param name="lp1">LinePlot that provides bounds to filled region [upper or lower]</param>
/// <param name="lp2">LinePlot that provides bounds to filled region [upper or lower]</param>
/// <remarks>TODO: make this work with other plot types.</remarks>
public FilledRegion( LinePlot lp1, LinePlot lp2 )
{
lp1_ = lp1;
lp2_ = lp2;
}
/// <summary>
/// Constructor
/// </summary>
/// <param name="l1">Vertical line to provide bounds for filled region</param>
/// <param name="l2">The other Vertical line to provide bounds for filled region</param>
public FilledRegion(VerticalLine l1, VerticalLine l2)
{
vl1_ = l1;
vl2_ = l2;
}
/// <summary>
/// Constructor
/// </summary>
/// <param name="l1">Vertical line to provide bounds for filled region</param>
/// <param name="l2">The other Vertical line to provide bounds for filled region</param>
public FilledRegion(HorizontalLine l1, HorizontalLine l2)
{
hl1_ = l1;
hl2_ = l2;
}
/// <summary>
/// Draw the filled region
/// </summary>
/// <param name="g">The GDI+ surface on which to draw.</param>
/// <param name="xAxis">The X-Axis to draw against.</param>
/// <param name="yAxis">The Y-Axis to draw against.</param>
public void Draw( System.Drawing.Graphics g, PhysicalAxis xAxis, PhysicalAxis yAxis )
{
ITransform2D t = Transform2D.GetTransformer(xAxis, yAxis);
Brush b = brush_;
if (b == null)
{
b = areaBrush_.Get(new Rectangle(xAxis.PhysicalMin.X, yAxis.PhysicalMax.Y, xAxis.PhysicalLength, yAxis.PhysicalLength));
}
if (hl1_ != null && hl2_ != null)
{
PointF[] points = new PointF[4];
points[0] = t.Transform(xAxis.Axis.WorldMin, hl1_.OrdinateValue);
points[1] = t.Transform(xAxis.Axis.WorldMax, hl1_.OrdinateValue);
points[2] = t.Transform(xAxis.Axis.WorldMax, hl2_.OrdinateValue);
points[3] = t.Transform(xAxis.Axis.WorldMin, hl2_.OrdinateValue);
g.FillPolygon(b, points);
}
else if (vl1_ != null && vl2_ != null)
{
PointF[] points = new PointF[4];
points[0] = t.Transform(vl1_.AbscissaValue, yAxis.Axis.WorldMin);
points[1] = t.Transform(vl1_.AbscissaValue, yAxis.Axis.WorldMax);
points[2] = t.Transform(vl2_.AbscissaValue, yAxis.Axis.WorldMax);
points[3] = t.Transform(vl2_.AbscissaValue, yAxis.Axis.WorldMin);
g.FillPolygon(b, points);
}
else if (lp1_ != null && lp2_ != null)
{
SequenceAdapter a1 = new SequenceAdapter(lp1_.DataSource, lp1_.DataMember, lp1_.OrdinateData, lp1_.AbscissaData);
SequenceAdapter a2 = new SequenceAdapter(lp2_.DataSource, lp2_.DataMember, lp2_.OrdinateData, lp2_.AbscissaData);
int count = a1.Count + a2.Count;
PointF[] points = new PointF[count];
for (int i = 0; i < a1.Count; ++i)
{
points[i] = t.Transform(a1[i]);
}
for (int i = 0; i < a2.Count; ++i)
{
points[i + a1.Count] = t.Transform(a2[a2.Count - i - 1]);
}
g.FillPolygon(b, points);
}
else
{
throw new NPlotException("One of bounds was set to null");
}
}
/// <summary>
/// Use this brush (and not a RectangleBrush) for drawing.
/// </summary>
public Brush Brush
{
set
{
brush_ = value;
areaBrush_ = null;
}
}
/// <summary>
/// Use this RectangleBrush (and not a normal Brush) for drawing.
/// </summary>
public IRectangleBrush RectangleBrush
{
set
{
brush_ = null;
areaBrush_ = value;
}
}
private VerticalLine vl1_;
private VerticalLine vl2_;
private HorizontalLine hl1_;
private HorizontalLine hl2_;
private LinePlot lp1_;
private LinePlot lp2_;
private Brush brush_ = new SolidBrush( Color.GhostWhite );
private IRectangleBrush areaBrush_ = null;
}
}

46
lib/FontScaler.cs Normal file
Просмотреть файл

@ -0,0 +1,46 @@
/*
NPlot - A charting library for .NET
FontScaler.cs
Copyright (C) 2003
Matt Howlett
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the following text in
the documentation and / or other materials provided with the
distribution:
"This product includes software developed as part of
the NPlot charting library project available from:
http://www.nplot.com/"
------------------------------------------------------------------------
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
$Id: FontScaler.cs,v 1.10 2004/11/04 12:18:24 mhowlett Exp $
*/
using System;
using System.Drawing;
namespace NPlot
{
}

248
lib/Grid.cs Normal file
Просмотреть файл

@ -0,0 +1,248 @@
/*
NPlot - A charting library for .NET
Grid.cs
Copyright (C) 2003
Matt Howlett
Redistribution and use of NPlot or parts there-of in source and
binary forms, with or without modification, are permitted provided
that the following conditions are met:
1. Re-distributions in source form must retain at the head of each
source file the above copyright notice, this list of conditions
and the following disclaimer.
2. Any product ("the product") that makes use NPlot or parts
there-of must either:
(a) allow any user of the product to obtain a complete machine-
readable copy of the corresponding source code for the
product and the version of NPlot used for a charge no more
than your cost of physically performing source distribution,
on a medium customarily used for software interchange, or:
(b) reproduce the following text in the documentation, about
box or other materials intended to be read by human users
of the product that is provided to every human user of the
product:
"This product includes software developed as
part of the NPlot library project available
from: http://www.nplot.com/"
The words "This product" may optionally be replace with
the actual name of the product.
------------------------------------------------------------------------
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
using System;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Collections;
namespace NPlot
{
/// <summary>
/// Encapsulates a Grid IDrawable object. Instances of this to a PlotSurface2D
/// instance to produce a grid.
/// </summary>
public class Grid : IDrawable
{
/// <summary>
///
/// </summary>
public enum GridType
{
/// <summary>
/// No grid.
/// </summary>
None = 0,
/// <summary>
/// Coarse grid. Lines at large tick positions only.
/// </summary>
Coarse = 1,
/// <summary>
/// Fine grid. Lines at both large and small tick positions.
/// </summary>
Fine = 2
}
/// <summary>
/// Default constructor
/// </summary>
public Grid()
{
minorGridPen_ = new Pen( Color.LightGray );
float[] pattern = {1.0f, 2.0f};
minorGridPen_.DashPattern = pattern;
majorGridPen_ = new Pen( Color.LightGray );
horizontalGridType_ = GridType.Coarse;
verticalGridType_ = GridType.Coarse;
}
/// <summary>
/// Specifies the horizontal grid type (none, coarse or fine).
/// </summary>
public GridType HorizontalGridType
{
get
{
return horizontalGridType_;
}
set
{
horizontalGridType_ = value;
}
}
GridType horizontalGridType_;
/// <summary>
/// Specifies the vertical grid type (none, coarse, or fine).
/// </summary>
public GridType VerticalGridType
{
get
{
return verticalGridType_;
}
set
{
verticalGridType_ = value;
}
}
GridType verticalGridType_;
/// <summary>
/// The pen used to draw major (coarse) grid lines.
/// </summary>
public System.Drawing.Pen MajorGridPen
{
get
{
return majorGridPen_;
}
set
{
majorGridPen_ = value;
}
}
private Pen majorGridPen_;
/// <summary>
/// The pen used to draw minor (fine) grid lines.
/// </summary>
public System.Drawing.Pen MinorGridPen
{
get
{
return minorGridPen_;
}
set
{
minorGridPen_ = value;
}
}
private Pen minorGridPen_;
/// <summary>
/// Does all the work in drawing grid lines.
/// </summary>
/// <param name="g">The graphics surface on which to render.</param>
/// <param name="axis">TODO</param>
/// <param name="orthogonalAxis">TODO</param>
/// <param name="a">the list of world values to draw grid lines at.</param>
/// <param name="horizontal">true if want horizontal lines, false otherwise.</param>
/// <param name="p">the pen to use to draw the grid lines.</param>
private void DrawGridLines(
Graphics g, PhysicalAxis axis, PhysicalAxis orthogonalAxis,
System.Collections.ArrayList a, bool horizontal, Pen p )
{
for (int i=0; i<a.Count; ++i)
{
PointF p1 = axis.WorldToPhysical((double)a[i], true);
PointF p2 = p1;
PointF p3 = orthogonalAxis.PhysicalMax;
PointF p4 = orthogonalAxis.PhysicalMin;
if (horizontal)
{
p1.Y = p4.Y;
p2.Y = p3.Y;
}
else
{
p1.X = p4.X;
p2.X = p3.X;
}
// note: casting all drawing was necessary for sane display. why?
g.DrawLine( p, (int)p1.X, (int)p1.Y, (int)p2.X, (int)p2.Y );
}
}
/// <summary>
/// Draws the grid
/// </summary>
/// <param name="g">The graphics surface on which to draw</param>
/// <param name="xAxis">The physical x axis to draw horizontal lines parallel to.</param>
/// <param name="yAxis">The physical y axis to draw vertical lines parallel to.</param>
public void Draw( Graphics g, PhysicalAxis xAxis, PhysicalAxis yAxis )
{
ArrayList xLargePositions = null;
ArrayList yLargePositions = null;
ArrayList xSmallPositions = null;
ArrayList ySmallPositions = null;
if (this.horizontalGridType_ != GridType.None)
{
xAxis.Axis.WorldTickPositions_FirstPass( xAxis.PhysicalMin, xAxis.PhysicalMax, out xLargePositions, out xSmallPositions );
DrawGridLines( g, xAxis, yAxis, xLargePositions, true, this.MajorGridPen );
}
if (this.verticalGridType_ != GridType.None)
{
yAxis.Axis.WorldTickPositions_FirstPass( yAxis.PhysicalMin, yAxis.PhysicalMax, out yLargePositions, out ySmallPositions );
DrawGridLines( g, yAxis, xAxis, yLargePositions, false, this.MajorGridPen );
}
if (this.horizontalGridType_ == GridType.Fine)
{
xAxis.Axis.WorldTickPositions_SecondPass( xAxis.PhysicalMin, xAxis.PhysicalMax, xLargePositions, ref xSmallPositions );
DrawGridLines( g, xAxis, yAxis, xSmallPositions, true, this.MinorGridPen );
}
if (this.verticalGridType_ == GridType.Fine)
{
yAxis.Axis.WorldTickPositions_SecondPass( yAxis.PhysicalMin, yAxis.PhysicalMax, yLargePositions, ref ySmallPositions );
DrawGridLines( g, yAxis, xAxis, ySmallPositions, false, this.MinorGridPen );
}
}
}
}

303
lib/Gtk.PlotSurface2D.cs Normal file
Просмотреть файл

@ -0,0 +1,303 @@
using System;
using System.Collections;
using System.ComponentModel;
using System.Data;
using Gtk;
using System.Drawing;
namespace NPlot { namespace Gtk {
public class PlotSurface2D : DrawingArea, IPlotSurface2D {
NPlot.PlotSurface2D ps;
/*Axis xAxis1Cache;
Axis yAxis1Cache;
Axis xAxis2Cache;
Axis yAxis2Cache;*/
// The cache.
System.Drawing.Bitmap bitmap_cache;
Gdk.Rectangle current_allocation; // The current allocation.
bool allocated = false;
public PlotSurface2D (IntPtr x) : base (x)
{
Console.WriteLine (Environment.StackTrace);
}
public PlotSurface2D ()
{
ps = new NPlot.PlotSurface2D ();
CanFocus = false;
SetSizeRequest (200, 200);
}
public void Refresh ()
{
UpdateCache ();
QueueDrawArea (0, 0, Allocation.Width, Allocation.Height);
}
protected override bool OnExposeEvent (Gdk.EventExpose args)
{
Gdk.Rectangle area = args.Area;
Console.WriteLine (area);
using (Graphics g = Gdk.Graphics.FromDrawable (args.Window)){
Rectangle bounds = new Rectangle (area.X, area.Y, area.Width, area.Height);
g.DrawImage (bitmap_cache, bounds, bounds, GraphicsUnit.Pixel);
}
return true;
}
protected override void OnSizeAllocated (Gdk.Rectangle allocation)
{
allocated = true;
current_allocation = allocation;
UpdateCache ();
base.OnSizeAllocated (allocation);
}
void UpdateCache ()
{
if (!allocated)
return;
if (bitmap_cache != null)
bitmap_cache.Dispose ();
bitmap_cache = new System.Drawing.Bitmap (current_allocation.Width, current_allocation.Height);
using (Graphics g = Graphics.FromImage (bitmap_cache)){
Rectangle bounds = new Rectangle (
0, 0, current_allocation.Width, current_allocation.Height);
ps.Draw (g, bounds);
}
}
#region IPlotSurface2D interface implementation
public void Add (IDrawable p, int zOrder)
{
ps.Add (p, zOrder);
}
public void Add (IDrawable p)
{
ps.Add (p);
}
public void Add (IDrawable p, NPlot.PlotSurface2D.XAxisPosition xp, NPlot.PlotSurface2D.YAxisPosition yp)
{
ps.Add (p, xp, yp);
}
public void Add (NPlot.IDrawable p, NPlot.PlotSurface2D.XAxisPosition xp, NPlot.PlotSurface2D.YAxisPosition yp, int zOrder)
{
ps.Add (p, xp, yp, zOrder);
}
public void Clear()
{
ps.Clear ();
}
public NPlot.Legend Legend {
get {
return ps.Legend;
}
set {
ps.Legend = value;
}
}
public int Padding {
get {
return ps.Padding;
}
set {
ps.Padding = value;
}
}
public int LegendZOrder {
get {
return ps.LegendZOrder;
}
set {
ps.LegendZOrder = value;
}
}
public System.Drawing.Color PlotBackColor {
set {
ps.PlotBackColor = value;
}
}
public System.Drawing.Bitmap PlotBackImage
{
set {
ps.PlotBackImage = value;
}
}
public IRectangleBrush PlotBackBrush
{
set {
ps.PlotBackBrush = value;
}
}
public Color TitleColor
{
set
{
ps.TitleColor = value;
}
}
public Brush TitleBrush
{
get
{
return ps.TitleBrush;
}
set
{
ps.TitleBrush = value;
}
}
/// <summary>
/// Gets an array list containing all drawables currently added to the PlotSurface2D.
/// </summary>
public ArrayList Drawables
{
get
{
return ps.Drawables;
}
}
public void Remove (IDrawable p, bool updateAxes)
{
ps.Remove(p, updateAxes);
}
public string Title {
get {
return ps.Title;
}
set {
ps.Title = value;
}
}
public System.Drawing.Font TitleFont {
get {
return ps.TitleFont;
}
set {
ps.TitleFont = value;
}
}
public System.Drawing.Drawing2D.SmoothingMode SmoothingMode {
get {
return ps.SmoothingMode;
}
set {
ps.SmoothingMode = value;
}
}
public void AddAxesConstraint (AxesConstraint c)
{
ps.AddAxesConstraint (c);
}
public Axis XAxis1 {
get {
return ps.XAxis1;
}
set
{
ps.XAxis1 = value;
}
}
public Axis YAxis1 {
get {
return ps.YAxis1;
}
set {
ps.YAxis1 = value;
}
}
public Axis XAxis2 {
get {
return ps.XAxis2;
}
set {
ps.XAxis2 = value;
}
}
public Axis YAxis2 {
get {
return ps.YAxis2;
}
set {
ps.YAxis2 = value;
}
}
public bool AutoScaleTitle {
get {
return ps.AutoScaleTitle;
}
set {
ps.AutoScaleTitle = value;
}
}
public bool AutoScaleAutoGeneratedAxes {
get {
return ps.AutoScaleAutoGeneratedAxes;
}
set {
ps.AutoScaleAutoGeneratedAxes = value;
}
}
public System.Drawing.Bitmap Bitmap {
get { return bitmap_cache;}
}
public int Width {
get { return current_allocation.Width; }
}
public int Height {
get { return current_allocation.Height;}
}
#endregion
} }
}

521
lib/HistogramPlot.cs Normal file
Просмотреть файл

@ -0,0 +1,521 @@
/*
NPlot - A charting library for .NET
HistogramPlot.cs
Copyright (C) 2003
Matt Howlett, Paolo Pierini
Redistribution and use of NPlot or parts there-of in source and
binary forms, with or without modification, are permitted provided
that the following conditions are met:
1. Re-distributions in source form must retain at the head of each
source file the above copyright notice, this list of conditions
and the following disclaimer.
2. Any product ("the product") that makes use NPlot or parts
there-of must either:
(a) allow any user of the product to obtain a complete machine-
readable copy of the corresponding source code for the
product and the version of NPlot used for a charge no more
than your cost of physically performing source distribution,
on a medium customarily used for software interchange, or:
(b) reproduce the following text in the documentation, about
box or other materials intended to be read by human users
of the product that is provided to every human user of the
product:
"This product includes software developed as
part of the NPlot library project available
from: http://www.nplot.com/"
The words "This product" may optionally be replace with
the actual name of the product.
------------------------------------------------------------------------
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
using System;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Collections;
namespace NPlot
{
/// <summary>
/// Provides ability to draw histogram plots.
/// </summary>
public class HistogramPlot : BaseSequencePlot, IPlot, ISequencePlot
{
/// <summary>
/// Set/Get the brush to use if the histogram is filled.
/// </summary>
public IRectangleBrush RectangleBrush
{
get
{
return rectangleBrush_;
}
set
{
rectangleBrush_ = value;
}
}
private IRectangleBrush rectangleBrush_ = new RectangleBrushes.Solid( Color.Black );
/// <summary>
/// Constructor
/// </summary>
public HistogramPlot()
{
}
/// <summary>
/// Renders the histogram.
/// </summary>
/// <param name="g">The Graphics surface on which to draw</param>
/// <param name="xAxis">The X-Axis to draw against.</param>
/// <param name="yAxis">The Y-Axis to draw against.</param>
public void Draw( Graphics g, PhysicalAxis xAxis, PhysicalAxis yAxis )
{
SequenceAdapter data =
new SequenceAdapter( this.DataSource, this.DataMember, this.OrdinateData, this.AbscissaData );
float yoff;
for ( int i=0; i<data.Count; ++i )
{
// (1) determine the top left hand point of the bar (assuming not centered)
PointD p1 = data[i];
if ( double.IsNaN(p1.X) || double.IsNaN(p1.Y) )
continue;
// (2) determine the top right hand point of the bar (assuming not centered)
PointD p2;
if (i+1 != data.Count)
{
p2 = data[i+1];
if ( double.IsNaN(p2.X) || double.IsNaN(p2.Y) )
continue;
p2.Y = p1.Y;
}
else if (i != 0)
{
p2 = data[i-1];
if ( double.IsNaN(p2.X) || double.IsNaN(p2.Y) )
continue;
double offset = p1.X - p2.X;
p2.X = p1.X + offset;
p2.Y = p1.Y;
}
else
{
double offset = 1.0f;
p2.X = p1.X + offset;
p2.Y = p1.Y;
}
// (3) now account for plots this may be stacked on top of.
HistogramPlot currentPlot = this;
yoff = 0.0f;
double yval = 0.0f;
while (currentPlot.isStacked_)
{
SequenceAdapter stackedToData = new SequenceAdapter(
currentPlot.stackedTo_.DataSource,
currentPlot.stackedTo_.DataMember,
currentPlot.stackedTo_.OrdinateData,
currentPlot.stackedTo_.AbscissaData );
yval += stackedToData[i].Y;
yoff = yAxis.WorldToPhysical( yval, false ).Y;
p1.Y += stackedToData[i].Y;
p2.Y += stackedToData[i].Y;
currentPlot = currentPlot.stackedTo_;
}
// (4) now account for centering
if ( center_ )
{
double offset = ( p2.X - p1.X ) / 2.0f;
p1.X -= offset;
p2.X -= offset;
}
// (5) now account for BaseOffset (shift of bar sideways).
p1.X += baseOffset_;
p2.X += baseOffset_;
// (6) now get physical coordinates of top two points.
PointF xPos1 = xAxis.WorldToPhysical( p1.X, false );
PointF yPos1 = yAxis.WorldToPhysical( p1.Y, false );
PointF xPos2 = xAxis.WorldToPhysical( p2.X, false );
PointF yPos2 = yAxis.WorldToPhysical( p2.Y, false );
if (isStacked_)
{
currentPlot = this;
while (currentPlot.isStacked_)
{
currentPlot = currentPlot.stackedTo_;
}
this.baseWidth_ = currentPlot.baseWidth_;
}
float width = xPos2.X - xPos1.X;
float height;
if (isStacked_)
{
height = -yPos1.Y+yoff;
}
else
{
height = -yPos1.Y+yAxis.PhysicalMin.Y;
}
float xoff = (1.0f - baseWidth_)/2.0f*width;
Rectangle r = new Rectangle( (int)(xPos1.X+xoff), (int)yPos1.Y, (int)(width-2*xoff), (int)height );
if (this.Filled)
{
if (r.Height != 0 && r.Width != 0)
{
// room for optimization maybe.
g.FillRectangle( rectangleBrush_.Get(r), r );
}
}
g.DrawRectangle( Pen, r.X, r.Y, r.Width, r.Height );
}
}
/// <summary>
/// Whether or not the histogram columns will be filled.
/// </summary>
public bool Filled
{
get
{
return filled_;
}
set
{
filled_ = value;
}
}
private bool filled_ = false;
private float baseWidth_ = 1.0f;
/// <summary>
/// The width of the histogram bar as a proportion of the data spacing
/// (in range 0.0 - 1.0).
/// </summary>
public float BaseWidth
{
get
{
return baseWidth_;
}
set
{
if (value > 0.0 && value <= 1.0)
{
baseWidth_ = value;
}
else
{
throw new NPlotException( "Base width must be between 0.0 and 1.0" );
}
}
}
/// <summary>
/// Returns an x-axis that is suitable for drawing this plot.
/// </summary>
/// <returns>A suitable x-axis.</returns>
public Axis SuggestXAxis()
{
SequenceAdapter data =
new SequenceAdapter( this.DataSource, this.DataMember, this.OrdinateData, this.AbscissaData );
Axis a = data.SuggestXAxis();
PointD p1;
PointD p2;
PointD p3;
PointD p4;
if (data.Count < 2)
{
p1 = data[0];
p1.X -= 1.0;
p2 = data[0];
p3 = p1;
p4 = p2;
}
else
{
p1 = data[0];
p2 = data[1];
p3 = data[data.Count-2];
p4 = data[data.Count-1];
}
double offset1;
double offset2;
if (!center_)
{
offset1 = 0.0f;
offset2 = p4.X - p3.X;
}
else
{
offset1 = (p2.X - p1.X)/2.0f;
offset2 = (p4.X - p3.X)/2.0f;
}
a.WorldMin -= offset1;
a.WorldMax += offset2;
return a;
}
/// <summary>
/// Returns a y-axis that is suitable for drawing this plot.
/// </summary>
/// <returns>A suitable y-axis.</returns>
public Axis SuggestYAxis()
{
if ( this.isStacked_ )
{
double tmpMax = 0.0f;
ArrayList adapterList = new ArrayList();
HistogramPlot currentPlot = this;
do
{
adapterList.Add( new SequenceAdapter(
currentPlot.DataSource,
currentPlot.DataMember,
currentPlot.OrdinateData,
currentPlot.AbscissaData )
);
} while ((currentPlot = currentPlot.stackedTo_) != null);
SequenceAdapter[] adapters =
(SequenceAdapter[])adapterList.ToArray(typeof(SequenceAdapter));
for (int i=0; i<adapters[0].Count; ++i)
{
double tmpHeight = 0.0f;
for (int j=0; j<adapters.Length; ++j)
{
tmpHeight += adapters[j][i].Y;
}
tmpMax = Math.Max(tmpMax, tmpHeight);
}
Axis a = new LinearAxis(0.0f,tmpMax);
// TODO make 0.08 a parameter.
a.IncreaseRange( 0.08 );
return a;
}
else
{
SequenceAdapter data =
new SequenceAdapter( this.DataSource, this.DataMember, this.OrdinateData, this.AbscissaData );
return data.SuggestYAxis();
}
}
/*
private double centerLine_ = 0.0;
/// <summary>
/// Histogram bars extend from the data value to this value. Default value is 0.
/// </summary>
public double CenterLine
{
get
{
return centerLine_;
}
set
{
centerLine_ = value;
}
}
*/
private bool center_ = true;
/// <summary>
/// If true, each histogram column will be centered on the associated abscissa value.
/// If false, each histogram colum will be drawn between the associated abscissa value, and the next abscissa value.
/// Default value is true.
/// </summary>
public bool Center
{
set
{
center_ = value;
}
get
{
return center_;
}
}
/// <summary>
/// If this histogram plot has another stacked on top, this will be true. Else false.
/// </summary>
public bool IsStacked
{
get
{
return isStacked_;
}
}
private bool isStacked_;
private HistogramPlot stackedTo_;
/// <summary>
/// Stack the histogram to another HistogramPlot.
/// </summary>
public void StackedTo(HistogramPlot hp)
{
SequenceAdapter data =
new SequenceAdapter( this.DataSource, this.DataMember, this.OrdinateData, this.AbscissaData );
SequenceAdapter hpData =
new SequenceAdapter( hp.DataSource, hp.DataMember, hp.OrdinateData, hp.AbscissaData );
if ( hp != null )
{
isStacked_ = true;
if ( hpData.Count != data.Count )
{
throw new NPlotException("Can stack HistogramPlot data only with the same number of datapoints.");
}
for ( int i=0; i < data.Count; ++i )
{
if ( data[i].X != hpData[i].X )
{
throw new NPlotException("Can stack HistogramPlot data only with the same X coordinates.");
}
if ( hpData[i].Y < 0.0f)
{
throw new NPlotException("Can stack HistogramPlot data only with positive Y coordinates.");
}
}
}
stackedTo_ = hp;
}
/// <summary>
/// Draws a representation of this plot in the legend.
/// </summary>
/// <param name="g">The graphics surface on which to draw.</param>
/// <param name="startEnd">A rectangle specifying the bounds of the area in the legend set aside for drawing.</param>
public void DrawInLegend( Graphics g, Rectangle startEnd )
{
if (Filled)
{
g.FillRectangle( rectangleBrush_.Get(startEnd), startEnd );
}
g.DrawRectangle( Pen, startEnd.X, startEnd.Y, startEnd.Width, startEnd.Height );
}
/// <summary>
/// The pen used to draw the plot
/// </summary>
public System.Drawing.Pen Pen
{
get
{
return pen_;
}
set
{
pen_ = value;
}
}
private System.Drawing.Pen pen_ = new Pen(Color.Black);
/// <summary>
/// The color of the pen used to draw lines in this plot.
/// </summary>
public System.Drawing.Color Color
{
set
{
if (pen_ != null)
{
pen_.Color = value;
}
else
{
pen_ = new Pen(value);
}
}
get
{
return pen_.Color;
}
}
/// <summary>
/// Horizontal position of histogram columns is offset by this much (in world coordinates).
/// </summary>
public double BaseOffset
{
set
{
baseOffset_ = value;
}
get
{
return baseOffset_;
}
}
private double baseOffset_;
}
}

287
lib/HorizontalLine.cs Normal file
Просмотреть файл

@ -0,0 +1,287 @@
/*
NPlot - A charting library for .NET
HorizontalLine.cs
Copyright (C) 2003
Matt Howlett
Redistribution and use of NPlot or parts there-of in source and
binary forms, with or without modification, are permitted provided
that the following conditions are met:
1. Re-distributions in source form must retain at the head of each
source file the above copyright notice, this list of conditions
and the following disclaimer.
2. Any product ("the product") that makes use NPlot or parts
there-of must either:
(a) allow any user of the product to obtain a complete machine-
readable copy of the corresponding source code for the
product and the version of NPlot used for a charge no more
than your cost of physically performing source distribution,
on a medium customarily used for software interchange, or:
(b) reproduce the following text in the documentation, about
box or other materials intended to be read by human users
of the product that is provided to every human user of the
product:
"This product includes software developed as
part of the NPlot library project available
from: http://www.nplot.com/"
The words "This product" may optionally be replace with
the actual name of the product.
------------------------------------------------------------------------
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
using System;
using System.Drawing;
namespace NPlot
{
/// <summary>
/// Encapsulates functionality for drawing a horizontal line on a plot surface.
/// </summary>
public class HorizontalLine : IPlot
{
/// <summary>
/// Constructor
/// </summary>
/// <param name="ordinateValue">ordinate (Y) value of line.</param>
public HorizontalLine( double ordinateValue )
{
this.value_ = ordinateValue;
}
/// <summary>
/// Constructor
/// </summary>
/// <param name="ordinateValue">ordinate (Y) value of line.</param>
/// <param name="color">draw the line using this color.</param>
public HorizontalLine( double ordinateValue, Color color )
{
this.value_ = ordinateValue;
this.pen_ = new Pen( color );
}
/// <summary>
/// Constructor
/// </summary>
/// <param name="ordinateValue">ordinate (Y) value of line.</param>
/// <param name="pen">Pen to use to draw the line.</param>
public HorizontalLine( double ordinateValue, Pen pen )
{
this.value_ = ordinateValue;
this.pen_ = pen;
}
/// <summary>
/// Draws a representation of the horizontal line in the legend.
/// </summary>
/// <param name="g">The graphics surface on which to draw</param>
/// <param name="startEnd">A rectangle specifying the bounds of the area in the legend set aside for drawing.</param>
public void DrawInLegend(System.Drawing.Graphics g, System.Drawing.Rectangle startEnd)
{
g.DrawLine( pen_, startEnd.Left, (startEnd.Top + startEnd.Bottom)/2,
startEnd.Right, (startEnd.Top + startEnd.Bottom)/2 );
}
/// <summary>
/// A label to associate with the plot - used in the legend.
/// </summary>
public string Label
{
get
{
return label_;
}
set
{
this.label_ = value;
}
}
private string label_ = "";
/// <summary>
/// Whether or not to include an entry for this plot in the legend if it exists.
/// </summary>
public bool ShowInLegend
{
get
{
return showInLegend_;
}
set
{
this.showInLegend_ = value;
}
}
private bool showInLegend_ = false;
/// <summary>
/// Returns null indicating that x extremities of the line are variable.
/// </summary>
/// <returns>null</returns>
public Axis SuggestXAxis()
{
return null;
}
/// <summary>
/// Returns a y-axis that is suitable for drawing this plot.
/// </summary>
/// <returns>A suitable y-axis.</returns>
public Axis SuggestYAxis()
{
return new LinearAxis( this.value_, this.value_ );
}
/// <summary>
/// Writes text data describing the horizontal line object to the supplied string builder. It is
/// possible to specify that the data will be written only if the line is in the specified
/// region.
/// </summary>
/// <param name="sb">the StringBuilder object to write to.</param>
/// <param name="region">a region used if onlyInRegion is true.</param>
/// <param name="onlyInRegion">If true, data will be written only if the line is in the specified region.</param>
public void WriteData(System.Text.StringBuilder sb, RectangleD region, bool onlyInRegion)
{
// return if line is not in plot region and
if (value_ > region.Y+region.Height || value_ < region.Y)
{
if (onlyInRegion)
{
return;
}
}
sb.Append( "Label: " );
sb.Append( this.Label );
sb.Append( "\r\n" );
sb.Append( value_.ToString() );
sb.Append( "\r\n" );
}
/// <summary>
/// Draws the horizontal line plot on a GDI+ surface against the provided x and y axes.
/// </summary>
/// <param name="g">The GDI+ surface on which to draw.</param>
/// <param name="xAxis">The X-Axis to draw against.</param>
/// <param name="yAxis">The Y-Axis to draw against.</param>
public void Draw(System.Drawing.Graphics g, PhysicalAxis xAxis, PhysicalAxis yAxis)
{
int xMin = xAxis.PhysicalMin.X;
int xMax = xAxis.PhysicalMax.X;
xMin += pixelIndent_;
xMax -= pixelIndent_;
float length = Math.Abs(xMax - xMin);
float lengthDiff = length - length*scale_;
float indentAmount = lengthDiff/2;
xMin += (int)indentAmount;
xMax -= (int)indentAmount;
int yPos = (int)yAxis.WorldToPhysical( value_, false ).Y;
g.DrawLine( pen_, new System.Drawing.Point( xMin, yPos ), new System.Drawing.Point( xMax, yPos ) );
// todo: clip and proper logic for flipped axis min max.
}
private double value_;
/// <summary>
/// ordinate (Y) value to draw horizontal line at.
/// </summary>
public double OrdinateValue
{
get
{
return value_;
}
set
{
value_ = value;
}
}
private Pen pen_ = new Pen( Color.Black );
/// <summary>
/// Pen to use to draw the horizontal line.
/// </summary>
public Pen Pen
{
get
{
return pen_;
}
set
{
pen_ = value;
}
}
/// <summary>
/// Each end of the line is indented by this many pixels.
/// </summary>
public int PixelIndent
{
get
{
return pixelIndent_;
}
set
{
pixelIndent_ = value;
}
}
private int pixelIndent_ = 0;
/// <summary>
/// The line length is multiplied by this amount. Default
/// corresponds to a value of 1.0.
/// </summary>
public float LengthScale
{
get
{
return scale_;
}
set
{
scale_ = value;
}
}
private float scale_ = 1.0f;
}
}

72
lib/IDrawable.cs Normal file
Просмотреть файл

@ -0,0 +1,72 @@
/*
NPlot - A charting library for .NET
IDrawable.cs
Copyright (C) 2003
Matt Howlett
Redistribution and use of NPlot or parts there-of in source and
binary forms, with or without modification, are permitted provided
that the following conditions are met:
1. Re-distributions in source form must retain at the head of each
source file the above copyright notice, this list of conditions
and the following disclaimer.
2. Any product ("the product") that makes use NPlot or parts
there-of must either:
(a) allow any user of the product to obtain a complete machine-
readable copy of the corresponding source code for the
product and the version of NPlot used for a charge no more
than your cost of physically performing source distribution,
on a medium customarily used for software interchange, or:
(b) reproduce the following text in the documentation, about
box or other materials intended to be read by human users
of the product that is provided to every human user of the
product:
"This product includes software developed as
part of the NPlot library project available
from: http://www.nplot.com/"
The words "This product" may optionally be replace with
the actual name of the product.
------------------------------------------------------------------------
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
using System;
using System.Drawing;
namespace NPlot
{
/// <summary>
/// Defines a Draw method for drawing objects against an x and y
/// Physical Axis.
/// </summary>
public interface IDrawable
{
/// <summary>
/// Draws this object against an x and y PhysicalAxis.
/// </summary>
/// <param name="g">The graphics surface on which to draw.</param>
/// <param name="xAxis">The physical x-axis to draw against.</param>
/// <param name="yAxis">The physical y-axis to draw against.</param>
void Draw( Graphics g, PhysicalAxis xAxis, PhysicalAxis yAxis );
}
}

27
lib/IDrawable3D.cs Normal file
Просмотреть файл

@ -0,0 +1,27 @@
// ******** experimental ********
/*
using System;
using System.Drawing;
namespace NPlot
{
/// <summary>
/// Defines a Draw method for drawing objects against x, y and z
/// Physical Axes.
/// </summary>
public interface IDrawable3D
{
/// <summary>
/// Draws this object against x, y and z PhysicalAxes.
/// </summary>
/// <param name="g">The graphics surface on which to draw.</param>
/// <param name="xAxis">The physical x-axis to draw against.</param>
/// <param name="yAxis">The physical y-axis to draw against.</param>
/// <param name="zAxis">The physical z-axis to draw against.</param>
/// <remarks>Other or different parameters will probably be needed here - basically
/// the supplied parameters need to allow the Draw method to do the world -> physical
/// transform.</remarks>
void Draw( Graphics g, PhysicalAxis xAxis, PhysicalAxis yAxis, PhysicalAxis zAxis );
}
}
*/

73
lib/IGradient.cs Normal file
Просмотреть файл

@ -0,0 +1,73 @@
/*
NPlot - A charting library for .NET
IGradient.cs
Copyright (C) 2003-2004
Matt Howlett
Redistribution and use of NPlot or parts there-of in source and
binary forms, with or without modification, are permitted provided
that the following conditions are met:
1. Re-distributions in source form must retain at the head of each
source file the above copyright notice, this list of conditions
and the following disclaimer.
2. Any product ("the product") that makes use NPlot or parts
there-of must either:
(a) allow any user of the product to obtain a complete machine-
readable copy of the corresponding source code for the
product and the version of NPlot used for a charge no more
than your cost of physically performing source distribution,
on a medium customarily used for software interchange, or:
(b) reproduce the following text in the documentation, about
box or other materials intended to be read by human users
of the product that is provided to every human user of the
product:
"This product includes software developed as
part of the NPlot library project available
from: http://www.nplot.com/"
The words "This product" may optionally be replace with
the actual name of the product.
------------------------------------------------------------------------
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
using System;
using System.Drawing;
using System.Drawing.Drawing2D;
namespace NPlot
{
/// <summary>
/// Defines a gradient.
/// </summary>
public interface IGradient
{
/// <summary>
/// Gets a color corresponding to a number between 0.0 and 1.0 inclusive.
/// </summary>
/// <param name="prop">the number to get corresponding color for (between 0.0 and 1.0)</param>
/// <returns>The color corresponding to the supplied number.</returns>
Color GetColor( double prop );
}
}

49
lib/IMeshPlot.cs Normal file
Просмотреть файл

@ -0,0 +1,49 @@
/*
NPlot - A charting library for .NET
IMeshPlot.cs
Copyright (C) 2003
Matt Howlett
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the following text in
the documentation and / or other materials provided with the
distribution:
"This product includes software developed as part of
the NPlot charting library project available from:
http://www.nplot.com/"
------------------------------------------------------------------------
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
$Id: IMeshPlot.cs,v 1.9 2004/10/23 07:08:35 mhowlett Exp $
*/
namespace NPlot
{
/// <summary>
/// TODO
/// </summary>
public interface IMeshPlot : IPlot
{
}
}

104
lib/IPlot.cs Normal file
Просмотреть файл

@ -0,0 +1,104 @@
/*
NPlot - A charting library for .NET
IPlot.cs
Copyright (C) 2003
Matt Howlett
Redistribution and use of NPlot or parts there-of in source and
binary forms, with or without modification, are permitted provided
that the following conditions are met:
1. Re-distributions in source form must retain at the head of each
source file the above copyright notice, this list of conditions
and the following disclaimer.
2. Any product ("the product") that makes use NPlot or parts
there-of must either:
(a) allow any user of the product to obtain a complete machine-
readable copy of the corresponding source code for the
product and the version of NPlot used for a charge no more
than your cost of physically performing source distribution,
on a medium customarily used for software interchange, or:
(b) reproduce the following text in the documentation, about
box or other materials intended to be read by human users
of the product that is provided to every human user of the
product:
"This product includes software developed as
part of the NPlot library project available
from: http://www.nplot.com/"
The words "This product" may optionally be replace with
the actual name of the product.
------------------------------------------------------------------------
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
using System.Drawing;
namespace NPlot
{
/// <summary>
/// Defines the interface for objects that (a) can draw a representation of
/// themselves in the legend and (b) can recommend a good axis to draw themselves
/// against.
/// </summary>
public interface IPlot : IDrawable
{
/// <summary>
/// Method used to draw a representation of the plot in a legend.
/// </summary>
void DrawInLegend( Graphics g, Rectangle startEnd );
/// <summary>
/// The label associated with the plot [used in legend]
/// </summary>
string Label { get; set; }
/// <summary>
/// Whether or not to include an entry for this plot in the legend if it exists.
/// </summary>
bool ShowInLegend { get; set; }
/// <summary>
/// The method used to set the default abscissa axis.
/// </summary>
Axis SuggestXAxis();
/// <summary>
/// The method used to set the default ordinate axis.
/// </summary>
Axis SuggestYAxis();
/// <summary>
/// Write data associated with the plot as text.
/// </summary>
/// <param name="sb">the string builder to write to.</param>
/// <param name="region">Only write out data in this region if onlyInRegion is true.</param>
/// <param name="onlyInRegion">If true, only data in region is written, else all data is written.</param>
void WriteData( System.Text.StringBuilder sb, RectangleD region, bool onlyInRegion );
}
}

33
lib/IPlot3D.cs Normal file
Просмотреть файл

@ -0,0 +1,33 @@
/*
using System;
namespace NPlot
{
/// <summary>
/// 3D plottable objects implement this interface.
/// </summary>
public interface IPlot3D
{
/// <summary>
/// The method used to set the default x axis.
/// </summary>
Axis SuggestXAxis();
/// <summary>
/// The method used to set the default y axis.
/// </summary>
Axis SuggestYAxis();
/// <summary>
/// The method used to set the default z axis.
/// </summary>
Axis SuggestZAxis();
}
}
*/

255
lib/IPlotSurface2D.cs Normal file
Просмотреть файл

@ -0,0 +1,255 @@
/*
NPlot - A charting library for .NET
IPlotSurface2D.cs
Copyright (C) 2003
Paolo Pierini, Matt Howlett
Redistribution and use of NPlot or parts there-of in source and
binary forms, with or without modification, are permitted provided
that the following conditions are met:
1. Re-distributions in source form must retain at the head of each
source file the above copyright notice, this list of conditions
and the following disclaimer.
2. Any product ("the product") that makes use NPlot or parts
there-of must either:
(a) allow any user of the product to obtain a complete machine-
readable copy of the corresponding source code for the
product and the version of NPlot used for a charge no more
than your cost of physically performing source distribution,
on a medium customarily used for software interchange, or:
(b) reproduce the following text in the documentation, about
box or other materials intended to be read by human users
of the product that is provided to every human user of the
product:
"This product includes software developed as
part of the NPlot library project available
from: http://www.nplot.com/"
The words "This product" may optionally be replace with
the actual name of the product.
------------------------------------------------------------------------
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
using System;
using System.Collections;
namespace NPlot
{
/// <summary>
/// Defines the PlotSurface2D interface - All specific PlotSurface2D classes
/// that use PlotSurface2D for their underlying operations should implement
/// this class.
/// </summary>
public interface IPlotSurface2D
{
/// <summary>
/// Adds a drawable object to the plot surface. If the object is an IPlot,
/// the PlotSurface2D axes will also be updated.
/// </summary>
/// <param name="p">The IDrawable object to add to the plot surface.</param>
/// <param name="zOrder">The z-ordering when drawing (objects with lower numbers are drawn first)</param>
void Add( IDrawable p, int zOrder );
/// <summary>
/// Adds a drawable object to the plot surface against the specified axes. If
/// the object is an IPlot, the PlotSurface2D axes will also be updated.
/// </summary>
/// <param name="p">the IDrawable object to add to the plot surface</param>
/// <param name="xp">the x-axis to add the plot against.</param>
/// <param name="yp">the y-axis to add the plot against.</param>
/// <param name="zOrder">The z-ordering when drawing (objects with lower numbers are drawn first)</param>
void Add( IDrawable p, NPlot.PlotSurface2D.XAxisPosition xp, NPlot.PlotSurface2D.YAxisPosition yp, int zOrder );
/// <summary>
/// Adds a drawable object to the plot surface. If the object is an IPlot,
/// the PlotSurface2D axes will also be updated.
/// </summary>
/// <param name="p">The IDrawable object to add to the plot surface.</param>
void Add(IDrawable p);
/// <summary>
/// Adds a drawable object to the plot surface against the specified axes. If
/// the object is an IPlot, the PlotSurface2D axes will also be updated.
/// </summary>
/// <param name="p">the IDrawable object to add to the plot surface</param>
/// <param name="xax">the x-axis to add the plot against.</param>
/// <param name="yax">the y-axis to add the plot against.</param>
void Add(IDrawable p, NPlot.PlotSurface2D.XAxisPosition xax, NPlot.PlotSurface2D.YAxisPosition yax);
/// <summary>
/// Clears the PlotSurface2D.
/// </summary>
void Clear();
/// <summary>
/// Gets or Sets the legend to use with this plot surface.
/// </summary>
NPlot.Legend Legend { get; set; }
/// <summary>
/// Setting this value determines the order (relative to IDrawables added to the plot surface)
/// that the legend is drawn.
/// </summary>
int LegendZOrder { get; set; }
/// <summary>
/// The distance in pixels to leave between of the edge of the bounding rectangle
/// supplied to the Draw method, and the markings that make up the plot.
/// </summary>
int Padding { get; set; }
/// <summary>
/// A color used to paint the plot background. Mutually exclusive with PlotBackImage and PlotBackBrush
/// </summary>
System.Drawing.Color PlotBackColor { set; }
/// <summary>
/// An imaged used to paint the plot background. Mutually exclusive with PlotBackColor and PlotBackBrush
/// </summary>
System.Drawing.Bitmap PlotBackImage { set; }
/// <summary>
/// A Rectangle brush used to paint the plot background. Mutually exclusive with PlotBackColor and PlotBackBrush
/// </summary>
IRectangleBrush PlotBackBrush { set; }
/// <summary>
/// The plot surface title.
/// </summary>
string Title { get; set; }
/// <summary>
/// Whether or not the title will be scaled according to size of the plot
/// surface.
/// </summary>
bool AutoScaleTitle { get; set; }
/// <summary>
/// When plots are added to the plot surface, the axes they are attached to
/// are immediately modified to reflect data of the plot. If
/// AutoScaleAutoGeneratedAxes is true when a plot is added, the axes will
/// be turned in to auto scaling ones if they are not already [tick marks,
/// tick text and label size scaled to size of plot surface]. If false,
/// axes will not be autoscaling.
/// </summary>
bool AutoScaleAutoGeneratedAxes { get; set; }
/// <summary>
/// Sets the title to be drawn using a solid brush of this color.
/// </summary>
System.Drawing.Color TitleColor { set; }
/// <summary>
/// The brush used for drawing the title.
/// </summary>
System.Drawing.Brush TitleBrush { get; set; }
/// <summary>
/// The plot title font.
/// </summary>
System.Drawing.Font TitleFont { get; set; }
/// <summary>
/// Smoothing mode to use when drawing plots.
/// </summary>
System.Drawing.Drawing2D.SmoothingMode SmoothingMode { get; set; }
/// <summary>
/// Add an axis constraint to the plot surface. Axis constraints can
/// specify relative world-pixel scalings, absolute axis positions etc.
/// </summary>
/// <param name="c">The axis constraint to add.</param>
void AddAxesConstraint( AxesConstraint c );
/// <summary>
/// The bottom abscissa axis.
/// </summary>
Axis XAxis1 { get; set; }
/// <summary>
/// The top abscissa axis.
/// </summary>
Axis XAxis2 { get; set; }
/// <summary>
/// The left ordinate axis.
/// </summary>
Axis YAxis1 { get; set; }
/// <summary>
/// The right ordinate axis.
/// </summary>
Axis YAxis2 { get; set; }
/// <summary>
/// Remove a drawable object from the plot surface.
/// </summary>
/// <param name="p">the object to remove</param>
/// <param name="updateAxes">whether or not to update the axes after removal.</param>
void Remove( IDrawable p, bool updateAxes );
/// <summary>
/// Gets an array list containing all drawables currently added to the PlotSurface2D.
/// </summary>
ArrayList Drawables { get; }
/*
/// <summary>
/// Calculates axes approprate to IPlots on PlotSurface. Note that
/// this is done automatically as a new plot is added. You may wish
/// to call this again if you update data in the plot.
/// </summary>
void AutoCalculateAxes();
/// <summary>
/// C
/// </summary>
/// <param name="p"></param>
void UpdateAxes( IPlot p );
*/
}
}

19
lib/IPlotSurface2Dnew.cs Normal file
Просмотреть файл

@ -0,0 +1,19 @@
// ******** experimental ********
/*
namespace NPlot
{
/// <summary>
/// Defines the PlotSurface2Dnew interface - All specific PlotSurface2Dnew classes
/// that use PlotSurface2Dnew for their underlying operations should implement
/// this class. TODO: this is experimental.
/// </summary>
public interface IPlotSurface2Dnew
{
/// <summary>
/// The distance in pixels to leave between of the edge of the bounding rectangle
/// supplied to the Draw method, and the markings that make up the plot.
/// </summary>
int Padding { get; set; }
}
}
*/

17
lib/IPlotSurface3D.cs Normal file
Просмотреть файл

@ -0,0 +1,17 @@
// ******** experimental ********
/*
using System;
namespace NPlot
{
/// <summary>
/// TODO.
/// </summary>
public interface IPlotSurface3D
{
}
}
*/

85
lib/ISequencePlot.cs Normal file
Просмотреть файл

@ -0,0 +1,85 @@
/*
NPlot - A charting library for .NET
IPlot.cs
Copyright (C) 2003
Matt Howlett
Redistribution and use of NPlot or parts there-of in source and
binary forms, with or without modification, are permitted provided
that the following conditions are met:
1. Re-distributions in source form must retain at the head of each
source file the above copyright notice, this list of conditions
and the following disclaimer.
2. Any product ("the product") that makes use NPlot or parts
there-of must either:
(a) allow any user of the product to obtain a complete machine-
readable copy of the corresponding source code for the
product and the version of NPlot used for a charge no more
than your cost of physically performing source distribution,
on a medium customarily used for software interchange, or:
(b) reproduce the following text in the documentation, about
box or other materials intended to be read by human users
of the product that is provided to every human user of the
product:
"This product includes software developed as
part of the NPlot library project available
from: http://www.nplot.com/"
The words "This product" may optionally be replace with
the actual name of the product.
------------------------------------------------------------------------
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
using System;
namespace NPlot
{
/// <summary>
/// Defines an mix-in style interface for plots that use SequenceAdapter to interpret supplied data.
/// </summary>
public interface ISequencePlot
{
/// <summary>
/// Gets or sets the source containing a list of values used to populate the plot object.
/// </summary>
object DataSource { get; set; }
/// <summary>
/// Gets or sets the specific data member in a multimember data source to get data from.
/// </summary>
string DataMember { get; set; }
/// <summary>
/// Gets or sets the data, or column name for the abscissa [x] axis.
/// </summary>
object AbscissaData { get; set; }
/// <summary>
/// Gets or sets the data, or column name for the ordinate [y] axis.
/// </summary>
object OrdinateData { get; set; }
}
}

98
lib/ISurface.cs Normal file
Просмотреть файл

@ -0,0 +1,98 @@
/*
NPlot - A charting library for .NET
ISurface.cs
Copyright (C) 2003
Matt Howlett
Redistribution and use of NPlot or parts there-of in source and
binary forms, with or without modification, are permitted provided
that the following conditions are met:
1. Re-distributions in source form must retain at the head of each
source file the above copyright notice, this list of conditions
and the following disclaimer.
2. Any product ("the product") that makes use NPlot or parts
there-of must either:
(a) allow any user of the product to obtain a complete machine-
readable copy of the corresponding source code for the
product and the version of NPlot used for a charge no more
than your cost of physically performing source distribution,
on a medium customarily used for software interchange, or:
(b) reproduce the following text in the documentation, about
box or other materials intended to be read by human users
of the product that is provided to every human user of the
product:
"This product includes software developed as
part of the NPlot library project available
from: http://www.nplot.com/"
The words "This product" may optionally be replace with
the actual name of the product.
------------------------------------------------------------------------
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
using System;
using System.Windows.Forms;
namespace NPlot
{
/// <summary>
/// All PlotSurface's implement this interface.
/// </summary>
/// <remarks>Some of the parameter lists will change to be made more uniform.</remarks>
public interface ISurface
{
/// <summary>
/// Provides functionality for drawing the control.
/// </summary>
/// <param name="pe">paint event args</param>
/// <param name="width">width of the control.</param>
/// <param name="height">height of the control.</param>
void DoPaint( PaintEventArgs pe, int width, int height );
/// <summary>
/// Provides functionality for handling mouse up events.
/// </summary>
/// <param name="e">mouse event args</param>
/// <param name="ctr">the control</param>
void DoMouseUp( MouseEventArgs e, System.Windows.Forms.Control ctr );
/// <summary>
/// Provides functionality for handling mouse move events.
/// </summary>
/// <param name="e">mouse event args</param>
/// <param name="ctr">the control</param>
void DoMouseMove( MouseEventArgs e, System.Windows.Forms.Control ctr );
/// <summary>
/// Provides functionality for handling mouse down events.
/// </summary>
/// <param name="e">mouse event args</param>
void DoMouseDown( MouseEventArgs e );
}
}

78
lib/ITransform2D.cs Normal file
Просмотреть файл

@ -0,0 +1,78 @@
/*
NPlot - A charting library for .NET
ITransform2D.cs
Copyright (C) 2003
Matt Howlett
Redistribution and use of NPlot or parts there-of in source and
binary forms, with or without modification, are permitted provided
that the following conditions are met:
1. Re-distributions in source form must retain at the head of each
source file the above copyright notice, this list of conditions
and the following disclaimer.
2. Any product ("the product") that makes use NPlot or parts
there-of must either:
(a) allow any user of the product to obtain a complete machine-
readable copy of the corresponding source code for the
product and the version of NPlot used for a charge no more
than your cost of physically performing source distribution,
on a medium customarily used for software interchange, or:
(b) reproduce the following text in the documentation, about
box or other materials intended to be read by human users
of the product that is provided to every human user of the
product:
"This product includes software developed as
part of the NPlot library project available
from: http://www.nplot.com/"
The words "This product" may optionally be replace with
the actual name of the product.
------------------------------------------------------------------------
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
using System;
using System.Drawing;
namespace NPlot
{
/// <summary>
/// This interface is useful in the Plot classes for transforming
/// world to physical coordinates. Create on using the GetTransformer
/// static method in Transform2D.
/// </summary>
public interface ITransform2D
{
/// <summary>
/// Transforms the given world point to physical coordinates
/// </summary>
PointF Transform( double x, double y );
/// <summary>
/// Transforms the given world point to physical coordinates
/// </summary>
PointF Transform( PointD worldPoint );
}
}

369
lib/ImagePlot.cs Normal file
Просмотреть файл

@ -0,0 +1,369 @@
/*
NPlot - A charting library for .NET
ImagePlot.cs
Copyright (C) 2003-2004
Matt Howlett
Redistribution and use of NPlot or parts there-of in source and
binary forms, with or without modification, are permitted provided
that the following conditions are met:
1. Re-distributions in source form must retain at the head of each
source file the above copyright notice, this list of conditions
and the following disclaimer.
2. Any product ("the product") that makes use NPlot or parts
there-of must either:
(a) allow any user of the product to obtain a complete machine-
readable copy of the corresponding source code for the
product and the version of NPlot used for a charge no more
than your cost of physically performing source distribution,
on a medium customarily used for software interchange, or:
(b) reproduce the following text in the documentation, about
box or other materials intended to be read by human users
of the product that is provided to every human user of the
product:
"This product includes software developed as
part of the NPlot library project available
from: http://www.nplot.com/"
The words "This product" may optionally be replace with
the actual name of the product.
------------------------------------------------------------------------
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
using System;
using System.Drawing;
using System.Drawing.Drawing2D;
namespace NPlot
{
/// <summary>
/// Encapsulates functionality for plotting data as a 2D image chart.
/// </summary>
public class ImagePlot : IPlot
{
private double[,] data_;
private double xStart_ = 0.0;
private double xStep_ = 1.0;
private double yStart_ = 0.0;
private double yStep_ = 1.0;
/// <summary>
/// At or below which value a minimum gradient color should be used.
/// </summary>
public double DataMin
{
get
{
return dataMin_;
}
set
{
dataMin_ = value;
}
}
private double dataMin_;
/// <summary>
/// At or above which value a maximum gradient color should be used.
/// </summary>
public double DataMax
{
get
{
return dataMax_;
}
set
{
dataMax_ = value;
}
}
private double dataMax_;
/// <summary>
/// Calculates the minimum and maximum values of the data array.
/// </summary>
private void calculateMinMax()
{
dataMin_ = data_[0,0];
dataMax_ = data_[0,0];
for (int i=0; i<data_.GetLength(0); ++i)
{
for (int j=0; j<data_.GetLength(1); ++j)
{
if (data_[i,j]<dataMin_)
{
dataMin_ = data_[i,j];
}
if (data_[i,j]>dataMax_)
{
dataMax_ = data_[i,j];
}
}
}
}
/// <summary>
/// Constructor
/// </summary>
/// <param name="data">the 2D array to plot</param>
/// <param name="xStart">the world value corresponding to the 1st position in the x-direction</param>
/// <param name="xStep">the world step size between pixels in the x-direction.</param>
/// <param name="yStart">the world value corresponding to the 1st position in the y-direction</param>
/// <param name="yStep">the world step size between pixels in the y-direction.</param>
/// <remarks>no adapters for this yet - when we get some more 2d
/// plotting functionality, then perhaps create some.</remarks>
public ImagePlot( double[,] data, double xStart, double xStep, double yStart, double yStep )
{
#if CHECK_ERRORS
if (data == null || data.GetLength(0) == 0 || data.GetLength(1) == 0)
{
throw new NPlotException( "ERROR: ImagePlot.ImagePlot: Data null, or zero length" );
}
#endif
this.data_ = data;
this.xStart_ = xStart;
this.xStep_ = xStep;
this.yStart_ = yStart;
this.yStep_ = yStep;
this.calculateMinMax();
}
/// <summary>
/// Constructor
/// </summary>
/// <param name="data">The 2D array to plot.</param>
public ImagePlot( double[,] data )
{
this.data_ = data;
this.calculateMinMax();
}
/// <summary>
/// Draw on to the supplied graphics surface against the supplied axes.
/// </summary>
/// <param name="g">The graphics surface on which to draw.</param>
/// <param name="xAxis">The X-Axis to draw against.</param>
/// <param name="yAxis">The Y-Axis to draw against.</param>
/// <remarks>TODO: block positions may be off by a pixel or so. maybe. Re-think calculations</remarks>
public void Draw( Graphics g, PhysicalAxis xAxis, PhysicalAxis yAxis )
{
if ( data_==null || data_.GetLength(0) == 0 || data_.GetLength(1) == 0 )
{
return;
}
double worldWidth = xAxis.Axis.WorldMax - xAxis.Axis.WorldMin;
double numBlocksHorizontal = worldWidth / this.xStep_;
double worldHeight = yAxis.Axis.WorldMax - yAxis.Axis.WorldMin;
double numBlocksVertical = worldHeight / this.yStep_;
double physicalWidth = xAxis.PhysicalMax.X - xAxis.PhysicalMin.X;
double blockWidth = physicalWidth / numBlocksHorizontal;
bool wPositive = true;
if (blockWidth < 0.0)
{
wPositive = false;
}
blockWidth = Math.Abs(blockWidth)+1;
double physicalHeight = yAxis.PhysicalMax.Y - yAxis.PhysicalMin.Y;
double blockHeight = physicalHeight / numBlocksVertical;
bool hPositive = true;
if (blockHeight < 0.0)
{
hPositive = false;
}
blockHeight = Math.Abs(blockHeight)+1;
for (int i=0; i<data_.GetLength(0); ++i)
{
for (int j=0; j<data_.GetLength(1); ++j)
{
double wX = (double)j*this.xStep_ + xStart_;
double wY = (double)i*this.yStep_ + yStart_;
if ( !hPositive )
{
wY += yStep_;
}
if (!wPositive )
{
wX += xStep_;
}
if (this.center_)
{
wX -= this.xStep_/2.0;
wY -= this.yStep_/2.0;
}
Pen p = new Pen( this.Gradient.GetColor( (data_[i,j]-this.dataMin_)/(this.dataMax_-this.dataMin_) ) );
int x = (int)xAxis.WorldToPhysical(wX,false).X;
int y = (int)yAxis.WorldToPhysical(wY,false).Y;
g.FillRectangle( p.Brush,
x,
y,
(int)blockWidth,
(int)blockHeight);
//g.DrawRectangle(Pens.White,x,y,(int)blockWidth,(int)blockHeight);
}
}
}
/// <summary>
/// The gradient that specifies the mapping between value and color.
/// </summary>
/// <remarks>memory allocation in get may be inefficient.</remarks>
public IGradient Gradient
{
get
{
if (gradient_ == null)
{
// TODO: suboptimal.
gradient_ = new LinearGradient( Color.FromArgb(255,255,255), Color.FromArgb(0,0,0) );
}
return this.gradient_;
}
set
{
this.gradient_ = value;
}
}
private IGradient gradient_;
/// <summary>
/// Draws a representation of this plot in the legend.
/// </summary>
/// <param name="g">The graphics surface on which to draw.</param>
/// <param name="startEnd">A rectangle specifying the bounds of the area in the legend set aside for drawing.</param>
public void DrawInLegend( Graphics g, Rectangle startEnd )
{
// not implemented yet.
}
/// <summary>
/// A label to associate with the plot - used in the legend.
/// </summary>
public string Label
{
get
{
return label_;
}
set
{
this.label_ = value;
}
}
private string label_ = "";
/// <summary>
/// Returns an x-axis that is suitable for drawing this plot.
/// </summary>
/// <returns>A suitable x-axis.</returns>
public Axis SuggestXAxis()
{
if (this.center_)
{
return new LinearAxis( this.xStart_ - this.xStep_/2.0, this.xStart_ + this.xStep_ * data_.GetLength(1) - this.xStep_/2.0 );
}
return new LinearAxis( this.xStart_, this.xStart_ + this.xStep_ * data_.GetLength(1) );
}
/// <summary>
/// Returns a y-axis that is suitable for drawing this plot.
/// </summary>
/// <returns>A suitable y-axis.</returns>
public Axis SuggestYAxis()
{
if (this.center_)
{
return new LinearAxis( this.yStart_ - this.yStep_/2.0, this.yStart_ + this.yStep_ * data_.GetLength(0) - this.yStep_/2.0 );
}
return new LinearAxis( this.yStart_, this.yStart_ + this.yStep_ * data_.GetLength(0) );
}
/// <summary>
/// If true, pixels are centered on their respective coordinates. If false, they are drawn
/// between their coordinates and the coordinates of the the next point in each direction.
/// </summary>
public bool Center
{
set
{
center_ = value;
}
get
{
return center_;
}
}
private bool center_ = true;
/// <summary>
/// Whether or not to include an entry for this plot in the legend if it exists.
/// </summary>
public bool ShowInLegend
{
get
{
return showInLegend_;
}
set
{
this.showInLegend_ = value;
}
}
private bool showInLegend_ = true;
/// <summary>
/// Write data associated with the plot as text.
/// </summary>
/// <param name="sb">the string builder to write to.</param>
/// <param name="region">Only write out data in this region if onlyInRegion is true.</param>
/// <param name="onlyInRegion">If true, only data in region is written, else all data is written.</param>
/// <remarks>TODO: not implemented.</remarks>
public void WriteData( System.Text.StringBuilder sb, RectangleD region, bool onlyInRegion )
{
}
}
}

356
lib/LabelAxis.cs Normal file
Просмотреть файл

@ -0,0 +1,356 @@
/*
NPlot - A charting library for .NET
LabelAxis.cs
Copyright (C) 2003
Matt Howlett
Redistribution and use of NPlot or parts there-of in source and
binary forms, with or without modification, are permitted provided
that the following conditions are met:
1. Re-distributions in source form must retain at the head of each
source file the above copyright notice, this list of conditions
and the following disclaimer.
2. Any product ("the product") that makes use NPlot or parts
there-of must either:
(a) allow any user of the product to obtain a complete machine-
readable copy of the corresponding source code for the
product and the version of NPlot used for a charge no more
than your cost of physically performing source distribution,
on a medium customarily used for software interchange, or:
(b) reproduce the following text in the documentation, about
box or other materials intended to be read by human users
of the product that is provided to every human user of the
product:
"This product includes software developed as
part of the NPlot library project available
from: http://www.nplot.com/"
The words "This product" may optionally be replace with
the actual name of the product.
------------------------------------------------------------------------
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
using System;
using System.Collections;
using System.Drawing;
namespace NPlot
{
/// <summary>
/// Allows the creation of axes with any number of user defined labels at
/// user defined world values along the axis.
/// </summary>
public class LabelAxis : Axis
{
/// <summary>
/// Deep copy of LabelAxis.
/// </summary>
/// <returns>A copy of the LinearAxis Class.</returns>
public override object Clone()
{
LabelAxis a = new LabelAxis();
// ensure that this isn't being called on a derived type. If it is, then oh no!
if (this.GetType() != a.GetType())
{
throw new NPlotException( "Error. Clone method is not defined in derived type." );
}
DoClone( this, a );
return a;
}
/// <summary>
/// Helper method for Clone.
/// </summary>
/// <param name="a">The original object to clone.</param>
/// <param name="b">The cloned object.</param>
protected static void DoClone( LabelAxis b, LabelAxis a )
{
Axis.DoClone( b, a );
a.labels_ = (ArrayList)b.labels_.Clone();
a.numbers_ = (ArrayList)b.numbers_.Clone();
a.ticksBetweenText_ = b.ticksBetweenText_;
a.sortDataIfNecessary_ = b.sortDataIfNecessary_;
}
/// <summary>
/// Initialise LabelAxis to default state.
/// </summary>
private void Init()
{
labels_ = new ArrayList();
numbers_ = new ArrayList();
}
/// <summary>
/// Copy constructor
/// </summary>
/// <param name="a">The Axis to clone.</param>
/// <remarks>TODO: [review notes] I don't think this will work as desired.</remarks>
public LabelAxis( Axis a )
: base( a )
{
Init();
}
/// <summary>
/// Default constructor
/// </summary>
public LabelAxis()
: base()
{
Init();
}
/// <summary>
/// Constructor
/// </summary>
/// <param name="worldMin">Minimum world value</param>
/// <param name="worldMax">Maximum world value</param>
public LabelAxis( double worldMin, double worldMax )
: base( worldMin, worldMax )
{
Init();
}
/// <summary>
/// Adds a label to the axis
/// </summary>
/// <param name="name">The label</param>
/// <param name="val">The world value at which to place the label</param>
public void AddLabel( string name, double val )
{
labels_.Add( name );
numbers_.Add( val );
}
/// <summary>
/// Given Graphics surface, and physical extents of axis, draw ticks and
/// associated labels.
/// </summary>
/// <param name="g">The GDI+ Graphics surface on which to draw.</param>
/// <param name="physicalMin">The physical location of the world min point</param>
/// <param name="physicalMax">The physical location of the world max point</param>
/// <param name="boundingBox">out: smallest box that completely encompasses all of the ticks and tick labels.</param>
/// <param name="labelOffset">out: a suitable offset from the axis to draw the axis label.</param>
protected override void DrawTicks(
Graphics g,
Point physicalMin,
Point physicalMax,
out object labelOffset,
out object boundingBox )
{
Point tLabelOffset;
Rectangle tBoundingBox;
labelOffset = this.getDefaultLabelOffset( physicalMin, physicalMax );
boundingBox = null;
// draw the tick labels (but not the ticks).
PointF lastPos = WorldToPhysical( (double)numbers_[0], physicalMin, physicalMax, true );
for (int i=0; i<labels_.Count; ++i)
{
if ((double)numbers_[i] > WorldMin && (double)numbers_[i] < WorldMax)
{
// check to make sure labels are far enough appart.
PointF thisPos = WorldToPhysical( (double)numbers_[i], physicalMin, physicalMax, true );
float dist = Utils.Distance( thisPos, lastPos );
if ( i==0 || (dist > this.PhysicalSpacingMin) )
{
lastPos = thisPos;
this.DrawTick( g, (double)numbers_[i], 0,
(string)labels_[i],
new Point(0,0),
physicalMin, physicalMax,
out tLabelOffset, out tBoundingBox );
Axis.UpdateOffsetAndBounds(
ref labelOffset, ref boundingBox,
tLabelOffset, tBoundingBox );
}
}
}
// now draw the ticks (which might not be aligned with the tick text).
ArrayList largeTickPositions;
ArrayList smallTickPositions;
WorldTickPositions_FirstPass( physicalMin, physicalMax, out largeTickPositions, out smallTickPositions );
lastPos = WorldToPhysical( (double)largeTickPositions[0], physicalMin, physicalMax, true );
for (int i=0; i<largeTickPositions.Count; ++i)
{
double tickPos = (double)largeTickPositions[i];
// check to see that labels are far enough appart.
PointF thisPos = WorldToPhysical( tickPos, physicalMin, physicalMax, true );
float dist = Utils.Distance( thisPos, lastPos );
if ( (i==0) || (dist> this.PhysicalSpacingMin) )
{
lastPos = thisPos;
this.DrawTick( g, tickPos, LargeTickSize,
"",
new Point(0,0),
physicalMin, physicalMax,
out tLabelOffset, out tBoundingBox );
Axis.UpdateOffsetAndBounds(
ref labelOffset, ref boundingBox,
tLabelOffset, tBoundingBox );
}
}
}
/// <summary>
/// Determines the positions, in world coordinates, of the large ticks.
///
/// Label axes do not have small ticks.
/// </summary>
/// <param name="physicalMin">The physical position corresponding to the world minimum of the axis.</param>
/// <param name="physicalMax">The physical position corresponding to the world maximum of the axis.</param>
/// <param name="largeTickPositions">ArrayList containing the positions of the large ticks.</param>
/// <param name="smallTickPositions">null</param>
internal override void WorldTickPositions_FirstPass(
Point physicalMin,
Point physicalMax,
out ArrayList largeTickPositions,
out ArrayList smallTickPositions
)
{
smallTickPositions = null;
largeTickPositions = new ArrayList();
// if ticks correspond to position of text
if (!ticksBetweenText_)
{
for (int i=0; i<labels_.Count; ++i)
{
if ((double)numbers_[i] > WorldMin && (double)numbers_[i] < WorldMax)
{
largeTickPositions.Add( numbers_[i] );
}
}
}
// if ticks correspond to gaps between text
else
{
ArrayList numbers_copy;
if (sortDataIfNecessary_)
{
numbers_copy = (ArrayList)numbers_.Clone(); // shallow copy.
numbers_copy.Sort();
}
else
{
numbers_copy = numbers_;
}
for (int i=1; i<labels_.Count; ++i)
{
double worldPosition = ((double)numbers_copy[i] + (double)numbers_copy[i-1])/2.0;
if (worldPosition > WorldMin && worldPosition < WorldMax)
{
largeTickPositions.Add( worldPosition );
}
}
}
}
/// <summary>
/// If true, large ticks are drawn between the labels, rather
/// than at the position of the labels.
/// </summary>
public bool TicksBetweenText
{
get
{
return ticksBetweenText_;
}
set
{
ticksBetweenText_ = value;
}
}
private bool ticksBetweenText_ = false;
/// <summary>
/// If your data may be be specified out of order (that is
/// abscissa values with a higher index may be less than
/// abscissa values of a lower index), then data sorting
/// may be necessary to implement some of the functionality
/// of this object. If you know your data is already
/// ordered with abscissa values lowest -> highest, then
/// you may set this to false. It's default is true.
/// </summary>
public bool SortDataIfNecessary
{
get
{
return sortDataIfNecessary_;
}
set
{
sortDataIfNecessary_ = value;
}
}
private bool sortDataIfNecessary_ = true;
/// <summary>
/// If consecutive labels are less than this number of pixels appart,
/// some of the labels will not be drawn.
/// </summary>
public int PhysicalSpacingMin
{
get
{
return physicalSpacingMin_;
}
set
{
physicalSpacingMin_ = value;
}
}
private int physicalSpacingMin_ = 0;
private ArrayList labels_;
private ArrayList numbers_;
}
}

324
lib/LabelPointPlot.cs Normal file
Просмотреть файл

@ -0,0 +1,324 @@
/*
NPlot - A charting library for .NET
LabelPointPlot.cs
Copyright (C) 2003
Matt Howlett
Redistribution and use of NPlot or parts there-of in source and
binary forms, with or without modification, are permitted provided
that the following conditions are met:
1. Re-distributions in source form must retain at the head of each
source file the above copyright notice, this list of conditions
and the following disclaimer.
2. Any product ("the product") that makes use NPlot or parts
there-of must either:
(a) allow any user of the product to obtain a complete machine-
readable copy of the corresponding source code for the
product and the version of NPlot used for a charge no more
than your cost of physically performing source distribution,
on a medium customarily used for software interchange, or:
(b) reproduce the following text in the documentation, about
box or other materials intended to be read by human users
of the product that is provided to every human user of the
product:
"This product includes software developed as
part of the NPlot library project available
from: http://www.nplot.com/"
The words "This product" may optionally be replace with
the actual name of the product.
------------------------------------------------------------------------
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
using System;
using System.Drawing;
using System.Data;
namespace NPlot
{
/// <summary>
/// Encapsulates functionality
/// </summary>
public class LabelPointPlot : PointPlot, ISequencePlot
{
/// <summary>
/// This class us used in conjunction with SequenceAdapter to interpret data
/// specified to the TextPlot class.
/// </summary>
private class TextDataAdapter
{
private object data_;
private object dataSource_;
private string dataMember_;
public TextDataAdapter( object dataSource, string dataMember, object data )
{
this.data_ = data;
this.dataSource_ = dataSource;
this.dataMember_ = dataMember;
}
public string this[int i]
{
get
{
// this is inefficient [could set up delegates in constructor].
if (data_ is string[])
{
return ((string[])data_)[i];
}
if (data_ is string)
{
if (dataSource_ == null)
{
throw new NPlotException( "Error: DataSource null" );
}
System.Data.DataRowCollection rows;
if ( dataSource_ is System.Data.DataSet )
{
if (dataMember_ != null)
{
// TODO error check
rows = ((DataTable)((DataSet)dataSource_).Tables[dataMember_]).Rows;
}
else
{
// TODO error check
rows = ((DataTable)((DataSet)dataSource_).Tables[0]).Rows;
}
}
else if (dataSource_ is System.Data.DataTable )
{
rows = ((DataTable)dataSource_).Rows;
}
else
{
throw new NPlotException ( "not implemented yet" );
}
return (string)((System.Data.DataRow)(rows[i]))[(string)data_];
}
if (data_ is System.Collections.ArrayList)
{
object dataPoint = ((System.Collections.ArrayList)data_)[i];
if (dataPoint is string)
return (string)dataPoint;
throw new NPlotException( "TextDataAdapter: data not in recognised format" );
}
if (data_ == null)
{
return "text";
}
throw new NPlotException( "Text data not of recognised type" );
}
}
public int Count
{
get
{
// this is inefficient [could set up delegates in constructor].
if (data_ == null)
{
return 0;
}
if (data_ is string[])
{
return ((string[])data_).Length;
}
if (data_ is System.Collections.ArrayList)
{
return ((System.Collections.ArrayList)data_).Count;
}
throw new NPlotException( "Text data not in correct format" );
}
}
}
/// <summary>
/// Enumeration of all label positions relative to a point.
/// </summary>
public enum LabelPositions
{
/// <summary>
/// Above the point
/// </summary>
Above,
/// <summary>
/// Below the point
/// </summary>
Below,
/// <summary>
/// To the left of the point
/// </summary>
Left,
/// <summary>
/// To the right of the point
/// </summary>
Right
}
/// <summary>
/// Default Constructor
/// </summary>
public LabelPointPlot()
{
}
/// <summary>
/// Constructor
/// </summary>
/// <param name="marker">The marker type to use for this plot.</param>
public LabelPointPlot( Marker marker )
: base( marker )
{
}
/// <summary>
/// The position of the text label in relation to the point.
/// </summary>
public LabelPositions LabelTextPosition
{
get
{
return labelTextPosition_;
}
set
{
labelTextPosition_ = value;
}
}
private LabelPositions labelTextPosition_ = LabelPositions.Above;
/// <summary>
/// The text datasource to attach to each point.
/// </summary>
public object TextData
{
get
{
return textData_;
}
set
{
textData_ = value;
}
}
object textData_;
/// <summary>
/// The Font used to write text.
/// </summary>
public Font Font
{
get
{
return font_;
}
set
{
font_ = value;
}
}
private Font font_ = new Font( "Arial", 8.0f );
/// <summary>
/// Draws the plot on a GDI+ surface against the provided x and y axes.
/// </summary>
/// <param name="g">The GDI+ surface on which to draw.</param>
/// <param name="xAxis">The X-Axis to draw against.</param>
/// <param name="yAxis">The Y-Axis to draw against.</param>
public override void Draw( Graphics g, PhysicalAxis xAxis, PhysicalAxis yAxis )
{
SequenceAdapter data =
new SequenceAdapter( this.DataSource, this.DataMember, this.OrdinateData, this.AbscissaData );
TextDataAdapter textData =
new TextDataAdapter( this.DataSource, this.DataMember, this.TextData );
// first plot the marker
// we can do this cast, since the constructor accepts only this type!
for (int i=0; i<data.Count; ++i)
{
try
{
PointD pt = data[i];
if ( !Double.IsNaN(pt.X) && !Double.IsNaN(pt.Y) )
{
PointF xPos = xAxis.WorldToPhysical( pt.X, false);
PointF yPos = yAxis.WorldToPhysical( pt.Y, false);
Marker.Draw( g, (int)xPos.X, (int)yPos.Y );
if ( textData[i] != "" )
{
SizeF size = g.MeasureString( textData[i], this.Font );
switch (labelTextPosition_)
{
case LabelPositions.Above:
g.DrawString( textData[i], font_, Brushes.Black, new PointF(xPos.X-size.Width/2,yPos.Y-size.Height-Marker.Size*2/3));
break;
case LabelPositions.Below:
g.DrawString( textData[i], font_, Brushes.Black, new PointF(xPos.X-size.Width/2,yPos.Y+Marker.Size*2/3));
break;
case LabelPositions.Left:
g.DrawString( textData[i], font_, Brushes.Black, new PointF(xPos.X-size.Width-Marker.Size*2/3,yPos.Y-size.Height/2));
break;
case LabelPositions.Right:
g.DrawString( textData[i], font_, Brushes.Black, new PointF(xPos.X+Marker.Size*2/3,yPos.Y-size.Height/2));
break;
}
}
}
}
catch
{
throw new NPlotException("Error in TextPlot.Draw");
}
}
}
}
}

352
lib/Legend.cs Normal file
Просмотреть файл

@ -0,0 +1,352 @@
/*
NPlot - A charting library for .NET
Legend.cs
Copyright (C) 2003
Matt Howlett
Redistribution and use of NPlot or parts there-of in source and
binary forms, with or without modification, are permitted provided
that the following conditions are met:
1. Re-distributions in source form must retain at the head of each
source file the above copyright notice, this list of conditions
and the following disclaimer.
2. Any product ("the product") that makes use NPlot or parts
there-of must either:
(a) allow any user of the product to obtain a complete machine-
readable copy of the corresponding source code for the
product and the version of NPlot used for a charge no more
than your cost of physically performing source distribution,
on a medium customarily used for software interchange, or:
(b) reproduce the following text in the documentation, about
box or other materials intended to be read by human users
of the product that is provided to every human user of the
product:
"This product includes software developed as
part of the NPlot library project available
from: http://www.nplot.com/"
The words "This product" may optionally be replace with
the actual name of the product.
------------------------------------------------------------------------
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
using System;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Collections;
namespace NPlot
{
/// <summary>
/// Legend functionality specific to Legends associated with a PlotSurface2D.
/// </summary>
public class Legend : LegendBase
{
/// <summary>
/// Enumeration of possible Legend placements.
/// </summary>
public enum Placement
{
/// <summary>
/// Inside the plot area.
/// </summary>
Inside = 0,
/// <summary>
/// Outside the plot area.
/// </summary>
Outside = 1
}
private int xOffset_;
private int yOffset_;
private PlotSurface2D.XAxisPosition xAttach_;
private PlotSurface2D.YAxisPosition yAttach_;
private Placement horizontalEdgePlacement_;
private Placement verticalEdgePlacement_;
private bool neverShiftAxes_;
/// <summary>
/// Whether or not the positions of the Axes may be shifted to make
/// room for the Legend.
/// </summary>
public bool NeverShiftAxes
{
get
{
return neverShiftAxes_;
}
set
{
neverShiftAxes_ = value;
}
}
/// <summary>
/// Offset from the chosen Y-Axis. TODO: better description.
/// </summary>
public int XOffset
{
get
{
return xOffset_;
}
set
{
xOffset_ = value;
}
}
/// <summary>
/// Offset from the X-Axis. TODO: better description.
/// </summary>
public int YOffset
{
get
{
return yOffset_;
}
set
{
yOffset_ = value;
}
}
/// <summary>
/// Whether or not to attach the legend on the inside of the top
/// or bottom axis (which, is specified using the AttachTo method) or the
/// outside.
/// </summary>
public Legend.Placement VerticalEdgePlacement
{
get
{
return verticalEdgePlacement_;
}
set
{
verticalEdgePlacement_ = value;
}
}
/// <summary>
/// Whether or not to attach the legend on the inside of the
/// left or right axis (which, is specified using the AttachTo method)
/// or the outside.
/// </summary>
public Legend.Placement HorizontalEdgePlacement
{
get
{
return horizontalEdgePlacement_;
}
set
{
horizontalEdgePlacement_ = value;
}
}
/// <summary>
/// Specify the Axes to attach the legend to.
/// </summary>
/// <param name="xa">Specify which horizontal axis the legend should be attached to.</param>
/// <param name="ya">Specify which vertical axis the legend should be attached to.</param>
public void AttachTo( PlotSurface2D.XAxisPosition xa, PlotSurface2D.YAxisPosition ya )
{
xAttach_ = xa;
yAttach_ = ya;
}
/// <summary>
/// Default constructor.
/// </summary>
public Legend()
{
xAttach_ = PlotSurface2D.XAxisPosition.Top;
yAttach_ = PlotSurface2D.YAxisPosition.Right;
xOffset_ = 10;
yOffset_ = 1;
verticalEdgePlacement_ = Placement.Outside;
horizontalEdgePlacement_ = Placement.Inside;
neverShiftAxes_ = false;
}
/// <summary>
/// Updates the PlotSurface2D axes to compensate for the legend.
/// </summary>
/// <param name="pXAxis1">the bottom x axis</param>
/// <param name="pYAxis1">the left y axis</param>
/// <param name="pXAxis2">the top x axis</param>
/// <param name="pYAxis2">the right y axis</param>
/// <param name="plots">list of plots.</param>
/// <param name="scale">scale parameter (for text and other)</param>
/// <param name="padding">padding around plot within bounds.</param>
/// <param name="bounds">graphics surface bounds</param>
/// <param name="position">legend position</param>
public void UpdateAxesPositions(
PhysicalAxis pXAxis1,
PhysicalAxis pYAxis1,
PhysicalAxis pXAxis2,
PhysicalAxis pYAxis2,
ArrayList plots,
float scale, int padding, Rectangle bounds,
out Point position )
{
int leftIndent = 0;
int rightIndent = 0;
int bottomIndent = 0;
int topIndent = 0;
position = new Point(0,0);
// now determine if legend should change any of these (legend should be fully
// visible at all times), and draw legend.
Rectangle legendWidthHeight = this.GetBoundingBox( new Point(0,0), plots, scale );
if (legendWidthHeight.Width > bounds.Width)
{
legendWidthHeight.Width = bounds.Width;
}
// (1) calculate legend position.
// y
position.Y = this.yOffset_;
if ( this.xAttach_ == PlotSurface2D.XAxisPosition.Bottom )
{
position.Y += pYAxis1.PhysicalMin.Y;
if ( this.horizontalEdgePlacement_ == Legend.Placement.Inside )
{
position.Y -= legendWidthHeight.Height;
}
}
else
{
position.Y += pYAxis1.PhysicalMax.Y;
if ( this.horizontalEdgePlacement_ == Legend.Placement.Outside )
{
position.Y -= legendWidthHeight.Height;
}
}
// x
position.X = this.xOffset_;
if ( this.yAttach_ == PlotSurface2D.YAxisPosition.Left )
{
if ( this.verticalEdgePlacement_ == Legend.Placement.Outside )
{
position.X -= legendWidthHeight.Width;
}
position.X += pXAxis1.PhysicalMin.X;
}
else
{
if ( this.verticalEdgePlacement_ == Legend.Placement.Inside )
{
position.X -= legendWidthHeight.Width;
}
position.X += pXAxis1.PhysicalMax.X;
}
// determine update amounts for axes
if ( !this.neverShiftAxes_ )
{
if ( position.X < padding )
{
int changeAmount = -position.X + padding;
// only allow axes to move away from bounds.
if ( changeAmount > 0 )
{
leftIndent = changeAmount;
}
position.X += changeAmount;
}
if ( position.X + legendWidthHeight.Width > bounds.Right - padding )
{
int changeAmount = (position.X - bounds.Right + legendWidthHeight.Width + padding );
// only allow axes to move away from bounds.
if ( changeAmount > 0.0f )
{
rightIndent = changeAmount;
}
position.X -= changeAmount;
}
if ( position.Y < padding )
{
int changeAmount = -position.Y + padding;
// only allow axes to move away from bounds.
if ( changeAmount > 0.0f )
{
topIndent = changeAmount;
}
position.Y += changeAmount;
}
if ( position.Y + legendWidthHeight.Height > bounds.Bottom - padding )
{
int changeAmount = (position.Y - bounds.Bottom + legendWidthHeight.Height + padding );
// only allow axes to move away from bounds.
if ( changeAmount > 0.0f )
{
bottomIndent = changeAmount;
}
position.Y -= changeAmount;
}
// update axes.
pXAxis1.PhysicalMin = new Point( pXAxis1.PhysicalMin.X + leftIndent, pXAxis1.PhysicalMin.Y - bottomIndent );
pXAxis1.PhysicalMax = new Point( pXAxis1.PhysicalMax.X - rightIndent, pXAxis1.PhysicalMax.Y - bottomIndent );
pYAxis1.PhysicalMin = new Point( pYAxis1.PhysicalMin.X + leftIndent, pYAxis1.PhysicalMin.Y - bottomIndent );
pYAxis1.PhysicalMax = new Point( pYAxis1.PhysicalMax.X + leftIndent, pYAxis1.PhysicalMax.Y + topIndent );
pXAxis2.PhysicalMin = new Point( pXAxis2.PhysicalMin.X + leftIndent, pXAxis2.PhysicalMin.Y + topIndent );
pXAxis2.PhysicalMax = new Point( pXAxis2.PhysicalMax.X - rightIndent, pXAxis2.PhysicalMax.Y + topIndent );
pYAxis2.PhysicalMin = new Point( pYAxis2.PhysicalMin.X - rightIndent, pYAxis2.PhysicalMin.Y - bottomIndent );
pYAxis2.PhysicalMax = new Point( pYAxis2.PhysicalMax.X - rightIndent, pYAxis2.PhysicalMax.Y + topIndent );
}
}
}
}

459
lib/LegendBase.cs Normal file
Просмотреть файл

@ -0,0 +1,459 @@
/*
NPlot - A charting library for .NET
LegendBase.cs
Copyright (C) 2003
Matt Howlett
Redistribution and use of NPlot or parts there-of in source and
binary forms, with or without modification, are permitted provided
that the following conditions are met:
1. Re-distributions in source form must retain at the head of each
source file the above copyright notice, this list of conditions
and the following disclaimer.
2. Any product ("the product") that makes use NPlot or parts
there-of must either:
(a) allow any user of the product to obtain a complete machine-
readable copy of the corresponding source code for the
product and the version of NPlot used for a charge no more
than your cost of physically performing source distribution,
on a medium customarily used for software interchange, or:
(b) reproduce the following text in the documentation, about
box or other materials intended to be read by human users
of the product that is provided to every human user of the
product:
"This product includes software developed as
part of the NPlot library project available
from: http://www.nplot.com/"
The words "This product" may optionally be replace with
the actual name of the product.
------------------------------------------------------------------------
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
using System;
using System.Collections;
using System.Drawing;
namespace NPlot
{
/// <summary>
/// Provides functionality for drawing legends.
/// </summary>
/// <remarks>
/// The class is quite closely tied to PlotSurface2D.
/// </remarks>
public class LegendBase
{
/// <summary>
/// Constructor.
/// </summary>
public LegendBase()
{
this.Font = new Font( new FontFamily("Arial"), 10, FontStyle.Regular, GraphicsUnit.Pixel );
this.BackgroundColor = Color.White;
this.BorderColor = Color.Black;
this.TextColor = Color.Black;
this.borderStyle_ = BorderType.Shadow;
this.autoScaleText_ = false;
}
/// <summary>
/// Get the bounding box of the rectangle.
/// </summary>
/// <param name="position">the position of the top left of the legend.</param>
/// <param name="plots">Array of plot objects to appear in the legend.</param>
/// <param name="scale">if the legend is set to scale, the amount to scale by.</param>>
/// <returns></returns>
/// <remarks>do implementation that doesn't call draw. Change xPos, yPos to PointF</remarks>
public Rectangle GetBoundingBox( Point position, ArrayList plots, float scale )
{
System.Drawing.Bitmap b = new System.Drawing.Bitmap(1,1);
Graphics g = Graphics.FromImage(b);
return this.Draw( g, position, plots, scale );
}
/// <summary>
/// Draw The legend
/// </summary>
/// <param name="g">The graphics surface on which to draw</param>
/// <param name="position">The position of the top left of the axis.</param>
/// <param name="plots">Array of plot objects to appear in the legend.</param>
/// <param name="scale">if the legend is set to scale, the amount to scale by.</param>
/// <returns>bounding box</returns>
public Rectangle Draw( Graphics g, Point position, ArrayList plots, float scale )
{
// first of all determine the Font to use in the legend.
Font textFont;
if (this.AutoScaleText)
{
textFont = Utils.ScaleFont( this.font_, scale );
}
else
{
textFont = this.font_;
}
// determine max width and max height of label strings and
// count the labels.
int labelCount = 0;
int maxHt = 0;
int maxWd = 0;
int unnamedCount = 0;
for (int i=0; i<plots.Count; ++i)
{
if (!(plots[i] is IPlot))
{
continue;
}
IPlot p = (IPlot)plots[i];
if (!p.ShowInLegend)
{
continue;
}
string label = p.Label;
if (label == "")
{
unnamedCount += 1;
label = "Series " + unnamedCount.ToString();
}
SizeF labelSize = g.MeasureString( label, textFont );
if ( labelSize.Height > maxHt )
{
maxHt = (int)labelSize.Height;
}
if ( labelSize.Width > maxWd )
{
maxWd = (int)labelSize.Width;
}
++labelCount;
}
bool extendingHorizontally = numberItemsHorizontally_ == -1;
bool extendingVertically = numberItemsVertically_ == -1;
// determine width in legend items count units.
int widthInItemCount = 0;
if (extendingVertically)
{
if (labelCount >= numberItemsHorizontally_)
{
widthInItemCount = numberItemsHorizontally_;
}
else
{
widthInItemCount = labelCount;
}
}
else if (extendingHorizontally)
{
widthInItemCount = labelCount / numberItemsVertically_;
if (labelCount % numberItemsVertically_ != 0)
widthInItemCount += 1;
}
else
{
throw new NPlotException( "logic error in legend base" );
}
// determine height of legend in items count units.
int heightInItemCount = 0;
if (extendingHorizontally)
{
if (labelCount >= numberItemsVertically_)
{
heightInItemCount = numberItemsVertically_;
}
else
{
heightInItemCount = labelCount;
}
}
else // extendingVertically
{
heightInItemCount = labelCount / numberItemsHorizontally_;
if (labelCount % numberItemsHorizontally_ != 0)
heightInItemCount += 1;
}
int lineLength = 20;
int hSpacing = (int)(5.0f * scale);
int vSpacing = (int)(3.0f * scale);
int boxWidth = (int) ((float)widthInItemCount * (lineLength + maxWd + hSpacing * 2.0f ) + hSpacing);
int boxHeight = (int)((float)heightInItemCount * (maxHt + vSpacing) + vSpacing);
int totalWidth = boxWidth;
int totalHeight = boxHeight;
// draw box around the legend.
if ( this.BorderStyle == BorderType.Line )
{
g.FillRectangle( new SolidBrush( this.bgColor_ ), position.X, position.Y, boxWidth, boxHeight );
g.DrawRectangle( new Pen( this.borderColor_ ), position.X, position.Y, boxWidth, boxHeight );
}
else if ( this.BorderStyle == BorderType.Shadow )
{
int offset = (int)(4.0f * scale);
g.FillRectangle( new SolidBrush( Color.FromArgb(128, Color.Gray) ), position.X+offset, position.Y+offset, boxWidth, boxHeight );
g.FillRectangle( new SolidBrush( this.bgColor_ ), position.X, position.Y, boxWidth, boxHeight );
g.DrawRectangle( new Pen( this.borderColor_ ), position.X, position.Y, boxWidth, boxHeight );
totalWidth += offset;
totalHeight += offset;
}
/*
else if ( this.BorderStyle == BorderType.Curved )
{
// TODO. make this nice.
}
*/
else
{
// do nothing.
}
// now draw entries in box..
labelCount = 0;
unnamedCount = 0;
int plotCount = -1;
for (int i=0; i<plots.Count; ++i)
{
if (!(plots[i] is IPlot))
{
continue;
}
IPlot p = (IPlot)plots[i];
if (!p.ShowInLegend)
{
continue;
}
plotCount += 1;
int xpos, ypos;
if (extendingVertically)
{
xpos = plotCount % numberItemsHorizontally_;
ypos = plotCount / numberItemsHorizontally_;
}
else
{
xpos = plotCount / numberItemsVertically_;
ypos = plotCount % numberItemsVertically_;
}
int lineXPos = (int)(position.X + hSpacing + xpos * (lineLength + maxWd + hSpacing * 2.0f));
int lineYPos = (int)(position.Y + vSpacing + ypos * (vSpacing + maxHt));
p.DrawInLegend( g, new Rectangle( lineXPos, lineYPos, lineLength, maxHt ) );
int textXPos = lineXPos + hSpacing + lineLength;
int textYPos = lineYPos;
string label = p.Label;
if (label == "")
{
unnamedCount += 1;
label = "Series " + unnamedCount.ToString();
}
g.DrawString( label, textFont,
new SolidBrush( this.textColor_ ), textXPos, textYPos );
++labelCount;
}
return new Rectangle( position.X, position.Y, totalWidth, totalHeight );
}
/// <summary>
/// The font used to draw text in the legend.
/// </summary>
public Font Font
{
get
{
return this.font_;
}
set
{
this.font_ = value;
}
}
private Font font_;
/// <summary>
/// The color used to draw text in the legend.
/// </summary>
public Color TextColor
{
get
{
return this.textColor_;
}
set
{
this.textColor_ = value;
}
}
Color textColor_;
/// <summary>
/// The background color of the legend.
/// </summary>
public Color BackgroundColor
{
get
{
return bgColor_;
}
set
{
bgColor_ = value;
}
}
Color bgColor_;
/// <summary>
/// The color of the legend border.
/// </summary>
public Color BorderColor
{
get
{
return borderColor_;
}
set
{
borderColor_ = value;
}
}
Color borderColor_;
/// <summary>
/// The types of legend borders (enum).
/// </summary>
public enum BorderType
{
/// <summary>
/// No border.
/// </summary>
None = 0,
/// <summary>
/// Line border.
/// </summary>
Line = 1,
/// <summary>
/// Shaded border.
/// </summary>
Shadow = 2
//Curved = 3
}
/// <summary>
/// The border style to use for the legend.
/// </summary>
public Legend.BorderType BorderStyle
{
get
{
return borderStyle_;
}
set
{
borderStyle_ = value;
}
}
private NPlot.Legend.BorderType borderStyle_;
/// <summary>
/// Whether or not to auto scale text in the legend according the physical
/// dimensions of the plot surface.
/// </summary>
public bool AutoScaleText
{
get
{
return autoScaleText_;
}
set
{
autoScaleText_ = value;
}
}
bool autoScaleText_;
/// <summary>
/// Setting this does two things. First of all, it sets the maximum number of
/// items in the legend vertically. Second of all, it makes the legend grow
/// horizontally (as it must given this constraint).
/// </summary>
public int NumberItemsVertically
{
set
{
this.numberItemsVertically_ = value;
this.numberItemsHorizontally_ = -1;
}
}
int numberItemsVertically_ = -1;
/// <summary>
/// Setting this does two things. First of all, it sets the maximum number of
/// items in the legend horizontally. Second of all, it makes the legend grow
/// vertically (as it must given this constraint).
/// </summary>
public int NumberItemsHorizontally
{
set
{
this.numberItemsHorizontally_ = value;
this.numberItemsVertically_ = -1;
}
}
int numberItemsHorizontally_ = 1;
}
}

355
lib/LinePlot.cs Normal file
Просмотреть файл

@ -0,0 +1,355 @@
/*
NPlot - A charting library for .NET
LinePlot.cs
Copyright (C) 2003
Matt Howlett
Redistribution and use of NPlot or parts there-of in source and
binary forms, with or without modification, are permitted provided
that the following conditions are met:
1. Re-distributions in source form must retain at the head of each
source file the above copyright notice, this list of conditions
and the following disclaimer.
2. Any product ("the product") that makes use NPlot or parts
there-of must either:
(a) allow any user of the product to obtain a complete machine-
readable copy of the corresponding source code for the
product and the version of NPlot used for a charge no more
than your cost of physically performing source distribution,
on a medium customarily used for software interchange, or:
(b) reproduce the following text in the documentation, about
box or other materials intended to be read by human users
of the product that is provided to every human user of the
product:
"This product includes software developed as
part of the NPlot library project available
from: http://www.nplot.com/"
The words "This product" may optionally be replace with
the actual name of the product.
------------------------------------------------------------------------
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
using System;
using System.Drawing;
using System.Diagnostics;
namespace NPlot
{
/// <summary>
/// Encapsulates functionality for plotting data as a line chart.
/// </summary>
public class LinePlot : BaseSequencePlot, IPlot, ISequencePlot
{
/// <summary>
/// Default constructor
/// </summary>
public LinePlot()
{
}
/// <summary>
/// Constructor
/// </summary>
/// <param name="dataSource">The data source to associate with this plot</param>
public LinePlot( object dataSource )
{
this.DataSource = dataSource;
}
/// <summary>
/// Constructor
/// </summary>
/// <param name="ordinateData">the ordinate data to associate with this plot.</param>
/// <param name="abscissaData">the abscissa data to associate with this plot.</param>
public LinePlot( object ordinateData, object abscissaData )
{
this.OrdinateData = ordinateData;
this.AbscissaData = abscissaData;
}
/// <summary>
/// Draws the line plot on a GDI+ surface against the provided x and y axes.
/// </summary>
/// <param name="g">The GDI+ surface on which to draw.</param>
/// <param name="xAxis">The X-Axis to draw against.</param>
/// <param name="yAxis">The Y-Axis to draw against.</param>
/// <param name="drawShadow">If true draw the shadow for the line. If false, draw line.</param>
public void DrawLineOrShadow( Graphics g, PhysicalAxis xAxis, PhysicalAxis yAxis, bool drawShadow )
{
Pen shadowPen = null;
if (drawShadow)
{
shadowPen = (Pen)this.Pen.Clone();
shadowPen.Color = this.ShadowColor;
}
SequenceAdapter data =
new SequenceAdapter( this.DataSource, this.DataMember, this.OrdinateData, this.AbscissaData );
ITransform2D t = Transform2D.GetTransformer( xAxis, yAxis );
int numberPoints = data.Count;
if (data.Count == 0)
{
return;
}
// clipping is now handled assigning a clip region in the
// graphic object before this call
if (numberPoints == 1)
{
PointF physical = t.Transform( data[0] );
if (drawShadow)
{
g.DrawLine( shadowPen,
physical.X - 0.5f + this.ShadowOffset.X,
physical.Y + this.ShadowOffset.Y,
physical.X + 0.5f + this.ShadowOffset.X,
physical.Y + this.ShadowOffset.Y );
}
else
{
g.DrawLine( Pen, physical.X-0.5f, physical.Y, physical.X+0.5f, physical.Y);
}
}
else
{
// prepare for clipping
double leftCutoff = xAxis.PhysicalToWorld(xAxis.PhysicalMin, false);
double rightCutoff = xAxis.PhysicalToWorld(xAxis.PhysicalMax, false);
if (leftCutoff > rightCutoff)
{
Utils.Swap(ref leftCutoff, ref rightCutoff);
}
if (drawShadow)
{
// correct cut-offs
double shadowCorrection =
xAxis.PhysicalToWorld(ShadowOffset, false) - xAxis.PhysicalToWorld(new Point(0,0), false);
leftCutoff -= shadowCorrection;
rightCutoff -= shadowCorrection;
}
for (int i = 1; i < numberPoints; ++i)
{
// check to see if any values null. If so, then continue.
double dx1 = data[i-1].X;
double dx2 = data[i].X;
double dy1 = data[i-1].Y;
double dy2 = data[i].Y;
if ( Double.IsNaN(dx1) || Double.IsNaN(dy1) ||
Double.IsNaN(dx2) || Double.IsNaN(dy2) )
{
continue;
}
// do horizontal clipping here, to speed up
if ((dx1 < leftCutoff || rightCutoff < dx1) &&
(dx2 < leftCutoff || rightCutoff < dx2))
{
continue;
}
// else draw line.
PointF p1 = t.Transform( data[i-1] );
PointF p2 = t.Transform( data[i] );
// when very far zoomed in, points can fall ontop of each other,
// and g.DrawLine throws an overflow exception
if (p1.Equals(p2))
continue;
if (drawShadow)
{
g.DrawLine( shadowPen,
p1.X + ShadowOffset.X,
p1.Y + ShadowOffset.Y,
p2.X + ShadowOffset.X,
p2.Y + ShadowOffset.Y );
}
else
{
g.DrawLine( Pen, p1.X, p1.Y, p2.X, p2.Y );
}
}
}
}
/// <summary>
/// Draws the line plot on a GDI+ surface against the provided x and y axes.
/// </summary>
/// <param name="g">The GDI+ surface on which to draw.</param>
/// <param name="xAxis">The X-Axis to draw against.</param>
/// <param name="yAxis">The Y-Axis to draw against.</param>
public void Draw( Graphics g, PhysicalAxis xAxis, PhysicalAxis yAxis )
{
if (this.shadow_)
{
this.DrawLineOrShadow( g, xAxis, yAxis, true );
}
this.DrawLineOrShadow( g, xAxis, yAxis, false );
}
/// <summary>
/// Returns an x-axis that is suitable for drawing this plot.
/// </summary>
/// <returns>A suitable x-axis.</returns>
public Axis SuggestXAxis()
{
SequenceAdapter data_ =
new SequenceAdapter( this.DataSource, this.DataMember, this.OrdinateData, this.AbscissaData );
return data_.SuggestXAxis();
}
/// <summary>
/// Returns a y-axis that is suitable for drawing this plot.
/// </summary>
/// <returns>A suitable y-axis.</returns>
public Axis SuggestYAxis()
{
SequenceAdapter data_ =
new SequenceAdapter( this.DataSource, this.DataMember, this.OrdinateData, this.AbscissaData );
return data_.SuggestYAxis();
}
/// <summary>
/// If true, draw a shadow under the line.
/// </summary>
public bool Shadow
{
get
{
return shadow_;
}
set
{
shadow_ = value;
}
}
private bool shadow_ = false;
/// <summary>
/// Color of line shadow if drawn. Use Shadow method to turn shadow on and off.
/// </summary>
public Color ShadowColor
{
get
{
return shadowColor_;
}
set
{
shadowColor_ = value;
}
}
private Color shadowColor_ = Color.FromArgb(100,100,100);
/// <summary>
/// Offset of shadow line from primary line.
/// </summary>
public Point ShadowOffset
{
get
{
return shadowOffset_;
}
set
{
shadowOffset_ = value;
}
}
private Point shadowOffset_ = new Point( 1, 1 );
/// <summary>
/// Draws a representation of this plot in the legend.
/// </summary>
/// <param name="g">The graphics surface on which to draw.</param>
/// <param name="startEnd">A rectangle specifying the bounds of the area in the legend set aside for drawing.</param>
public virtual void DrawInLegend(Graphics g, Rectangle startEnd)
{
g.DrawLine(pen_, startEnd.Left, (startEnd.Top + startEnd.Bottom) / 2,
startEnd.Right, (startEnd.Top + startEnd.Bottom) / 2);
}
/// <summary>
/// The pen used to draw the plot
/// </summary>
public System.Drawing.Pen Pen
{
get
{
return pen_;
}
set
{
pen_ = value;
}
}
private System.Drawing.Pen pen_ = new Pen(Color.Black);
/// <summary>
/// The color of the pen used to draw lines in this plot.
/// </summary>
public System.Drawing.Color Color
{
set
{
if (pen_ != null)
{
pen_.Color = value;
}
else
{
pen_ = new Pen(value);
}
}
get
{
return pen_.Color;
}
}
}
}

650
lib/LinearAxis.cs Normal file
Просмотреть файл

@ -0,0 +1,650 @@
/*
NPlot - A charting library for .NET
LinearAxis.cs
Copyright (C) 2003
Matt Howlett
Redistribution and use of NPlot or parts there-of in source and
binary forms, with or without modification, are permitted provided
that the following conditions are met:
1. Re-distributions in source form must retain at the head of each
source file the above copyright notice, this list of conditions
and the following disclaimer.
2. Any product ("the product") that makes use NPlot or parts
there-of must either:
(a) allow any user of the product to obtain a complete machine-
readable copy of the corresponding source code for the
product and the version of NPlot used for a charge no more
than your cost of physically performing source distribution,
on a medium customarily used for software interchange, or:
(b) reproduce the following text in the documentation, about
box or other materials intended to be read by human users
of the product that is provided to every human user of the
product:
"This product includes software developed as
part of the NPlot library project available
from: http://www.nplot.com/"
The words "This product" may optionally be replace with
the actual name of the product.
------------------------------------------------------------------------
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
using System.Drawing;
using System.Collections;
using System;
using System.Text;
using System.Diagnostics;
namespace NPlot
{
/// <summary>
/// Provides functionality for drawing axes with a linear numeric scale.
/// </summary>
public class LinearAxis : Axis, System.ICloneable
{
/// <summary>
/// Deep copy of LinearAxis.
/// </summary>
/// <returns>A copy of the LinearAxis Class</returns>
public override object Clone()
{
LinearAxis a = new LinearAxis();
// ensure that this isn't being called on a derived type. If it is, then oh no!
if (this.GetType() != a.GetType())
{
throw new NPlotException( "Clone not defined in derived type. Help!" );
}
this.DoClone( this, a );
return a;
}
/// <summary>
/// Helper method for Clone.
/// </summary>
protected void DoClone( LinearAxis b, LinearAxis a )
{
Axis.DoClone( b, a );
a.numberSmallTicks_ = b.numberSmallTicks_;
a.largeTickValue_ = b.largeTickValue_;
a.largeTickStep_ = b.largeTickStep_;
a.offset_ = b.offset_;
a.scale_ = b.scale_;
}
/// <summary>
/// Copy constructor
/// </summary>
/// <param name="a">The Axis to clone</param>
public LinearAxis( Axis a )
: base( a )
{
Init();
}
/// <summary>
/// Default constructor.
/// </summary>
public LinearAxis()
: base()
{
Init();
}
/// <summary>
/// Construct a linear axis with the provided world min and max values.
/// </summary>
/// <param name="worldMin">the world minimum value of the axis.</param>
/// <param name="worldMax">the world maximum value of the axis.</param>
public LinearAxis( double worldMin, double worldMax )
: base( worldMin, worldMax )
{
Init();
}
private void Init()
{
this.NumberFormat = "{0:g5}";
}
/// <summary>
/// Draws the large and small ticks [and tick labels] for this axis.
/// </summary>
/// <param name="g">The graphics surface on which to draw.</param>
/// <param name="physicalMin">The physical position corresponding to the world minimum of the axis.</param>
/// <param name="physicalMax">The physical position corresponding to the world maximum of the axis.</param>
/// <param name="boundingBox">out: smallest box that completely surrounds all ticks and associated labels for this axis.</param>
/// <param name="labelOffset">out: offset from the axis to draw the axis label.</param>
protected override void DrawTicks(
Graphics g,
Point physicalMin,
Point physicalMax,
out object labelOffset,
out object boundingBox )
{
Point tLabelOffset;
Rectangle tBoundingBox;
labelOffset = this.getDefaultLabelOffset( physicalMin, physicalMax );
boundingBox = null;
ArrayList largeTickPositions;
ArrayList smallTickPositions;
this.WorldTickPositions( physicalMin, physicalMax, out largeTickPositions, out smallTickPositions );
labelOffset = new Point( 0, 0 );
boundingBox = null;
if (largeTickPositions.Count > 0)
{
for (int i = 0; i < largeTickPositions.Count; ++i)
{
double labelNumber = (double)largeTickPositions[i];
// TODO: Find out why zero is sometimes significantly not zero [seen as high as 10^-16].
if (Math.Abs(labelNumber) < 0.000000000000001)
{
labelNumber = 0.0;
}
StringBuilder label = new StringBuilder();
label.AppendFormat(this.NumberFormat, labelNumber);
this.DrawTick( g, ((double)largeTickPositions[i]/this.scale_-this.offset_),
this.LargeTickSize, label.ToString(),
new Point(0,0), physicalMin, physicalMax,
out tLabelOffset, out tBoundingBox );
Axis.UpdateOffsetAndBounds( ref labelOffset, ref boundingBox,
tLabelOffset, tBoundingBox );
}
}
for (int i = 0; i<smallTickPositions.Count; ++i)
{
this.DrawTick( g, ((double)smallTickPositions[i]/this.scale_-this.offset_),
this.SmallTickSize, "",
new Point(0, 0), physicalMin, physicalMax,
out tLabelOffset, out tBoundingBox );
// assume bounding box and label offset unchanged by small tick bounds.
}
}
/// <summary>
/// Determines the positions, in world coordinates, of the small ticks
/// if they have not already been generated.
///
/// </summary>
/// <param name="physicalMin">The physical position corresponding to the world minimum of the axis.</param>
/// <param name="physicalMax">The physical position corresponding to the world maximum of the axis.</param>
/// <param name="largeTickPositions">The positions of the large ticks.</param>
/// <param name="smallTickPositions">If null, small tick positions are returned via this parameter. Otherwise this function does nothing.</param>
internal override void WorldTickPositions_SecondPass(
Point physicalMin,
Point physicalMax,
ArrayList largeTickPositions,
ref ArrayList smallTickPositions )
{
// return if already generated.
if (smallTickPositions != null)
return;
int physicalAxisLength = Utils.Distance( physicalMin, physicalMax );
double adjustedMax = this.AdjustedWorldValue( WorldMax );
double adjustedMin = this.AdjustedWorldValue( WorldMin );
smallTickPositions = new ArrayList();
// TODO: Can optimize this now.
bool shouldCullMiddle;
double bigTickSpacing = this.DetermineLargeTickStep( physicalAxisLength, out shouldCullMiddle );
int nSmall = this.DetermineNumberSmallTicks( bigTickSpacing );
double smallTickSpacing = bigTickSpacing / (double)nSmall;
// if there is at least one big tick
if (largeTickPositions.Count > 0)
{
double pos1 = (double)largeTickPositions[0] - smallTickSpacing;
while (pos1 > adjustedMin)
{
smallTickPositions.Add( pos1 );
pos1 -= smallTickSpacing;
}
}
for (int i = 0; i < largeTickPositions.Count; ++i )
{
for (int j = 1; j < nSmall; ++j )
{
double pos = (double)largeTickPositions[i] + ((double)j) * smallTickSpacing;
if (pos <= adjustedMax)
{
smallTickPositions.Add( pos );
}
}
}
}
/// <summary>
/// Adjusts a real world value to one that has been modified to
/// reflect the Axis Scale and Offset properties.
/// </summary>
/// <param name="world">world value to adjust</param>
/// <returns>adjusted world value</returns>
public double AdjustedWorldValue( double world )
{
return world * this.scale_ + this.offset_;
}
/// <summary>
/// Determines the positions, in world coordinates, of the large ticks.
/// When the physical extent of the axis is small, some of the positions
/// that were generated in this pass may be converted to small tick
/// positions and returned as well.
///
/// If the LargeTickStep isn't set then this is calculated automatically and
/// depends on the physical extent of the axis.
/// </summary>
/// <param name="physicalMin">The physical position corresponding to the world minimum of the axis.</param>
/// <param name="physicalMax">The physical position corresponding to the world maximum of the axis.</param>
/// <param name="largeTickPositions">ArrayList containing the positions of the large ticks.</param>
/// <param name="smallTickPositions">ArrayList containing the positions of the small ticks if calculated, null otherwise.</param>
internal override void WorldTickPositions_FirstPass(
Point physicalMin,
Point physicalMax,
out ArrayList largeTickPositions,
out ArrayList smallTickPositions
)
{
// (1) error check
if ( double.IsNaN(WorldMin) || double.IsNaN(WorldMax) )
{
throw new NPlotException( "world extent of axis not set." );
}
double adjustedMax = this.AdjustedWorldValue( WorldMax );
double adjustedMin = this.AdjustedWorldValue( WorldMin );
// (2) determine distance between large ticks.
bool shouldCullMiddle;
double tickDist = this.DetermineLargeTickStep(
Utils.Distance(physicalMin, physicalMax),
out shouldCullMiddle );
// (3) determine starting position.
double first = 0.0f;
if (!double.IsNaN(largeTickValue_))
{
// this works for both case when largTickValue_ lt or gt adjustedMin.
first = largeTickValue_ + (Math.Ceiling((adjustedMin-largeTickValue_)/tickDist))*tickDist;
}
else
{
if( adjustedMin > 0.0 )
{
double nToFirst = Math.Floor(adjustedMin / tickDist) + 1.0f;
first = nToFirst * tickDist;
}
else
{
double nToFirst = Math.Floor(-adjustedMin/tickDist) - 1.0f;
first = -nToFirst * tickDist;
}
// could miss one, if first is just below zero.
if ((first - tickDist) >= adjustedMin)
{
first -= tickDist;
}
}
// (4) now make list of large tick positions.
largeTickPositions = new ArrayList();
if (tickDist < 0.0) // some sanity checking. TODO: remove this.
throw new NPlotException( "Tick dist is negative" );
double position = first;
int safetyCount = 0;
while (
(position <= adjustedMax) &&
(++safetyCount < 5000) )
{
largeTickPositions.Add( position );
position += tickDist;
}
// (5) if the physical extent is too small, and the middle
// ticks should be turned into small ticks, then do this now.
smallTickPositions = null;
if (shouldCullMiddle)
{
smallTickPositions = new ArrayList();
if (largeTickPositions.Count > 2)
{
for (int i=1; i<largeTickPositions.Count-1; ++i)
{
smallTickPositions.Add( largeTickPositions[i] );
}
}
ArrayList culledPositions = new ArrayList();
culledPositions.Add( largeTickPositions[0] );
culledPositions.Add( largeTickPositions[largeTickPositions.Count-1] );
largeTickPositions = culledPositions;
}
}
/// <summary>
/// Calculates the world spacing between large ticks, based on the physical
/// axis length (parameter), world axis length, Mantissa values and
/// MinPhysicalLargeTickStep. A value such that at least two
/// </summary>
/// <param name="physicalLength">physical length of the axis</param>
/// <param name="shouldCullMiddle">Returns true if we were forced to make spacing of
/// large ticks too small in order to ensure that there are at least two of
/// them. The draw ticks method should not draw more than two large ticks if this
/// returns true.</param>
/// <returns>Large tick spacing</returns>
/// <remarks>TODO: This can be optimised a bit.</remarks>
private double DetermineLargeTickStep( float physicalLength, out bool shouldCullMiddle )
{
shouldCullMiddle = false;
if ( double.IsNaN(WorldMin) || double.IsNaN(WorldMax) )
{
throw new NPlotException( "world extent of axis not set." );
}
// if the large tick has been explicitly set, then return this.
if ( !double.IsNaN(largeTickStep_) )
{
if ( largeTickStep_ <= 0.0f )
{
throw new NPlotException(
"can't have negative or zero tick step - reverse WorldMin WorldMax instead."
);
}
return largeTickStep_;
}
// otherwise we need to calculate the large tick step ourselves.
// adjust world max and min for offset and scale properties of axis.
double adjustedMax = this.AdjustedWorldValue( WorldMax );
double adjustedMin = this.AdjustedWorldValue( WorldMin );
double range = adjustedMax - adjustedMin;
// if axis has zero world length, then return arbitrary number.
if ( Utils.DoubleEqual( adjustedMax, adjustedMin ) )
{
return 1.0f;
}
double approxTickStep;
if (TicksIndependentOfPhysicalExtent)
{
approxTickStep = range / 6.0f;
}
else
{
approxTickStep = (MinPhysicalLargeTickStep / physicalLength) * range;
}
double exponent = Math.Floor( Math.Log10( approxTickStep ) );
double mantissa = Math.Pow( 10.0, Math.Log10( approxTickStep ) - exponent );
// determine next whole mantissa below the approx one.
int mantissaIndex = Mantissas.Length-1;
for (int i=1; i<Mantissas.Length; ++i)
{
if (mantissa < Mantissas[i])
{
mantissaIndex = i-1;
break;
}
}
// then choose next largest spacing.
mantissaIndex += 1;
if (mantissaIndex == Mantissas.Length)
{
mantissaIndex = 0;
exponent += 1.0;
}
if (!TicksIndependentOfPhysicalExtent)
{
// now make sure that the returned value is such that at least two
// large tick marks will be displayed.
double tickStep = Math.Pow( 10.0, exponent ) * Mantissas[mantissaIndex];
float physicalStep = (float)((tickStep / range) * physicalLength);
while (physicalStep > physicalLength/2)
{
shouldCullMiddle = true;
mantissaIndex -= 1;
if (mantissaIndex == -1)
{
mantissaIndex = Mantissas.Length-1;
exponent -= 1.0;
}
tickStep = Math.Pow( 10.0, exponent ) * Mantissas[mantissaIndex];
physicalStep = (float)((tickStep / range) * physicalLength);
}
}
// and we're done.
return Math.Pow( 10.0, exponent ) * Mantissas[mantissaIndex];
}
/// <summary>
/// Given the large tick step, determine the number of small ticks that should
/// be placed in between.
/// </summary>
/// <param name="bigTickDist">the large tick step.</param>
/// <returns>the number of small ticks to place between large ticks.</returns>
private int DetermineNumberSmallTicks( double bigTickDist )
{
if (this.numberSmallTicks_ != null)
{
return (int)this.numberSmallTicks_+1;
}
if (this.SmallTickCounts.Length != this.Mantissas.Length)
{
throw new NPlotException( "Mantissa.Length != SmallTickCounts.Length" );
}
if (bigTickDist > 0.0f)
{
double exponent = Math.Floor( Math.Log10( bigTickDist ) );
double mantissa = Math.Pow( 10.0, Math.Log10( bigTickDist ) - exponent );
for (int i=0; i<Mantissas.Length; ++i)
{
if ( Math.Abs(mantissa-Mantissas[i]) < 0.001 )
{
return SmallTickCounts[i]+1;
}
}
}
return 0;
}
/// <summary>
/// The distance between large ticks. If this is set to NaN [default],
/// this distance will be calculated automatically.
/// </summary>
public double LargeTickStep
{
set
{
largeTickStep_ = value;
}
get
{
return largeTickStep_;
}
}
/// <summary>
/// If set !NaN, gives the distance between large ticks.
/// </summary>
private double largeTickStep_ = double.NaN;
/// <summary>
/// If set, a large tick will be placed at this position, and other large ticks will
/// be placed relative to this position.
/// </summary>
public double LargeTickValue
{
set
{
largeTickValue_ = value;
}
get
{
return largeTickValue_;
}
}
private double largeTickValue_ = double.NaN;
/// <summary>
/// The number of small ticks between large ticks.
/// </summary>
public int NumberOfSmallTicks
{
set
{
numberSmallTicks_ = value;
}
get
{
// TODO: something better here.
return (int)numberSmallTicks_;
}
}
private object numberSmallTicks_ = null;
/// <summary>
/// Scale to apply to world values when labelling axis:
/// (labelWorld = world * scale + offset). This does not
/// affect the "real" world range of the axis.
/// </summary>
public double Scale
{
get
{
return scale_;
}
set
{
scale_ = value;
}
}
/// <summary>
/// Offset to apply to world values when labelling the axis:
/// (labelWorld = axisWorld * scale + offset). This does not
/// affect the "real" world range of the axis.
/// </summary>
public double Offset
{
get
{
return offset_;
}
set
{
offset_ = value;
}
}
/// <summary>
/// If LargeTickStep isn't specified, then a suitable value is
/// calculated automatically. To determine the tick spacing, the
/// world axis length is divided by ApproximateNumberLargeTicks
/// and the next lowest distance m*10^e for some m in the Mantissas
/// set and some integer e is used as the large tick spacing.
/// </summary>
public float ApproxNumberLargeTicks = 3.0f;
/// <summary>
/// If LargeTickStep isn't specified, then a suitable value is
/// calculated automatically. The value will be of the form
/// m*10^e for some m in this set.
/// </summary>
public double[] Mantissas = {1.0, 2.0, 5.0};
/// <summary>
/// If NumberOfSmallTicks isn't specified then ....
/// If specified LargeTickStep manually, then no small ticks unless
/// NumberOfSmallTicks specified.
/// </summary>
public int[] SmallTickCounts = {4, 1, 4};
private double offset_ = 0.0;
private double scale_ = 1.0;
}
}

159
lib/LinearGradient.cs Normal file
Просмотреть файл

@ -0,0 +1,159 @@
/*
NPlot - A charting library for .NET
Gradient.cs
Copyright (C) 2003
Matt Howlett
Redistribution and use of NPlot or parts there-of in source and
binary forms, with or without modification, are permitted provided
that the following conditions are met:
1. Re-distributions in source form must retain at the head of each
source file the above copyright notice, this list of conditions
and the following disclaimer.
2. Any product ("the product") that makes use NPlot or parts
there-of must either:
(a) allow any user of the product to obtain a complete machine-
readable copy of the corresponding source code for the
product and the version of NPlot used for a charge no more
than your cost of physically performing source distribution,
on a medium customarily used for software interchange, or:
(b) reproduce the following text in the documentation, about
box or other materials intended to be read by human users
of the product that is provided to every human user of the
product:
"This product includes software developed as
part of the NPlot library project available
from: http://www.nplot.com/"
The words "This product" may optionally be replace with
the actual name of the product.
------------------------------------------------------------------------
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
using System;
using System.Drawing;
namespace NPlot
{
/// <summary>
/// Class for creating a linear gradient.
/// </summary>
public class LinearGradient : IGradient
{
/// <summary>
/// Constructor.
/// </summary>
/// <param name="minColor">The color corresponding to 0.0</param>
/// <param name="maxColor">The color corresponding to 1.0</param>
public LinearGradient( Color minColor, Color maxColor )
{
this.minColor_ = minColor;
this.maxColor_ = maxColor;
}
/// <summary>
/// The color corresponding to 0.0
/// </summary>
public Color MaxColor
{
get
{
return this.maxColor_;
}
set
{
this.maxColor_ = value;
}
}
private Color maxColor_;
/// <summary>
/// The color corresponding to 1.0
/// </summary>
public Color MinColor
{
get
{
return this.minColor_;
}
set
{
this.minColor_ = value;
}
}
private Color minColor_;
/// <summary>
/// The color corresponding to NaN
/// </summary>
public Color VoidColor
{
get
{
return voidColor_;
}
set
{
voidColor_ = value;
}
}
private Color voidColor_ = Color.Black;
/// <summary>
/// Gets a color corresponding to a number between 0.0 and 1.0 inclusive. The color will
/// be a linear interpolation of the min and max colors.
/// </summary>
/// <param name="prop">the number to get corresponding color for (between 0.0 and 1.0)</param>
/// <returns>The color corresponding to the supplied number.</returns>
public Color GetColor( double prop )
{
if (Double.IsNaN(prop))
{
return voidColor_;
}
if ( prop <= 0.0 )
{
return this.MinColor;
}
if ( prop >= 1.0 )
{
return this.MaxColor;
}
byte r = (byte)((int)(this.MinColor.R) + (int)(((double)this.MaxColor.R - (double)this.MinColor.R)*prop));
byte g = (byte)((int)(this.MinColor.G) + (int)(((double)this.MaxColor.G - (double)this.MinColor.G)*prop));
byte b = (byte)((int)(this.MinColor.B) + (int)(((double)this.MaxColor.B - (double)this.MinColor.B)*prop));
return Color.FromArgb(r,g,b);
}
}
}

678
lib/LogAxis.cs Normal file
Просмотреть файл

@ -0,0 +1,678 @@
/*
NPlot - A charting library for .NET
LogAxis.cs
Copyright (C) 2003
Paolo Pierini, Matt Howlett
Redistribution and use of NPlot or parts there-of in source and
binary forms, with or without modification, are permitted provided
that the following conditions are met:
1. Re-distributions in source form must retain at the head of each
source file the above copyright notice, this list of conditions
and the following disclaimer.
2. Any product ("the product") that makes use NPlot or parts
there-of must either:
(a) allow any user of the product to obtain a complete machine-
readable copy of the corresponding source code for the
product and the version of NPlot used for a charge no more
than your cost of physically performing source distribution,
on a medium customarily used for software interchange, or:
(b) reproduce the following text in the documentation, about
box or other materials intended to be read by human users
of the product that is provided to every human user of the
product:
"This product includes software developed as
part of the NPlot library project available
from: http://www.nplot.com/"
The words "This product" may optionally be replace with
the actual name of the product.
------------------------------------------------------------------------
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
using System;
using System.Drawing;
using System.Collections;
using System.Text;
namespace NPlot
{
/// <summary>
/// The class implementing logarithmic axes.
/// </summary>
public class LogAxis : Axis
{
/// <summary>
/// Deep Copy of the LogAxis.
/// </summary>
/// <returns>A Copy of the LogAxis Class.</returns>
public override object Clone()
{
LogAxis a = new LogAxis();
if (this.GetType() != a.GetType())
{
throw new NPlotException("Clone not defined in derived type. Help!");
}
this.DoClone( this, a );
return a;
}
/// <summary>
/// Helper method for Clone (actual implementation)
/// </summary>
/// <param name="a">The original object to clone.</param>
/// <param name="b">The cloned object.</param>
protected void DoClone(LogAxis b, LogAxis a)
{
Axis.DoClone(b,a);
// add specific elemtents of the class for the deep copy of the object
a.numberSmallTicks_ = b.numberSmallTicks_;
a.largeTickValue_ = b.largeTickValue_;
a.largeTickStep_ = b.largeTickStep_;
}
/// <summary>
/// Default constructor.
/// </summary>
public LogAxis()
: base()
{
Init();
}
/// <summary>
/// Copy Constructor
/// </summary>
/// <param name="a">The Axis to clone.</param>
public LogAxis(Axis a)
: base(a)
{
Init();
}
/// <summary>
/// Constructor
/// </summary>
/// <param name="worldMin">Minimum World value for the axis.</param>
/// <param name="worldMax">Maximum World value for the axis.</param>
public LogAxis(double worldMin, double worldMax)
: base( worldMin, worldMax )
{
Init();
}
private void Init()
{
this.NumberFormat = "{0:g5}";
}
/// <summary>
/// Draw the ticks.
/// </summary>
/// <param name="g">The drawing surface on which to draw.</param>
/// <param name="physicalMin">The minimum physical extent of the axis.</param>
/// <param name="physicalMax">The maximum physical extent of the axis.</param>
/// <param name="boundingBox">out: smallest box that completely encompasses all of the ticks and tick labels.</param>
/// <param name="labelOffset">out: a suitable offset from the axis to draw the axis label.</param>
/// <returns> An ArrayList containing the offset from the axis required for an axis label
/// to miss this tick, followed by a bounding rectangle for the tick and tickLabel drawn.</returns>
protected override void DrawTicks(
Graphics g,
Point physicalMin,
Point physicalMax,
out object labelOffset,
out object boundingBox )
{
Point tLabelOffset;
Rectangle tBoundingBox;
labelOffset = this.getDefaultLabelOffset( physicalMin, physicalMax );
boundingBox = null;
ArrayList largeTickPositions;
ArrayList smallTickPositions;
this.WorldTickPositions( physicalMin, physicalMax, out largeTickPositions, out smallTickPositions );
Point offset = new Point( 0, 0 );
object bb = null;
// Missed this protection
if (largeTickPositions.Count > 0)
{
for (int i=0; i<largeTickPositions.Count; ++i)
{
StringBuilder label = new StringBuilder();
// do google search for "format specifier writeline" for help on this.
label.AppendFormat(this.NumberFormat, (double)largeTickPositions[i]);
this.DrawTick( g, (double)largeTickPositions[i], this.LargeTickSize, label.ToString(),
new Point(0,0), physicalMin, physicalMax, out tLabelOffset, out tBoundingBox );
Axis.UpdateOffsetAndBounds( ref labelOffset, ref boundingBox, tLabelOffset, tBoundingBox );
}
}
else
{
// just get the axis bounding box)
PointF dir = Utils.UnitVector(physicalMin,physicalMax);
Rectangle rr = new Rectangle( physicalMin.X,
(int)((physicalMax.X-physicalMin.X)*dir.X),
physicalMin.Y,
(int)((physicalMax.Y-physicalMin.Y)*dir.Y) );
bb = rr;
}
// missed protection for zero ticks
if (smallTickPositions.Count > 0)
{
for (int i=0; i<smallTickPositions.Count; ++i)
{
this.DrawTick( g, (double)smallTickPositions[i], this.SmallTickSize,
"", new Point(0,0), physicalMin, physicalMax, out tLabelOffset, out tBoundingBox );
// ignore r for now - assume bb unchanged by small tick bounds.
}
}
}
/// <summary>
/// Determines the positions, in world coordinates, of the small ticks
/// if they have not already been generated.
/// </summary>
/// <param name="physicalMin">The physical position corresponding to the world minimum of the axis.</param>
/// <param name="physicalMax">The physical position corresponding to the world maximum of the axis.</param>
/// <param name="largeTickPositions">The positions of the large ticks, unchanged</param>
/// <param name="smallTickPositions">If null, small tick positions are returned via this parameter. Otherwise this function does nothing.</param>
internal override void WorldTickPositions_SecondPass(
Point physicalMin,
Point physicalMax,
ArrayList largeTickPositions,
ref ArrayList smallTickPositions )
{
if (smallTickPositions != null)
{
throw new NPlotException( "not expecting smallTickPositions to be set already." );
}
smallTickPositions = new ArrayList();
// retrieve the spacing of the big ticks. Remember this is decades!
double bigTickSpacing = this.DetermineTickSpacing();
int nSmall = this.DetermineNumberSmallTicks( bigTickSpacing );
// now we have to set the ticks
// let us start with the easy case where the major tick distance
// is larger than a decade
if ( bigTickSpacing > 1.0f )
{
if (largeTickPositions.Count > 0)
{
// deal with the smallticks preceding the
// first big tick
double pos1 = (double)largeTickPositions[0];
while (pos1 > this.WorldMin)
{
pos1 = pos1 / 10.0f;
smallTickPositions.Add( pos1 );
}
// now go on for all other Major ticks
for (int i=0; i<largeTickPositions.Count; ++i )
{
double pos = (double)largeTickPositions[i];
for (int j=1; j<=nSmall; ++j )
{
pos=pos*10.0F;
// check to see if we are still in the range
if (pos < WorldMax)
{
smallTickPositions.Add( pos );
}
}
}
}
}
else
{
// guess what...
double [] m = { 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f, 8.0f, 9.0f };
// Then we deal with the other ticks
if (largeTickPositions.Count > 0)
{
// first deal with the smallticks preceding the first big tick
// positioning before the first tick
double pos1=(double)largeTickPositions[0]/10.0f;
for (int i=0; i<m.Length; i++)
{
double pos=pos1*m[i];
if (pos>this.WorldMin)
{
smallTickPositions.Add(pos);
}
}
// now go on for all other Major ticks
for (int i=0; i<largeTickPositions.Count; ++i )
{
pos1=(double)largeTickPositions[i];
for (int j=0; j<m.Length; ++j )
{
double pos=pos1*m[j];
// check to see if we are still in the range
if (pos < WorldMax)
{
smallTickPositions.Add( pos );
}
}
}
}
else
{
// probably a minor tick would anyway fall in the range
// find the decade preceding the minimum
double dec=Math.Floor(Math.Log10(WorldMin));
double pos1=Math.Pow(10.0,dec);
for (int i=0; i<m.Length; i++)
{
double pos=pos1*m[i];
if (pos>this.WorldMin && pos< this.WorldMax )
{
smallTickPositions.Add(pos);
}
}
}
}
}
private static double m_d5Log = -Math.Log10(0.5); // .30103
private static double m_d5RegionPos = Math.Abs(m_d5Log + ((1 - m_d5Log) / 2)); // ' .6505
private static double m_d5RegionNeg = Math.Abs(m_d5Log / 2); // '.1505
private void CalcGrids( double dLenAxis, int nNumDivisions, ref double dDivisionInterval)
{
double dMyInterval = dLenAxis / nNumDivisions;
double dPower = Math.Log10(dMyInterval);
dDivisionInterval = 10 ^ (int)dPower;
double dFixPower = dPower - (int)dPower;
double d5Region = Math.Abs(dPower - dFixPower);
double dMyMult;
if (dPower < 0)
{
d5Region = -(dPower - dFixPower);
dMyMult = 0.5;
}
else
{
d5Region = 1 - (dPower - dFixPower);
dMyMult = 5;
}
if ((d5Region >= m_d5RegionNeg) && (d5Region <= m_d5RegionPos))
{
dDivisionInterval = dDivisionInterval * dMyMult;
}
}
/// <summary>
/// Determines the positions, in world coordinates, of the log spaced large ticks.
/// </summary>
/// <param name="physicalMin">The physical position corresponding to the world minimum of the axis.</param>
/// <param name="physicalMax">The physical position corresponding to the world maximum of the axis.</param>
/// <param name="largeTickPositions">ArrayList containing the positions of the large ticks.</param>
/// <param name="smallTickPositions">null</param>
internal override void WorldTickPositions_FirstPass(
Point physicalMin,
Point physicalMax,
out ArrayList largeTickPositions,
out ArrayList smallTickPositions
)
{
smallTickPositions = null;
largeTickPositions = new ArrayList();
if ( double.IsNaN(WorldMin) || double.IsNaN(WorldMax) )
{
throw new NPlotException( "world extent of axis not set." );
}
double roundTickDist = this.DetermineTickSpacing( );
// now determine first tick position.
double first = 0.0f;
// if the user hasn't specified a large tick position.
if (double.IsNaN(largeTickValue_))
{
if( WorldMin > 0.0 )
{
double nToFirst = Math.Floor(Math.Log10(WorldMin) / roundTickDist)+1.0f;
first = nToFirst * roundTickDist;
}
// could miss one, if first is just below zero.
if (first-roundTickDist >= Math.Log10(WorldMin))
{
first -= roundTickDist;
}
}
// the user has specified one place they would like a large tick placed.
else
{
first = Math.Log10( this.LargeTickValue );
// TODO: check here not too much different.
// could result in long loop.
while (first < Math.Log10(WorldMin))
{
first += roundTickDist;
}
while (first > Math.Log10(WorldMin)+roundTickDist)
{
first -= roundTickDist;
}
}
double mark = first;
while (mark <= Math.Log10(WorldMax))
{
// up to here only logs are dealt with, but I want to return
// a real value in the arraylist
double val;
val = Math.Pow( 10.0, mark );
largeTickPositions.Add( val );
mark += roundTickDist;
}
}
/// <summary>
/// Determines the tick spacing.
/// </summary>
/// <returns>The tick spacing (in decades!)</returns>
private double DetermineTickSpacing( )
{
if ( double.IsNaN(WorldMin) || double.IsNaN(WorldMax) )
{
throw new NPlotException( "world extent of axis is not set." );
}
// if largeTickStep has been set, it is used
if ( !double.IsNaN( this.largeTickStep_) )
{
if ( this.largeTickStep_ <= 0.0f )
{
throw new NPlotException( "can't have negative tick step - reverse WorldMin WorldMax instead." );
}
return this.largeTickStep_;
}
double MagRange = (double)(Math.Floor(Math.Log10(WorldMax)) - Math.Floor(Math.Log10(WorldMin))+1.0);
if ( MagRange > 0.0 )
{
// for now, a simple logic
// start with a major tick every order of magnitude, and
// increment if in order not to have more than 10 ticks in
// the plot.
double roundTickDist=1.0F;
int nticks=(int)(MagRange/roundTickDist);
while (nticks > 10)
{
roundTickDist++;
nticks=(int)(MagRange/roundTickDist);
}
return roundTickDist;
}
else
{
return 0.0f;
}
}
/// <summary>
/// Determines the number of small ticks between two large ticks.
/// </summary>
/// <param name="bigTickDist">The distance between two large ticks.</param>
/// <returns>The number of small ticks.</returns>
private int DetermineNumberSmallTicks( double bigTickDist )
{
// if the big ticks is more than one decade, the
// small ticks are every decade, I don't let the user set it.
if (this.numberSmallTicks_ != null && bigTickDist == 1.0f)
{
return (int)this.numberSmallTicks_+1;
}
// if we are plotting every decade, we have to
// put the log ticks. As a start, I put every
// small tick (.2,.3,.4,.5,.6,.7,.8,.9)
if (bigTickDist == 1.0f)
{
return 8;
}
// easy, put a tick every missed decade
else if (bigTickDist > 1.0f)
{
return (int)bigTickDist - 1;
}
else
{
throw new NPlotException("Wrong Major tick distance setting");
}
}
/// <summary>
/// The step between large ticks, expressed in decades for the Log scale.
/// </summary>
public double LargeTickStep
{
set
{
largeTickStep_ = value;
}
get
{
return largeTickStep_;
}
}
/// <summary>
/// Position of one of the large ticks [other positions will be calculated relative to this one].
/// </summary>
public double LargeTickValue
{
set
{
largeTickValue_ = value;
}
get
{
return largeTickValue_;
}
}
/// <summary>
/// The number of small ticks between large ticks.
/// </summary>
public int NumberSmallTicks
{
set
{
numberSmallTicks_ = value;
}
}
// Private members
private object numberSmallTicks_;
private double largeTickValue_ = double.NaN;
private double largeTickStep_ = double.NaN;
/// <summary>
/// World to physical coordinate transform.
/// </summary>
/// <param name="coord">The coordinate value to transform.</param>
/// <param name="physicalMin">The physical position corresponding to the world minimum of the axis.</param>
/// <param name="physicalMax">The physical position corresponding to the world maximum of the axis.</param>
/// <param name="clip">if false, then physical value may extend outside worldMin / worldMax. If true, the physical value returned will be clipped to physicalMin or physicalMax if it lies outside this range.</param>
/// <returns>The transformed coordinates.</returns>
/// <remarks>TODO: make Reversed property work for this.</remarks>
public override PointF WorldToPhysical(
double coord,
PointF physicalMin,
PointF physicalMax,
bool clip )
{
// if want clipped value, return extrema if outside range.
if (clip)
{
if (coord > WorldMax)
{
return physicalMax;
}
if (coord < WorldMin)
{
return physicalMin;
}
}
if (coord < 0.0f)
{
throw new NPlotException( "Cannot have negative values for data using Log Axis" );
}
// inside range or don't want to clip.
double lrange = (double)(Math.Log10(WorldMax) - Math.Log10(WorldMin));
double prop = (double)((Math.Log10(coord) - Math.Log10(WorldMin)) / lrange);
PointF offset = new PointF( (float)(prop * (physicalMax.X - physicalMin.X)),
(float)(prop * (physicalMax.Y - physicalMin.Y)) );
return new PointF( physicalMin.X + offset.X, physicalMin.Y + offset.Y );
}
/// <summary>
/// Return the world coordinate of the projection of the point p onto
/// the axis.
/// </summary>
/// <param name="p">The point to project onto the axis</param>
/// <param name="physicalMin">The physical position corresponding to the world minimum of the axis.</param>
/// <param name="physicalMax">The physical position corresponding to the world maximum of the axis.</param>
/// <param name="clip">If true, the world value will be clipped to WorldMin or WorldMax as appropriate if it lies outside this range.</param>
/// <returns>The world value corresponding to the projection of the point p onto the axis.</returns>
public override double PhysicalToWorld( PointF p, PointF physicalMin, PointF physicalMax, bool clip )
{
// use the base method to do the projection on the axis.
double t = base.PhysicalToWorld( p, physicalMin, physicalMax, clip );
// now reconstruct phys dist prop along this assuming linear scale as base method did.
double v = (t - this.WorldMin) / (this.WorldMax - this.WorldMin);
double ret = WorldMin*Math.Pow( WorldMax / WorldMin, v );
// if want clipped value, return extrema if outside range.
if (clip)
{
ret = Math.Max( ret, WorldMin );
ret = Math.Min( ret, WorldMax );
}
return ret;
}
/// <summary>
/// The minimum world extent of the axis. Must be greater than zero.
/// </summary>
public override double WorldMin
{
get
{
return (double)base.WorldMin;
}
set
{
if (value > 0.0f)
{
base.WorldMin = value;
}
else
{
throw new NPlotException("Cannot have negative values in Log Axis");
}
}
}
/// <summary>
/// The maximum world extent of the axis. Must be greater than zero.
/// </summary>
public override double WorldMax
{
get
{
return (double)base.WorldMax;
}
set
{
if (value > 0.0F)
{
base.WorldMax = value;
}
else
{
throw new NPlotException("Cannot have negative values in Log Axis");
}
}
}
/// <summary>
/// Get whether or not this axis is linear. It is not.
/// </summary>
public override bool IsLinear
{
get
{
return false;
}
}
}
}

1278
lib/MainForm.cs Normal file

Разница между файлами не показана из-за своего большого размера Загрузить разницу

99
lib/Makefile Normal file
Просмотреть файл

@ -0,0 +1,99 @@
CSC=mcs -debug+
VERSION=0.9.9.2
NPLOT_SOURCES = \
AdapterUtils.cs \
NPlotException.cs \
ArrowItem.cs \
AssemblyInfo.cs \
AxesConstraint.cs \
Axis.cs \
BasePlot.cs \
BaseSequenceLinePlot.cs \
BaseSequencePlot.cs \
Bitmap.PlotSurface2D.cs \
CandlePlot.cs \
DateTimeAxis.cs \
ErrorHandler.cs \
FilledRegion.cs \
FontScaler.cs \
Grid.cs \
HistogramPlot.cs \
HorizontalLine.cs \
IDrawable.cs \
IGradient.cs \
ImagePlot.cs \
IMeshPlot.cs \
IPlot.cs \
IPlotSurface2D.cs \
ITransform2D.cs \
ISequencePlot.cs \
LabelAxis.cs \
LabelPointPlot.cs \
LegendBase.cs \
Legend.cs \
LinearAxis.cs \
LinearGradient.cs \
LinePlot.cs \
LogAxis.cs \
Marker.cs \
MarkerItem.cs \
PageAlignedPhysicalAxis.cs \
PhysicalAxis.cs \
PiAxis.cs \
PiePlot.cs \
PlotSurface2D.cs \
PlotSurface3D.cs \
PointD.cs \
PointPlot.cs \
RectangleBrushes.cs \
RectangleD.cs \
SequenceAdapter.cs \
StartStep.cs \
StepPlot.cs \
Transform2D.cs \
Utils.cs \
VerticalLine.cs \
Web.Design.PlotSurface2D.cs \
Web.PlotSurface2D.cs
NPLOT_GTK_SOURCES = \
Gtk.PlotSurface2D.cs \
sysdraw.cs
all: NPlot.dll NPlot.Gtk.dll tests
tests: mf.exe test.exe
NPLOT_DLLS= -r:System.Web \
-r:System.Design \
-r:System.Drawing \
-r:System.Data
NPLOT_GTK_DLLS= -r:System.Web \
-r:System.Design \
-r:System.Drawing \
-r:System.Data \
-pkg:gtk-sharp-2.0 \
-r:NPlot.dll
NPlot.dll: $(NPLOT_SOURCES) Makefile
$(CSC) $(NPLOT_SOURCES) -target:library -out:NPlot.dll $(NPLOT_DLLS)
NPlot.Gtk.dll: $(NPLOT_SOURCES) $(NPLOT_GTK_SOURCES) NPlot.dll Makefile
$(CSC) $(NPLOT_GTK_SOURCES) -target:library -out:NPlot.Gtk.dll $(NPLOT_GTK_DLLS)
mf.exe: MainForm.cs NPlot.Gtk.dll
$(CSC) MainForm.cs -out:mf.exe -r:NPlot.dll -r:NPlot.Gtk.dll -pkg:gtk-sharp-2.0 -r:System.Drawing -r:System.Data -resource:asx_jbh.xml,NPlotDemo.resources.asx_jbh.xml
test.exe: NPlot.dll test.cs
$(CSC) test.cs -r:NPlot.dll -r:NPlot.Gtk.dll -pkg:gtk-sharp-2.0 -r:System.Drawing
install: NPlot.dll NPlot.Gtk.dll
-mkdir -p $(prefix)/lib/nplot
cp NPlot.dll NPlot.Gtk.dll $(prefix)/lib/mono/1.0/
sed -e "s,@prefix@,$(prefix),g" -e "s/@VERSION@/$(VERSION)/" < nplot.pc.in > $(prefix)/lib/pkgconfig/nplot.pc
sed -e "s,@prefix@,$(prefix),g" -e "s/@VERSION@/$(VERSION)/" < nplot-gtk.pc.in > $(prefix)/lib/pkgconfig/nplot-gtk.pc
clean:
rm *exe *dll *mdb

487
lib/Marker.cs Normal file
Просмотреть файл

@ -0,0 +1,487 @@
/*
NPlot - A charting library for .NET
Marker.cs
Copyright (C) 2003
Paolo Pierini, Matt Howlett
Redistribution and use of NPlot or parts there-of in source and
binary forms, with or without modification, are permitted provided
that the following conditions are met:
1. Re-distributions in source form must retain at the head of each
source file the above copyright notice, this list of conditions
and the following disclaimer.
2. Any product ("the product") that makes use NPlot or parts
there-of must either:
(a) allow any user of the product to obtain a complete machine-
readable copy of the corresponding source code for the
product and the version of NPlot used for a charge no more
than your cost of physically performing source distribution,
on a medium customarily used for software interchange, or:
(b) reproduce the following text in the documentation, about
box or other materials intended to be read by human users
of the product that is provided to every human user of the
product:
"This product includes software developed as
part of the NPlot library project available
from: http://www.nplot.com/"
The words "This product" may optionally be replace with
the actual name of the product.
------------------------------------------------------------------------
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
using System;
using System.Drawing;
using System.Drawing.Drawing2D;
namespace NPlot
{
/// <summary>
/// Encapsulates functionality relating to markers used by the PointPlot class.
/// </summary>
public class Marker
{
/// <summary>
/// Enumeration of all different types of marker.
/// </summary>
public enum MarkerType
{
/// <summary>
/// A simple cross marker (x).
/// </summary>
Cross1,
/// <summary>
/// Another simple cross marker (+).
/// </summary>
Cross2,
/// <summary>
/// A circle marker.
/// </summary>
Circle,
/// <summary>
/// A square marker.
/// </summary>
Square,
/// <summary>
/// A triangle marker (upwards).
/// </summary>
Triangle,
/// <summary>
/// A triangle marker (upwards).
/// </summary>
TriangleUp,
/// <summary>
/// A triangle marker (upwards).
/// </summary>
TriangleDown,
/// <summary>
/// A diamond,
/// </summary>
Diamond,
/// <summary>
/// A filled circle
/// </summary>
FilledCircle,
/// <summary>
/// A filled square
/// </summary>
FilledSquare,
/// <summary>
/// A filled triangle
/// </summary>
FilledTriangle,
/// <summary>
/// A small flag (up)
/// </summary>
Flag,
/// <summary>
/// A small flag (up)
/// </summary>
FlagUp,
/// <summary>
/// A small flag (down)
/// </summary>
FlagDown,
/// <summary>
/// No marker
/// </summary>
None
}
private MarkerType markerType_;
private int size_;
private int h_;
private System.Drawing.Pen pen_ = new Pen( Color.Black );
private System.Drawing.Brush brush_ = new SolidBrush( Color.Black );
private bool filled_ = false;
private bool dropLine_ = false;
/// <summary>
/// The type of marker.
/// </summary>
public MarkerType Type
{
get
{
return markerType_;
}
set
{
markerType_ = value;
}
}
/// <summary>
/// Whether or not to draw a dropline.
/// </summary>
public bool DropLine
{
get
{
return dropLine_;
}
set
{
dropLine_ = value;
}
}
/// <summary>
/// The marker size.
/// </summary>
public int Size
{
get
{
return size_;
}
set
{
size_ = value;
h_ = size_/2;
}
}
/// <summary>
/// The brush used to fill the marker.
/// </summary>
public Brush FillBrush
{
get
{
return brush_;
}
set
{
brush_ = value;
}
}
/// <summary>
/// Fill with color.
/// </summary>
public bool Filled
{
get
{
return filled_;
}
set
{
filled_ = value;
}
}
/// <summary>
/// Sets the pen color and fill brush to be solid with the specified color.
/// </summary>
public System.Drawing.Color Color
{
set
{
pen_.Color = value;
brush_ = new SolidBrush( value );
}
get
{
return pen_.Color;
}
}
/// <summary>
/// The Pen used to draw the marker.
/// </summary>
public System.Drawing.Pen Pen
{
set
{
pen_ = value;
}
get
{
return pen_;
}
}
/// <summary>
/// Default constructor.
/// </summary>
public Marker()
{
markerType_ = MarkerType.Square;
Size = 4;
filled_ = false;
}
/// <summary>
/// Constructor
/// </summary>
/// <param name="markertype">The marker type.</param>
public Marker( MarkerType markertype )
{
markerType_ = markertype;
Size = 4;
filled_ = false;
}
/// <summary>
/// Constructor
/// </summary>
/// <param name="markertype">The marker type.</param>
/// <param name="size">The marker size.</param>
public Marker( MarkerType markertype, int size )
{
markerType_ = markertype;
Size = size;
filled_ = false;
}
/// <summary>
/// Constructor
/// </summary>
/// <param name="markertype">The marker type.</param>
/// <param name="size">The marker size.</param>
/// <param name="color">The marker color.</param>
public Marker( MarkerType markertype, int size, Color color )
{
markerType_ = markertype;
Size = size;
Color = color;
filled_ = false;
}
/// <summary>
/// Constructor
/// </summary>
/// <param name="markertype">The marker type.</param>
/// <param name="size">The marker size.</param>
/// <param name="pen">The marker Pen.</param>
public Marker( MarkerType markertype, int size, Pen pen )
{
markerType_ = markertype;
Size = size;
Pen = pen;
filled_ = false;
}
/// <summary>
/// Constructor
/// </summary>
/// <param name="markertype">The marker type.</param>
/// <param name="size">The marker size.</param>
/// <param name="pen">The marker Pen.</param>
/// <param name="fill">The fill flag.</param>
public Marker( MarkerType markertype, int size, Pen pen, bool fill )
{
markerType_ = markertype;
Size = size;
Pen = pen;
filled_ = fill;
}
/// <summary>
/// Draws the marker at the given position
/// </summary>
/// <param name="g">The graphics surface on which to draw.</param>
/// <param name="x">The [physical] x position to draw the marker.</param>
/// <param name="y">The [physical] y position to draw the marker.</param>
public void Draw( Graphics g, int x, int y )
{
switch (markerType_)
{
case MarkerType.Cross1:
g.DrawLine( pen_, x-h_, y+h_, x+h_, y-h_ );
g.DrawLine( pen_, x+h_, y+h_, x-h_, y-h_ );
break;
case MarkerType.Cross2:
g.DrawLine( pen_, x, y-h_, x, y+h_ );
g.DrawLine( pen_, x-h_, y, x+h_, y );
break;
case MarkerType.Circle:
g.DrawEllipse( pen_, x-h_, y-h_, size_, size_ );
if ( this.filled_ )
{
g.FillEllipse( brush_, x-h_, y-h_, size_, size_ );
}
break;
case MarkerType.Square:
g.DrawRectangle( pen_, x-h_, y-h_, size_, size_ );
if ( this.filled_ )
{
g.FillRectangle( brush_, x-h_, y-h_, size_, size_ );
}
break;
case MarkerType.Triangle:
case MarkerType.TriangleDown:
{
Point p1 = new Point( x-h_, y-h_ );
Point p2 = new Point( x, y+h_ );
Point p3 = new Point( x+h_, y-h_ );
Point [] pts = new Point [3] { p1, p2, p3 };
GraphicsPath gp = new GraphicsPath();
gp.AddPolygon( pts );
g.DrawPath( pen_, gp );
if (this.filled_)
{
g.FillPath( brush_, gp );
}
break;
}
case MarkerType.TriangleUp:
{
Point p1 = new Point( x-h_, y+h_ );
Point p2 = new Point( x, y-h_ );
Point p3 = new Point( x+h_, y+h_ );
Point [] pts = new Point [3] { p1, p2, p3 };
GraphicsPath gp = new GraphicsPath();
gp.AddPolygon( pts );
g.DrawPath( pen_, gp );
if (this.filled_)
{
g.FillPath( brush_, gp );
}
break;
}
case MarkerType.FilledCircle:
g.DrawEllipse( pen_, x-h_, y-h_, size_, size_ );
g.FillEllipse( brush_, x-h_, y-h_, size_, size_ );
break;
case MarkerType.FilledSquare:
g.DrawRectangle( pen_, x-h_, y-h_, size_, size_ );
g.FillRectangle( brush_, x-h_, y-h_, size_, size_ );
break;
case MarkerType.FilledTriangle:
{
Point p1 = new Point( x-h_, y-h_ );
Point p2 = new Point( x, y+h_ );
Point p3 = new Point( x+h_, y-h_ );
Point [] pts = new Point [3] { p1, p2, p3 };
GraphicsPath gp = new GraphicsPath();
gp.AddPolygon( pts );
g.DrawPath( pen_, gp );
g.FillPath( brush_, gp );
break;
}
case MarkerType.Diamond:
{
Point p1 = new Point( x-h_, y );
Point p2 = new Point( x, y-h_ );
Point p3 = new Point( x+h_, y );
Point p4 = new Point( x, y+h_ );
Point [] pts = new Point [4] { p1, p2, p3, p4 };
GraphicsPath gp = new GraphicsPath();
gp.AddPolygon( pts );
g.DrawPath( pen_, gp );
if (this.filled_)
{
g.FillPath( brush_, gp );
}
break;
}
case MarkerType.Flag:
case MarkerType.FlagUp:
{
Point p1 = new Point( x, y );
Point p2 = new Point( x, y-size_ );
Point p3 = new Point( x+size_, y-size_+size_/3 );
Point p4 = new Point( x, y-size_+2*size_/3 );
g.DrawLine( pen_, p1, p2 );
Point [] pts = new Point [3] { p2, p3, p4 };
GraphicsPath gp = new GraphicsPath();
gp.AddPolygon( pts );
g.DrawPath( pen_, gp );
if (this.filled_)
{
g.FillPath( brush_, gp );
}
break;
}
case MarkerType.FlagDown:
{
Point p1 = new Point( x, y );
Point p2 = new Point( x, y+size_ );
Point p3 = new Point( x+size_, y+size_-size_/3 );
Point p4 = new Point( x, y+size_-2*size_/3 );
g.DrawLine( pen_, p1, p2 );
Point [] pts = new Point [3] { p2, p3, p4 };
GraphicsPath gp = new GraphicsPath();
gp.AddPolygon( pts );
g.DrawPath( pen_, gp );
if (this.filled_)
{
g.FillPath( brush_, gp );
}
break;
}
case MarkerType.None:
break;
}
}
}
}

136
lib/MarkerItem.cs Normal file
Просмотреть файл

@ -0,0 +1,136 @@
/*
NPlot - A charting library for .NET
MarkerItem.cs
Copyright (C) 2003
Matt Howlett
Redistribution and use of NPlot or parts there-of in source and
binary forms, with or without modification, are permitted provided
that the following conditions are met:
1. Re-distributions in source form must retain at the head of each
source file the above copyright notice, this list of conditions
and the following disclaimer.
2. Any product ("the product") that makes use NPlot or parts
there-of must either:
(a) allow any user of the product to obtain a complete machine-
readable copy of the corresponding source code for the
product and the version of NPlot used for a charge no more
than your cost of physically performing source distribution,
on a medium customarily used for software interchange, or:
(b) reproduce the following text in the documentation, about
box or other materials intended to be read by human users
of the product that is provided to every human user of the
product:
"This product includes software developed as
part of the NPlot library project available
from: http://www.nplot.com/"
The words "This product" may optionally be replace with
the actual name of the product.
------------------------------------------------------------------------
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
using System;
using System.Drawing;
namespace NPlot
{
/// <summary>
/// Class for placement of a single marker.
/// </summary>
public class MarkerItem : IDrawable
{
private Marker marker_;
private double x_;
private double y_;
/// <summary>
/// Constructs a square marker at the (world) point point.
/// </summary>
/// <param name="point">the world position at which to place the marker</param>
public MarkerItem( PointD point )
{
marker_ = new Marker( Marker.MarkerType.Square );
x_ = point.X;
y_ = point.Y;
}
/// <summary>
/// Default constructor - a square black marker.
/// </summary>
/// <param name="x">The world x position of the marker</param>
/// <param name="y">The world y position of the marker</param>
public MarkerItem( double x, double y )
{
marker_ = new Marker( Marker.MarkerType.Square );
x_ = x;
y_ = y;
}
/// <summary>
/// Constructor
/// </summary>
/// <param name="marker">The marker to place on the chart.</param>
/// <param name="x">The world x position of the marker</param>
/// <param name="y">The world y position of the marker</param>
public MarkerItem( Marker marker, double x, double y )
{
marker_ = marker;
x_ = x;
y_ = y;
}
/// <summary>
/// Constructor
/// </summary>
/// <param name="marker">The marker to place on the chart.</param>
/// <param name="point">The world position of the marker</param>
public MarkerItem( Marker marker, PointD point )
{
marker_ = marker;
x_ = point.X;
y_ = point.Y;
}
/// <summary>
/// Draws the marker on a plot surface.
/// </summary>
/// <param name="g">graphics surface on which to draw</param>
/// <param name="xAxis">The X-Axis to draw against.</param>
/// <param name="yAxis">The Y-Axis to draw against.</param>
public void Draw( System.Drawing.Graphics g, PhysicalAxis xAxis, PhysicalAxis yAxis )
{
PointF point = new PointF(
xAxis.WorldToPhysical( x_, true ).X,
yAxis.WorldToPhysical( y_, true ).Y );
marker_.Draw( g, (int)point.X, (int)point.Y );
}
}
}

Двоичные данные
lib/NPlot.Gtk.dll Executable file

Двоичный файл не отображается.

6
lib/NPlot.Gtk.dll.config Normal file
Просмотреть файл

@ -0,0 +1,6 @@
<configuration>
<dllmap dll="libglib-2.0-0.dll" target="libglib-2.0.so.0"/>
<dllmap dll="libgobject-2.0-0.dll" target="libgobject-2.0.so.0"/>
<dllmap dll="libgdk-win32-2.0-0.dll" target="libgdk-x11-2.0.so.0"/>
<dllmap dll="libgdk_pixbuf-2.0-0.dll" target="libgdk_pixbuf-2.0.so.0"/>
</configuration>

Двоичные данные
lib/NPlot.Gtk.dll.mdb Normal file

Двоичный файл не отображается.

393
lib/NPlot.csproj Normal file
Просмотреть файл

@ -0,0 +1,393 @@
<VisualStudioProject>
<CSHARP
ProjectType = "Local"
ProductVersion = "7.10.3077"
SchemaVersion = "2.0"
ProjectGuid = "{E6867FF5-74EC-4464-8958-D71CB46232F3}"
>
<Build>
<Settings
ApplicationIcon = ""
AssemblyKeyContainerName = ""
AssemblyName = "NPlot"
AssemblyOriginatorKeyFile = ""
DefaultClientScript = "JScript"
DefaultHTMLPageLayout = "Grid"
DefaultTargetSchema = "IE50"
DelaySign = "false"
OutputType = "Library"
PreBuildEvent = ""
PostBuildEvent = ""
RootNamespace = "NPlot"
RunPostBuildEvent = "OnBuildSuccess"
StartupObject = ""
>
<Config
Name = "Debug"
AllowUnsafeBlocks = "false"
BaseAddress = "285212672"
CheckForOverflowUnderflow = "false"
ConfigurationOverrideFile = ""
DefineConstants = "DEBUG;TRACE;CHECK_ERRORS"
DocumentationFile = "NPlot.xml"
DebugSymbols = "true"
FileAlignment = "4096"
IncrementalBuild = "false"
NoStdLib = "false"
NoWarn = ""
Optimize = "false"
OutputPath = "bin\Debug\"
RegisterForComInterop = "false"
RemoveIntegerChecks = "false"
TreatWarningsAsErrors = "false"
WarningLevel = "4"
/>
<Config
Name = "Release"
AllowUnsafeBlocks = "false"
BaseAddress = "285212672"
CheckForOverflowUnderflow = "false"
ConfigurationOverrideFile = ""
DefineConstants = "TRACE"
DocumentationFile = "NPlot.xml"
DebugSymbols = "false"
FileAlignment = "4096"
IncrementalBuild = "false"
NoStdLib = "false"
NoWarn = ""
Optimize = "true"
OutputPath = "bin\Release\"
RegisterForComInterop = "false"
RemoveIntegerChecks = "false"
TreatWarningsAsErrors = "false"
WarningLevel = "4"
/>
</Settings>
<References>
<Reference
Name = "System"
AssemblyName = "System"
HintPath = "C:\WINDOWS\Microsoft.NET\Framework\v1.0.3705\System.dll"
/>
<Reference
Name = "System.Data"
AssemblyName = "System.Data"
HintPath = "C:\WINDOWS\Microsoft.NET\Framework\v1.0.3705\System.Data.dll"
/>
<Reference
Name = "System.XML"
AssemblyName = "System.Xml"
HintPath = "C:\WINDOWS\Microsoft.NET\Framework\v1.0.3705\System.XML.dll"
/>
<Reference
Name = "System.Drawing"
AssemblyName = "System.Drawing"
HintPath = "C:\WINDOWS\Microsoft.NET\Framework\v1.0.3705\System.Drawing.dll"
/>
<Reference
Name = "System.Windows.Forms"
AssemblyName = "System.Windows.Forms"
HintPath = "C:\WINDOWS\Microsoft.NET\Framework\v1.0.3705\System.Windows.Forms.dll"
/>
<Reference
Name = "System.Web"
AssemblyName = "System.Web"
HintPath = "..\..\..\..\..\..\WINDOWS\Microsoft.NET\Framework\v1.0.3705\System.Web.dll"
/>
<Reference
Name = "System.Design"
AssemblyName = "System.Design"
HintPath = "..\..\..\..\..\..\..\WINDOWS\Microsoft.NET\Framework\v1.0.3705\System.Design.dll"
/>
</References>
</Build>
<Files>
<Include>
<File
RelPath = "AdapterUtils.cs"
SubType = "Code"
BuildAction = "Compile"
/>
<File
RelPath = "ArrowItem.cs"
SubType = "Code"
BuildAction = "Compile"
/>
<File
RelPath = "AssemblyInfo.cs"
SubType = "Code"
BuildAction = "Compile"
/>
<File
RelPath = "AxesConstraint.cs"
SubType = "Code"
BuildAction = "Compile"
/>
<File
RelPath = "Axis.cs"
SubType = "Code"
BuildAction = "Compile"
/>
<File
RelPath = "BarPlot.cs"
SubType = "Code"
BuildAction = "Compile"
/>
<File
RelPath = "BasePlot.cs"
SubType = "Code"
BuildAction = "Compile"
/>
<File
RelPath = "BaseSequencePlot.cs"
SubType = "Code"
BuildAction = "Compile"
/>
<File
RelPath = "Bitmap.PlotSurface2D.cs"
SubType = "Code"
BuildAction = "Compile"
/>
<File
RelPath = "CandlePlot.cs"
SubType = "Code"
BuildAction = "Compile"
/>
<File
RelPath = "changelog.txt"
BuildAction = "Content"
/>
<File
RelPath = "DateTimeAxis.cs"
SubType = "Code"
BuildAction = "Compile"
/>
<File
RelPath = "FilledRegion.cs"
SubType = "Code"
BuildAction = "Compile"
/>
<File
RelPath = "Grid.cs"
SubType = "Code"
BuildAction = "Compile"
/>
<File
RelPath = "HistogramPlot.cs"
SubType = "Code"
BuildAction = "Compile"
/>
<File
RelPath = "HorizontalLine.cs"
SubType = "Code"
BuildAction = "Compile"
/>
<File
RelPath = "icon.ico"
BuildAction = "EmbeddedResource"
/>
<File
RelPath = "IDrawable.cs"
SubType = "Code"
BuildAction = "Compile"
/>
<File
RelPath = "IGradient.cs"
SubType = "Code"
BuildAction = "Compile"
/>
<File
RelPath = "ImagePlot.cs"
SubType = "Code"
BuildAction = "Compile"
/>
<File
RelPath = "IPlot.cs"
SubType = "Code"
BuildAction = "Compile"
/>
<File
RelPath = "IPlotSurface2D.cs"
SubType = "Code"
BuildAction = "Compile"
/>
<File
RelPath = "ISequencePlot.cs"
SubType = "Code"
BuildAction = "Compile"
/>
<File
RelPath = "ISurface.cs"
SubType = "Code"
BuildAction = "Compile"
/>
<File
RelPath = "ITransform2D.cs"
SubType = "Code"
BuildAction = "Compile"
/>
<File
RelPath = "LabelAxis.cs"
SubType = "Code"
BuildAction = "Compile"
/>
<File
RelPath = "LabelPointPlot.cs"
SubType = "Code"
BuildAction = "Compile"
/>
<File
RelPath = "Legend.cs"
SubType = "Code"
BuildAction = "Compile"
/>
<File
RelPath = "LegendBase.cs"
SubType = "Code"
BuildAction = "Compile"
/>
<File
RelPath = "LinearAxis.cs"
SubType = "Code"
BuildAction = "Compile"
/>
<File
RelPath = "LinearGradient.cs"
SubType = "Code"
BuildAction = "Compile"
/>
<File
RelPath = "LinePlot.cs"
SubType = "Code"
BuildAction = "Compile"
/>
<File
RelPath = "LogAxis.cs"
SubType = "Code"
BuildAction = "Compile"
/>
<File
RelPath = "Marker.cs"
SubType = "Code"
BuildAction = "Compile"
/>
<File
RelPath = "MarkerItem.cs"
SubType = "Code"
BuildAction = "Compile"
/>
<File
RelPath = "NPlotException.cs"
SubType = "Code"
BuildAction = "Compile"
/>
<File
RelPath = "PageAlignedPhysicalAxis.cs"
SubType = "Code"
BuildAction = "Compile"
/>
<File
RelPath = "PhysicalAxis.cs"
SubType = "Code"
BuildAction = "Compile"
/>
<File
RelPath = "PiAxis.cs"
SubType = "Code"
BuildAction = "Compile"
/>
<File
RelPath = "PlotSurface2D.cs"
SubType = "Code"
BuildAction = "Compile"
/>
<File
RelPath = "PointD.cs"
SubType = "Code"
BuildAction = "Compile"
/>
<File
RelPath = "PointPlot.cs"
SubType = "Code"
BuildAction = "Compile"
/>
<File
RelPath = "RectangleBrushes.cs"
SubType = "Code"
BuildAction = "Compile"
/>
<File
RelPath = "RectangleD.cs"
SubType = "Code"
BuildAction = "Compile"
/>
<File
RelPath = "SequenceAdapter.cs"
SubType = "Code"
BuildAction = "Compile"
/>
<File
RelPath = "StartStep.cs"
SubType = "Code"
BuildAction = "Compile"
/>
<File
RelPath = "StepGradient.cs"
SubType = "Code"
BuildAction = "Compile"
/>
<File
RelPath = "StepPlot.cs"
SubType = "Code"
BuildAction = "Compile"
/>
<File
RelPath = "TextItem.cs"
SubType = "Code"
BuildAction = "Compile"
/>
<File
RelPath = "TradingDateTimeAxis.cs"
SubType = "Code"
BuildAction = "Compile"
/>
<File
RelPath = "Transform2D.cs"
SubType = "Code"
BuildAction = "Compile"
/>
<File
RelPath = "Utils.cs"
SubType = "Code"
BuildAction = "Compile"
/>
<File
RelPath = "VerticalLine.cs"
SubType = "Code"
BuildAction = "Compile"
/>
<File
RelPath = "Web.Design.PlotSurface2D.cs"
SubType = "Code"
BuildAction = "Compile"
/>
<File
RelPath = "Web.PlotSurface2D.cs"
SubType = "Code"
BuildAction = "Compile"
/>
<File
RelPath = "Windows.PlotSurface2D.cs"
SubType = "Component"
BuildAction = "Compile"
/>
<File
RelPath = "Windows.PlotSurface2D.resx"
DependentUpon = "Windows.PlotSurface2D.cs"
BuildAction = "EmbeddedResource"
/>
</Include>
</Files>
</CSHARP>
</VisualStudioProject>

48
lib/NPlot.csproj.user Normal file
Просмотреть файл

@ -0,0 +1,48 @@
<VisualStudioProject>
<CSHARP LastOpenVersion = "7.10.3077" >
<Build>
<Settings ReferencePath = "" >
<Config
Name = "Debug"
EnableASPDebugging = "false"
EnableASPXDebugging = "false"
EnableUnmanagedDebugging = "false"
EnableSQLServerDebugging = "false"
RemoteDebugEnabled = "false"
RemoteDebugMachine = ""
StartAction = "Project"
StartArguments = ""
StartPage = ""
StartProgram = ""
StartURL = ""
StartWorkingDirectory = ""
StartWithIE = "false"
/>
<Config
Name = "Release"
EnableASPDebugging = "false"
EnableASPXDebugging = "false"
EnableUnmanagedDebugging = "false"
EnableSQLServerDebugging = "false"
RemoteDebugEnabled = "false"
RemoteDebugMachine = ""
StartAction = "Project"
StartArguments = ""
StartPage = ""
StartProgram = ""
StartURL = ""
StartWorkingDirectory = ""
StartWithIE = "false"
/>
</Settings>
</Build>
<OtherProjectSettings
CopyProjectDestinationFolder = ""
CopyProjectUncPath = ""
CopyProjectOption = "0"
ProjectView = "ProjectFiles"
ProjectTrust = "0"
/>
</CSHARP>
</VisualStudioProject>

Двоичные данные
lib/NPlot.dll Executable file

Двоичный файл не отображается.

Двоичные данные
lib/NPlot.dll.mdb Normal file

Двоичный файл не отображается.

297
lib/NPlot.ndoc Normal file
Просмотреть файл

@ -0,0 +1,297 @@
<project SchemaVersion="1.3">
<assemblies>
<assembly location="C:\cvshome\lib\bin\Debug\NPlot.dll" documentation="C:\cvshome\lib\NPlot.xml" />
</assemblies>
<namespaces>
<namespace name="NPlot"></namespace>
<namespace name="NPlot.Bitmap"></namespace>
<namespace name="NPlot.web"></namespace>
<namespace name="NPlot.web.Design"></namespace>
<namespace name="NPlot.Windows"></namespace>
</namespaces>
<documenters>
<documenter name="JavaDoc">
<property name="OutputDirectory" value=".\doc\" />
<property name="ShowMissingSummaries" value="False" />
<property name="ShowMissingRemarks" value="False" />
<property name="ShowMissingParams" value="False" />
<property name="ShowMissingReturns" value="False" />
<property name="ShowMissingValues" value="False" />
<property name="DocumentExplicitInterfaceImplementations" value="False" />
<property name="DocumentInternals" value="False" />
<property name="DocumentProtected" value="True" />
<property name="DocumentSealedProtected" value="False" />
<property name="DocumentPrivates" value="False" />
<property name="DocumentProtectedInternalAsProtected" value="False" />
<property name="DocumentEmptyNamespaces" value="False" />
<property name="SkipNamespacesWithoutSummaries" value="False" />
<property name="EditorBrowsableFilter" value="Off" />
<property name="IncludeAssemblyVersion" value="False" />
<property name="CopyrightText" value="" />
<property name="CopyrightHref" value="" />
<property name="ReferencesPath" value="" />
<property name="FeedbackEmailAddress" value="" />
<property name="UseNamespaceDocSummaries" value="False" />
<property name="AutoPropertyBackerSummaries" value="False" />
<property name="AutoDocumentConstructors" value="True" />
<property name="GetExternalSummaries" value="True" />
<property name="Preliminary" value="False" />
<property name="UseNDocXmlFile" value="" />
<property name="CleanIntermediates" value="False" />
<property name="DocumentAttributes" value="False" />
<property name="ShowTypeIdInAttributes" value="False" />
<property name="DocumentedAttributes" value="" />
<property name="InheritPlatformSupport" value="True" />
<property name="DefaultOSSupport" value="all" />
<property name="SupportCompactFrameworkByDefault" value="False" />
<property name="SupportMONOFrameworkByDefault" value="False" />
<property name="AdditionalFrameworkList" value="" />
<property name="AdditionalOSList" value="" />
</documenter>
<documenter name="LaTeX">
<property name="OutputDirectory" value=".\doc\" />
<property name="TextFileFullName" value="Documentation.tex" />
<property name="TexFileBaseName" value="Documentation" />
<property name="LatexCompiler" value="latex" />
<property name="TexFileFullPath" value=".\doc\Documentation.tex" />
<property name="ShowMissingSummaries" value="False" />
<property name="ShowMissingRemarks" value="False" />
<property name="ShowMissingParams" value="False" />
<property name="ShowMissingReturns" value="False" />
<property name="ShowMissingValues" value="False" />
<property name="DocumentExplicitInterfaceImplementations" value="False" />
<property name="DocumentInternals" value="False" />
<property name="DocumentProtected" value="True" />
<property name="DocumentSealedProtected" value="False" />
<property name="DocumentPrivates" value="False" />
<property name="DocumentProtectedInternalAsProtected" value="False" />
<property name="DocumentEmptyNamespaces" value="False" />
<property name="SkipNamespacesWithoutSummaries" value="False" />
<property name="EditorBrowsableFilter" value="Off" />
<property name="IncludeAssemblyVersion" value="False" />
<property name="CopyrightText" value="" />
<property name="CopyrightHref" value="" />
<property name="ReferencesPath" value="" />
<property name="FeedbackEmailAddress" value="" />
<property name="UseNamespaceDocSummaries" value="False" />
<property name="AutoPropertyBackerSummaries" value="False" />
<property name="AutoDocumentConstructors" value="True" />
<property name="GetExternalSummaries" value="True" />
<property name="Preliminary" value="False" />
<property name="UseNDocXmlFile" value="" />
<property name="CleanIntermediates" value="False" />
<property name="DocumentAttributes" value="False" />
<property name="ShowTypeIdInAttributes" value="False" />
<property name="DocumentedAttributes" value="" />
<property name="InheritPlatformSupport" value="True" />
<property name="DefaultOSSupport" value="all" />
<property name="SupportCompactFrameworkByDefault" value="False" />
<property name="SupportMONOFrameworkByDefault" value="False" />
<property name="AdditionalFrameworkList" value="" />
<property name="AdditionalOSList" value="" />
</documenter>
<documenter name="LinearHtml">
<property name="IncludeTypeMemberDetails" value="False" />
<property name="OutputDirectory" value=".\doc\" />
<property name="MethodParametersInTable" value="False" />
<property name="TypeIncludeRegexp" value="" />
<property name="NamespaceExcludeRegexp" value="" />
<property name="Title" value="An NDoc Documented Class Library" />
<property name="IncludeHierarchy" value="False" />
<property name="SortTOCByNamespace" value="True" />
<property name="HeaderHtml" value="" />
<property name="FooterHtml" value="" />
<property name="FilesToInclude" value="" />
<property name="ShowMissingSummaries" value="False" />
<property name="ShowMissingRemarks" value="False" />
<property name="ShowMissingParams" value="False" />
<property name="ShowMissingReturns" value="False" />
<property name="ShowMissingValues" value="False" />
<property name="DocumentExplicitInterfaceImplementations" value="False" />
<property name="DocumentInternals" value="False" />
<property name="DocumentProtected" value="True" />
<property name="DocumentSealedProtected" value="False" />
<property name="DocumentPrivates" value="False" />
<property name="DocumentProtectedInternalAsProtected" value="False" />
<property name="DocumentEmptyNamespaces" value="False" />
<property name="SkipNamespacesWithoutSummaries" value="False" />
<property name="EditorBrowsableFilter" value="Off" />
<property name="IncludeAssemblyVersion" value="False" />
<property name="CopyrightText" value="" />
<property name="CopyrightHref" value="" />
<property name="ReferencesPath" value="" />
<property name="FeedbackEmailAddress" value="" />
<property name="UseNamespaceDocSummaries" value="False" />
<property name="AutoPropertyBackerSummaries" value="False" />
<property name="AutoDocumentConstructors" value="True" />
<property name="GetExternalSummaries" value="True" />
<property name="Preliminary" value="False" />
<property name="UseNDocXmlFile" value="" />
<property name="CleanIntermediates" value="False" />
<property name="DocumentAttributes" value="False" />
<property name="ShowTypeIdInAttributes" value="False" />
<property name="DocumentedAttributes" value="" />
<property name="InheritPlatformSupport" value="True" />
<property name="DefaultOSSupport" value="all" />
<property name="SupportCompactFrameworkByDefault" value="False" />
<property name="SupportMONOFrameworkByDefault" value="False" />
<property name="AdditionalFrameworkList" value="" />
<property name="AdditionalOSList" value="" />
</documenter>
<documenter name="MSDN">
<property name="OutputDirectory" value="C:\cvshome\lib\doc\" />
<property name="HtmlHelpName" value="NPlot_Documentation" />
<property name="IncludeFavorites" value="False" />
<property name="Title" value="" />
<property name="DefaultTOC" value="" />
<property name="IncludeHierarchy" value="False" />
<property name="ShowVisualBasic" value="True" />
<property name="RootPageFileName" value="" />
<property name="RootPageContainsNamespaces" value="False" />
<property name="BinaryTOC" value="True" />
<property name="OutputTarget" value="HtmlHelpAndWeb" />
<property name="HeaderHtml" value="&lt;i&gt;Documentation for the &lt;a href=&quot;http://netcontrols.org/nplot/&quot; target=&quot;_top&quot;&gt;NPlot&lt;/a&gt; .NET charting library v0.9.7&lt;/i&gt;&#xD;&#xA;&lt;h2&gt;%TOPIC_TITLE%&lt;h2&gt;&#xD;&#xA;" />
<property name="FooterHtml" value="Copyright 2003, 2004 Matt Howlett and others.&lt;br&gt;&lt;br&gt;&#xD;&#xA;" />
<property name="FilesToInclude" value="" />
<property name="LinkToSdkDocVersion" value="SDK_v1_1" />
<property name="ExtensibilityStylesheet" value="" />
<property name="ShowMissingSummaries" value="False" />
<property name="ShowMissingRemarks" value="False" />
<property name="ShowMissingParams" value="False" />
<property name="ShowMissingReturns" value="False" />
<property name="ShowMissingValues" value="False" />
<property name="DocumentExplicitInterfaceImplementations" value="False" />
<property name="DocumentInternals" value="False" />
<property name="DocumentProtected" value="True" />
<property name="DocumentSealedProtected" value="False" />
<property name="DocumentPrivates" value="False" />
<property name="DocumentProtectedInternalAsProtected" value="False" />
<property name="DocumentEmptyNamespaces" value="False" />
<property name="SkipNamespacesWithoutSummaries" value="False" />
<property name="EditorBrowsableFilter" value="Off" />
<property name="IncludeAssemblyVersion" value="True" />
<property name="CopyrightText" value="" />
<property name="CopyrightHref" value="" />
<property name="ReferencesPath" value="" />
<property name="FeedbackEmailAddress" value="" />
<property name="UseNamespaceDocSummaries" value="False" />
<property name="AutoPropertyBackerSummaries" value="False" />
<property name="AutoDocumentConstructors" value="False" />
<property name="GetExternalSummaries" value="True" />
<property name="Preliminary" value="True" />
<property name="UseNDocXmlFile" value="" />
<property name="CleanIntermediates" value="True" />
<property name="DocumentAttributes" value="False" />
<property name="ShowTypeIdInAttributes" value="False" />
<property name="DocumentedAttributes" value="" />
<property name="InheritPlatformSupport" value="True" />
<property name="DefaultOSSupport" value="all" />
<property name="SupportCompactFrameworkByDefault" value="False" />
<property name="SupportMONOFrameworkByDefault" value="False" />
<property name="AdditionalFrameworkList" value="" />
<property name="AdditionalOSList" value="" />
</documenter>
<documenter name="VS.NET 2003">
<property name="OutputDirectory" value=".\doc\" />
<property name="HtmlHelpName" value="Documentation" />
<property name="Title" value="An NDoc documented library" />
<property name="IncludeHierarchy" value="False" />
<property name="RegisterTitleWithNamespace" value="False" />
<property name="CollectionNamespace" value="" />
<property name="RegisterTitleAsCollection" value="False" />
<property name="GenerateCollectionFiles" value="False" />
<property name="PlugInNamespace" value="ms.vscc" />
<property name="CollectionTOCStyle" value="Hierarchical" />
<property name="LinkToSdkDocVersion" value="SDK_v1_1" />
<property name="CharacterSet" value="UTF8" />
<property name="LangID" value="1033" />
<property name="BuildSeparateIndexFile" value="False" />
<property name="DocSetList" value="NETFramework" />
<property name="Version" value="1.0.0.0" />
<property name="CreateFullTextIndex" value="True" />
<property name="IncludeDefaultStopWordList" value="True" />
<property name="UseHelpNamespaceMappingFile" value="" />
<property name="OmitSyntaxSection" value="False" />
<property name="IntroductionPage" value="" />
<property name="AboutPageInfo" value="" />
<property name="EmptyIndexTermPage" value="" />
<property name="NavFailPage" value="" />
<property name="AboutPageIconPage" value="" />
<property name="AdditionalContentResourceDirectory" value="" />
<property name="ExtensibilityStylesheet" value="" />
<property name="ShowMissingSummaries" value="False" />
<property name="ShowMissingRemarks" value="False" />
<property name="ShowMissingParams" value="False" />
<property name="ShowMissingReturns" value="False" />
<property name="ShowMissingValues" value="False" />
<property name="DocumentExplicitInterfaceImplementations" value="False" />
<property name="DocumentInternals" value="False" />
<property name="DocumentProtected" value="True" />
<property name="DocumentSealedProtected" value="False" />
<property name="DocumentPrivates" value="False" />
<property name="DocumentProtectedInternalAsProtected" value="False" />
<property name="DocumentEmptyNamespaces" value="False" />
<property name="SkipNamespacesWithoutSummaries" value="False" />
<property name="EditorBrowsableFilter" value="Off" />
<property name="IncludeAssemblyVersion" value="False" />
<property name="CopyrightText" value="" />
<property name="CopyrightHref" value="" />
<property name="ReferencesPath" value="" />
<property name="FeedbackEmailAddress" value="" />
<property name="UseNamespaceDocSummaries" value="False" />
<property name="AutoPropertyBackerSummaries" value="False" />
<property name="AutoDocumentConstructors" value="True" />
<property name="GetExternalSummaries" value="True" />
<property name="Preliminary" value="False" />
<property name="UseNDocXmlFile" value="" />
<property name="CleanIntermediates" value="False" />
<property name="DocumentAttributes" value="False" />
<property name="ShowTypeIdInAttributes" value="False" />
<property name="DocumentedAttributes" value="" />
<property name="InheritPlatformSupport" value="True" />
<property name="DefaultOSSupport" value="all" />
<property name="SupportCompactFrameworkByDefault" value="False" />
<property name="SupportMONOFrameworkByDefault" value="False" />
<property name="AdditionalFrameworkList" value="" />
<property name="AdditionalOSList" value="" />
</documenter>
<documenter name="XML">
<property name="OutputFile" value=".\doc\doc.xml" />
<property name="ShowMissingSummaries" value="False" />
<property name="ShowMissingRemarks" value="False" />
<property name="ShowMissingParams" value="False" />
<property name="ShowMissingReturns" value="False" />
<property name="ShowMissingValues" value="False" />
<property name="DocumentExplicitInterfaceImplementations" value="False" />
<property name="DocumentInternals" value="False" />
<property name="DocumentProtected" value="True" />
<property name="DocumentSealedProtected" value="False" />
<property name="DocumentPrivates" value="False" />
<property name="DocumentProtectedInternalAsProtected" value="False" />
<property name="DocumentEmptyNamespaces" value="False" />
<property name="SkipNamespacesWithoutSummaries" value="False" />
<property name="EditorBrowsableFilter" value="Off" />
<property name="IncludeAssemblyVersion" value="False" />
<property name="CopyrightText" value="" />
<property name="CopyrightHref" value="" />
<property name="ReferencesPath" value="" />
<property name="FeedbackEmailAddress" value="" />
<property name="UseNamespaceDocSummaries" value="False" />
<property name="AutoPropertyBackerSummaries" value="False" />
<property name="AutoDocumentConstructors" value="True" />
<property name="GetExternalSummaries" value="True" />
<property name="Preliminary" value="False" />
<property name="UseNDocXmlFile" value="" />
<property name="CleanIntermediates" value="False" />
<property name="DocumentAttributes" value="False" />
<property name="ShowTypeIdInAttributes" value="False" />
<property name="DocumentedAttributes" value="" />
<property name="InheritPlatformSupport" value="True" />
<property name="DefaultOSSupport" value="all" />
<property name="SupportCompactFrameworkByDefault" value="False" />
<property name="SupportMONOFrameworkByDefault" value="False" />
<property name="AdditionalFrameworkList" value="" />
<property name="AdditionalOSList" value="" />
</documenter>
</documenters>
</project>

30
lib/NPlot.sln Normal file
Просмотреть файл

@ -0,0 +1,30 @@
Microsoft Visual Studio Solution File, Format Version 8.00
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NPlot", "NPlot.csproj", "{E6867FF5-74EC-4464-8958-D71CB46232F3}"
ProjectSection(ProjectDependencies) = postProject
EndProjectSection
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NPlotDemo", "..\demos\cs\NPlotDemo.csproj", "{7427C7A7-6CB0-4CB3-A0DB-F11603C5C29A}"
ProjectSection(ProjectDependencies) = postProject
{E6867FF5-74EC-4464-8958-D71CB46232F3} = {E6867FF5-74EC-4464-8958-D71CB46232F3}
EndProjectSection
EndProject
Global
GlobalSection(SolutionConfiguration) = preSolution
Debug = Debug
Release = Release
EndGlobalSection
GlobalSection(ProjectConfiguration) = postSolution
{E6867FF5-74EC-4464-8958-D71CB46232F3}.Debug.ActiveCfg = Debug|.NET
{E6867FF5-74EC-4464-8958-D71CB46232F3}.Debug.Build.0 = Debug|.NET
{E6867FF5-74EC-4464-8958-D71CB46232F3}.Release.ActiveCfg = Release|.NET
{E6867FF5-74EC-4464-8958-D71CB46232F3}.Release.Build.0 = Release|.NET
{7427C7A7-6CB0-4CB3-A0DB-F11603C5C29A}.Debug.ActiveCfg = Debug|.NET
{7427C7A7-6CB0-4CB3-A0DB-F11603C5C29A}.Debug.Build.0 = Debug|.NET
{7427C7A7-6CB0-4CB3-A0DB-F11603C5C29A}.Release.ActiveCfg = Release|.NET
{7427C7A7-6CB0-4CB3-A0DB-F11603C5C29A}.Release.Build.0 = Release|.NET
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
EndGlobalSection
GlobalSection(ExtensibilityAddIns) = postSolution
EndGlobalSection
EndGlobal

90
lib/NPlotException.cs Normal file
Просмотреть файл

@ -0,0 +1,90 @@
/*
NPlot - A charting library for .NET
NPlotException.cs
Copyright (C) 2005
Matt Howlett
Redistribution and use of NPlot or parts there-of in source and
binary forms, with or without modification, are permitted provided
that the following conditions are met:
1. Re-distributions in source form must retain at the head of each
source file the above copyright notice, this list of conditions
and the following disclaimer.
2. Any product ("the product") that makes use NPlot or parts
there-of must either:
(a) allow any user of the product to obtain a complete machine-
readable copy of the corresponding source code for the
product and the version of NPlot used for a charge no more
than your cost of physically performing source distribution,
on a medium customarily used for software interchange, or:
(b) reproduce the following text in the documentation, about
box or other materials intended to be read by human users
of the product that is provided to every human user of the
product:
"This product includes software developed as
part of the NPlot library project available
from: http://www.nplot.com/"
The words "This product" may optionally be replace with
the actual name of the product.
------------------------------------------------------------------------
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
using System;
namespace NPlot
{
/// <summary>
/// All exceptions thrown by NPlot are of this type.
/// </summary>
public class NPlotException : System.Exception
{
/// <summary>
/// Constructor
/// </summary>
/// <param name="message">The error message that explains the reason for the exception.</param>
/// <param name="innerException">The exception that is the cause of the current exception.</param>
public NPlotException( string message, System.Exception innerException )
: base( message, innerException )
{
}
/// <summary>
/// Constructor
/// </summary>
/// <param name="message">The error message that explains the reason for the exception.</param>
public NPlotException( string message )
: base( message )
{
}
/// <summary>
/// Constructor.
/// </summary>
public NPlotException()
{
}
}
}

Просмотреть файл

@ -0,0 +1,151 @@
/*
NPlot - A charting library for .NET
PageAlignedPhysicalAxis.cs
Copyright (C) 2005
Matt Howlett
Redistribution and use of NPlot or parts there-of in source and
binary forms, with or without modification, are permitted provided
that the following conditions are met:
1. Re-distributions in source form must retain at the head of each
source file the above copyright notice, this list of conditions
and the following disclaimer.
2. Any product ("the product") that makes use NPlot or parts
there-of must either:
(a) allow any user of the product to obtain a complete machine-
readable copy of the corresponding source code for the
product and the version of NPlot used for a charge no more
than your cost of physically performing source distribution,
on a medium customarily used for software interchange, or:
(b) reproduce the following text in the documentation, about
box or other materials intended to be read by human users
of the product that is provided to every human user of the
product:
"This product includes software developed as
part of the NPlot library project available
from: http://www.nplot.com/"
The words "This product" may optionally be replace with
the actual name of the product.
------------------------------------------------------------------------
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
using System;
using System.Collections;
namespace NPlot
{
/// <summary>
/// The bare minimum needed to do world->physical and physical->world transforms for
/// vertical axes. Also includes tick placements. Built for speed.
/// </summary>
/// <remarks>currently unused</remarks>
public class PageAlignedPhysicalAxis
{
private int pMin_;
private int pMax_;
private int pLength_; // cached.
private double worldMin_;
private double worldMax_;
private double worldLength_; // cached.
/// <summary>
/// Construct from a fully-blown physical axis.
/// </summary>
/// <param name="physicalAxis">the physical axis to get initial values from.</param>
public PageAlignedPhysicalAxis( PhysicalAxis physicalAxis )
{
worldMin_ = physicalAxis.Axis.WorldMin;
worldMax_ = physicalAxis.Axis.WorldMax;
worldLength_ = worldMax_ - worldMin_;
if ( physicalAxis.PhysicalMin.X == physicalAxis.PhysicalMax.X )
{
pMin_ = physicalAxis.PhysicalMin.Y;
pMax_ = physicalAxis.PhysicalMax.Y;
}
else if ( physicalAxis.PhysicalMin.Y == physicalAxis.PhysicalMax.Y )
{
pMin_ = physicalAxis.PhysicalMin.X;
pMax_ = physicalAxis.PhysicalMax.X;
}
else
{
throw new NPlotException( "Physical axis is not page aligned" );
}
pLength_ = pMax_ - pMin_;
}
/// <summary>
/// return the physical coordinate corresponding to the supplied world coordinate.
/// </summary>
/// <param name="world">world coordinate to determine physical coordinate for.</param>
/// <returns>the physical coordinate corresoindng to the supplied world coordinate.</returns>
public float WorldToPhysical( double world )
{
return (float)(((world-worldMin_) / worldLength_) * (float)pLength_ + (float)pMin_);
}
/// <summary>
/// return the physical coordinate corresponding to the supplied world coordinate,
/// clipped if it is outside the bounds of the axis
/// </summary>
/// <param name="world">world coordinate to determine physical coordinate for.</param>
/// <returns>the physical coordinate corresoindng to the supplied world coordinate.</returns>
public float WorldToPhysicalClipped( double world )
{
if (world > worldMax_)
{
return pMax_;
}
if (world < worldMin_)
{
return pMin_;
}
// is this quicker than returning WorldToPhysical?
return (float)(((world-worldMin_) / worldLength_) * (float)pLength_ + (float)pMin_);
}
/// <summary>
/// return the world coordinate corresponding to the supplied physical coordinate.
/// </summary>
/// <param name="physical">physical coordinate to determine world coordinate for.</param>
/// <returns>the world coordinate corresponding to the supplied </returns>
public double PhysicalToWorld( float physical )
{
return ((float)(physical-pMin_) / (float)pLength_) * worldLength_ + worldMin_;
}
}
}

276
lib/PhysicalAxis.cs Normal file
Просмотреть файл

@ -0,0 +1,276 @@
/*
NPlot - A charting library for .NET
PhysicalAxis.cs
Copyright (C) 2003
Matt Howlett, Paolo Pierini
Redistribution and use of NPlot or parts there-of in source and
binary forms, with or without modification, are permitted provided
that the following conditions are met:
1. Re-distributions in source form must retain at the head of each
source file the above copyright notice, this list of conditions
and the following disclaimer.
2. Any product ("the product") that makes use NPlot or parts
there-of must either:
(a) allow any user of the product to obtain a complete machine-
readable copy of the corresponding source code for the
product and the version of NPlot used for a charge no more
than your cost of physically performing source distribution,
on a medium customarily used for software interchange, or:
(b) reproduce the following text in the documentation, about
box or other materials intended to be read by human users
of the product that is provided to every human user of the
product:
"This product includes software developed as
part of the NPlot library project available
from: http://www.nplot.com/"
The words "This product" may optionally be replace with
the actual name of the product.
------------------------------------------------------------------------
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
using System;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Collections;
namespace NPlot
{
/// <summary>
/// This class adds physical positioning information [PhysicalMin, PhysicalMax]
/// and related functionality on top of a specific Axis class.
///
/// It's an interesting
/// question where to put this information. It belongs with every specific axis
/// type, but on the other hand, users of the library as it is normally used
/// should not see it because
/// positioning of axes is handled internally by PlotSurface2D. Therefore it doesn't make sense
/// to put it in the Axis class unless it is internal. But if this were done it would restrict
/// use of this information outside the library always, which is not what is wanted.
/// The main disadvantage with the method chosen is that there is a lot of passing
/// of the positional information between physical axis and the underlying logical
/// axis type.
///
/// C# doesn't have templates. If it did, I might derive PhysicalAxis from the
/// templated Axis type (LinearAxis etc). Instead, have used a has-a relationship
/// with an Axis superclass.
/// </summary>
public class PhysicalAxis
{
/// <summary>
/// Prevent default construction.
/// </summary>
private PhysicalAxis()
{
}
/// <summary>
/// Construct
/// </summary>
/// <param name="a">The axis this is a physical representation of.</param>
/// <param name="physicalMin">the physical position of the world minimum axis value.</param>
/// <param name="physicalMax">the physical position of the world maximum axis value.</param>
public PhysicalAxis( Axis a, Point physicalMin, Point physicalMax )
{
this.Axis = a;
this.PhysicalMin = physicalMin;
this.PhysicalMax = physicalMax;
}
/// <summary>
/// Returns the smallest rectangle that completely contains all parts of the axis [including ticks and label].
/// </summary>
/// <returns>the smallest rectangle that completely contains all parts of the axis [including ticks and label].</returns>
public virtual Rectangle GetBoundingBox()
{
System.Drawing.Bitmap scratchArea_ = new System.Drawing.Bitmap( 1, 1 );
Graphics g = Graphics.FromImage( scratchArea_ );
Rectangle bounds;
this.Draw( g, out bounds );
return bounds;
}
/// <summary>
/// Draws the axis on the given graphics surface.
/// </summary>
/// <param name="g">The graphics surface on which to draw.</param>
/// <param name="boundingBox">out: the axis bounding box - the smallest rectangle that
/// completely contains all parts of the axis [including ticks and label].</param>
public virtual void Draw( System.Drawing.Graphics g, out Rectangle boundingBox )
{
this.Axis.Draw( g, PhysicalMin, PhysicalMax, out boundingBox );
}
/// <summary>
/// Given a world coordinate value, returns the physical position of the
/// coordinate along the axis.
/// </summary>
/// <param name="coord">the world coordinate</param>
/// <param name="clip">if true, the physical position returned will be clipped to the physical max / min position as appropriate if the world value is outside the limits of the axis.</param>
/// <returns>the physical position of the coordinate along the axis.</returns>
public PointF WorldToPhysical( double coord, bool clip )
{
return Axis.WorldToPhysical( coord, PhysicalMin, PhysicalMax, clip );
}
/// <summary>
/// Given a physical point on the graphics surface, returns the world
/// value of it's projection onto the axis [i.e. closest point on the axis].
/// The function is implemented for axes of arbitrary orientation.
/// </summary>
/// <param name="p">Physical point to find corresponding world value of.</param>
/// <param name="clip">if true, returns a world position outside WorldMin / WorldMax
/// range if this is closer to the axis line. If false, such values will
/// be clipped to be either WorldMin or WorldMax as appropriate.</param>
/// <returns>the world value of the point's projection onto the axis.</returns>
public double PhysicalToWorld( Point p, bool clip )
{
return Axis.PhysicalToWorld( p, PhysicalMin, PhysicalMax, clip );
}
/// <summary>
/// This sets new world limits for the axis from two physical points
/// selected within the plot area.
/// </summary>
/// <param name="min">The upper left point of the selection.</param>
/// <param name="max">The lower right point of the selection.</param>
public void SetWorldLimitsFromPhysical( Point min, Point max )
{
double minc;
double maxc;
if (Axis != null)
{
minc = Axis.WorldMin;
maxc = Axis.WorldMax;
if ( !Axis.Reversed )
{
double tmp = this.PhysicalToWorld(min,true);
Axis.WorldMax = this.PhysicalToWorld(max,true);
Axis.WorldMin = tmp;
}
else
{
double tmp = this.PhysicalToWorld(min,true);
Axis.WorldMin = this.PhysicalToWorld(max,true);
Axis.WorldMax = tmp;
}
// need to trap somehow if the user selects an
// arbitrarily small range. Otherwise the GDI+
// drawing routines lead to an overflow in painting
// the picture. This may be not the optimal solution,
// but if the GDI+ draw leads to an overflow the
// graphic surface becomes unusable anymore and I
// had difficulty to trap the error.
double half = (Axis.WorldMin + Axis.WorldMax)/2;
double width = Axis.WorldMax - Axis.WorldMin;
if (Math.Abs(half/width) > 1.0e12)
{
Axis.WorldMin = minc;
Axis.WorldMax = maxc;
}
}
}
/// <summary>
/// The physical position corresponding to WorldMin.
/// </summary>
public Point PhysicalMin
{
get
{
return physicalMin_;
}
set
{
physicalMin_ = value;
}
}
private Point physicalMin_;
/// <summary>
/// The physical position corresponding to WorldMax.
/// </summary>
public Point PhysicalMax
{
get
{
return physicalMax_;
}
set
{
physicalMax_ = value;
}
}
private Point physicalMax_;
/// <summary>
/// The axis this object adds physical extents to.
/// </summary>
public Axis Axis
{
get
{
return axis_;
}
set
{
axis_ = value;
}
}
private Axis axis_;
/// <summary>
/// The length in pixels of the axis.
/// </summary>
public int PhysicalLength
{
get
{
return Utils.Distance( PhysicalMin, PhysicalMax );
}
}
/// <summary>
/// The length in world coordinates of one pixel.
/// </summary>
public double PixelWorldLength
{
get
{
return this.Axis.WorldLength / this.PhysicalLength;
}
}
}
}

230
lib/PiAxis.cs Normal file
Просмотреть файл

@ -0,0 +1,230 @@
/*
NPlot - A charting library for .NET
PiAxis.cs
Copyright (C) 2004
Matt Howlett
Redistribution and use of NPlot or parts there-of in source and
binary forms, with or without modification, are permitted provided
that the following conditions are met:
1. Re-distributions in source form must retain at the head of each
source file the above copyright notice, this list of conditions
and the following disclaimer.
2. Any product ("the product") that makes use NPlot or parts
there-of must either:
(a) allow any user of the product to obtain a complete machine-
readable copy of the corresponding source code for the
product and the version of NPlot used for a charge no more
than your cost of physically performing source distribution,
on a medium customarily used for software interchange, or:
(b) reproduce the following text in the documentation, about
box or other materials intended to be read by human users
of the product that is provided to every human user of the
product:
"This product includes software developed as
part of the NPlot library project available
from: http://www.nplot.com/"
The words "This product" may optionally be replace with
the actual name of the product.
------------------------------------------------------------------------
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
using System;
using System.Drawing;
using System.Collections;
namespace NPlot
{
/// <summary>
/// Axis with labels in multiples of Pi. Maybe needs a better name.
/// Lots of functionality still to be added - currently only puts labels
/// at whole increments of pi, want arbitrary increments, automatically
/// determined and dependance on physical length.
/// Volunteers?
/// </summary>
public class PiAxis : Axis
{
/// <summary>
/// Deep copy of PiAxis.
/// </summary>
/// <returns>A copy of the LinearAxis Class.</returns>
public override object Clone()
{
PiAxis a = new PiAxis();
// ensure that this isn't being called on a derived type. If it is, then oh no!
if (this.GetType() != a.GetType())
{
throw new NPlotException( "Error. Clone method is not defined in derived type." );
}
DoClone( this, a );
return a;
}
/// <summary>
/// Helper method for Clone.
/// </summary>
/// <param name="a">The original object to clone.</param>
/// <param name="b">The cloned object.</param>
protected static void DoClone( PiAxis b, PiAxis a )
{
Axis.DoClone( b, a );
}
/// <summary>
/// Initialise PiAxis to default state.
/// </summary>
private void Init()
{
}
/// <summary>
/// Copy constructor
/// </summary>
/// <param name="a">The Axis to clone.</param>
/// <remarks>TODO: [review notes] I don't think this will work as desired.</remarks>
public PiAxis( Axis a )
: base( a )
{
Init();
}
/// <summary>
/// Default constructor
/// </summary>
public PiAxis()
: base()
{
Init();
}
/// <summary>
/// Constructor
/// </summary>
/// <param name="worldMin">Minimum world value</param>
/// <param name="worldMax">Maximum world value</param>
public PiAxis( double worldMin, double worldMax )
: base( worldMin, worldMax )
{
Init();
}
/// <summary>
/// Given Graphics surface, and physical extents of axis, draw ticks and
/// associated labels.
/// </summary>
/// <param name="g">The GDI+ Graphics surface on which to draw.</param>
/// <param name="physicalMin">The physical location of the world min point</param>
/// <param name="physicalMax">The physical location of the world max point</param>
/// <param name="boundingBox">out: smallest box that completely encompasses all of the ticks and tick labels.</param>
/// <param name="labelOffset">out: a suitable offset from the axis to draw the axis label.</param>
protected override void DrawTicks(
Graphics g,
Point physicalMin,
Point physicalMax,
out object labelOffset,
out object boundingBox )
{
Point tLabelOffset;
Rectangle tBoundingBox;
labelOffset = this.getDefaultLabelOffset( physicalMin, physicalMax );
boundingBox = null;
int start = (int)Math.Ceiling( this.WorldMin / Math.PI );
int end = (int)Math.Floor( this.WorldMax / Math.PI );
// sanity checking.
if ( end - start < 0 || end - start > 30 )
{
return;
}
for (int i=start; i<=end; ++i)
{
string label = i.ToString() + "Pi";
if (i == 0)
label = "0";
else if (i == 1)
label = "Pi";
this.DrawTick( g, i*Math.PI, this.LargeTickSize,
label,
new Point(0,0),
physicalMin, physicalMax,
out tLabelOffset, out tBoundingBox );
Axis.UpdateOffsetAndBounds(
ref labelOffset, ref boundingBox,
tLabelOffset, tBoundingBox );
}
}
/// <summary>
/// Determines the positions, in world coordinates, of the large ticks.
///
/// Label axes do not have small ticks.
/// </summary>
/// <param name="physicalMin">The physical position corresponding to the world minimum of the axis.</param>
/// <param name="physicalMax">The physical position corresponding to the world maximum of the axis.</param>
/// <param name="largeTickPositions">ArrayList containing the positions of the large ticks.</param>
/// <param name="smallTickPositions">null</param>
internal override void WorldTickPositions_FirstPass(
Point physicalMin,
Point physicalMax,
out ArrayList largeTickPositions,
out ArrayList smallTickPositions
)
{
smallTickPositions = null;
largeTickPositions = new ArrayList();
int start = (int)Math.Ceiling( this.WorldMin / Math.PI );
int end = (int)Math.Floor( this.WorldMax / Math.PI );
// sanity checking.
if ( end - start < 0 || end - start > 30 )
{
return;
}
for (int i=start; i<end; ++i)
{
largeTickPositions.Add( i*Math.PI );
}
}
}
}

120
lib/PiePlot.cs Normal file
Просмотреть файл

@ -0,0 +1,120 @@
/*
NPlot - A charting library for .NET
PiePlot.cs
Copyright (C) 2004
Thierry Malo
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
$Id: PiePlot.cs,v 1.3 2004/10/23 07:08:35 mhowlett Exp $
*/
/*
using System;
using System.Drawing;
namespace scpl
{
/// <summary>
/// Description résumée de PiePlot.
/// </summary>
public class PiePlot : BasePlot, IPlot
{
public PiePlot(ISequenceAdapter datas)
{
//
// TODO : ajoutez ici la logique du constructeur
//
this.Data=datas;
_brushes=new Brush[_MaxBrush];
_brushes[0] = Brushes.DarkBlue;
_brushes[1] = Brushes.Yellow;
_brushes[2] = Brushes.Green;
_brushes[3] = Brushes.Brown;
_brushes[4] = Brushes.Blue;
_brushes[5] = Brushes.Red;
_brushes[6] = Brushes.LightGreen;
_brushes[7] = Brushes.Salmon;
}
private ISequenceAdapter data_;
private double _Total;
const int _MaxBrush=8;
private Brush[] _brushes;
public ISequenceAdapter Data
{
get
{
return data_;
}
set
{
data_ = value;
// calculate the sum of all value (this is related to 360°)
_Total = 0;
for ( int i=0; i<data_.Count; ++i )
{
_Total += data_[i].Y;
}
}
}
#region SuggestXAxis
public virtual Axis SuggestXAxis()
{
return data_.SuggestXAxis();
}
#endregion
#region SuggestXAxis
public virtual Axis SuggestYAxis()
{
return data_.SuggestYAxis();
}
#endregion
public virtual void Draw( Graphics g, PhysicalAxis xAxis, PhysicalAxis yAxis )
{
int LastAngle=0,ReelAngle;
float rx=(xAxis.PhysicalMax.X - xAxis.PhysicalMin.X);
float ry=(yAxis.PhysicalMin.Y - yAxis.PhysicalMax.Y);
int h=(int) (ry * 0.8);
int w= (int) (rx * 0.8);
// This is to keep the pie based on a circle (i.e. inside a square)
int s=Math.Min(h,w);
// calculate boundary rectangle coordinate
int cy=(int) (yAxis.PhysicalMax.Y + (h * 1.2 - s) / 2);
int cx=(int) (xAxis.PhysicalMin.X + (w * 1.2 - s) / 2);
for (int i=0; i<this.Data.Count; ++i)
{
ReelAngle = (int) (data_[i].Y * 360 / _Total);
g.FillPie(_brushes[i % _MaxBrush], cx, cy, s, s, LastAngle, ReelAngle);
LastAngle += ReelAngle;
}
}
}
}
*/

1334
lib/PlotSurface2D.cs Normal file

Разница между файлами не показана из-за своего большого размера Загрузить разницу

439
lib/PlotSurface2Dnew.cs Normal file
Просмотреть файл

@ -0,0 +1,439 @@
// ******** experimental ********
/*
using System;
using System.Xml;
using System.Data;
using System.Collections;
using System.IO;
using System.Reflection;
using System.Drawing;
namespace NPlot
{
class PlotSurface2Dnew
{
private ArrayList axisLines_;
private ArrayList axisDefinitions_;
private ArrayList drawables_;
private ArrayList xAxisPositions_;
private ArrayList yAxisPositions_;
private System.Collections.Hashtable axes_;
/// <summary>
/// PlotSurface2D styles supplied with the library.
/// </summary>
public enum PlotSurfaceStyle
{
Standard,
CrossedAxes,
OppositeCloned
}
private class AxisDefinition
{
public string Name = "";
public AxisLine axisLine = null;
public int Min = 0;
public int Max = 100;
}
private class AxisLine
{
public enum OrientationType
{
Horizontal,
Vertical
}
public string Name = "";
public OrientationType Orientation = OrientationType.Horizontal;
public float Position = 0;
}
/// <summary>
/// Constructor
/// </summary>
public PlotSurface2Dnew()
{
Init();
}
private AxisDefinition parseAxis( XmlNode node )
{
// get Parameters
AxisDefinition d = new AxisDefinition();
for (int i=0; i<node.Attributes.Count; ++i)
{
XmlAttribute a = node.Attributes[i];
switch (a.Name.ToLower())
{
case "name":
d.Name = a.Value;
break;
case "axisline":
bool found = false;
for (int j=0; j<axisLines_.Count; ++j)
{
if (((AxisLine)axisLines_[j]).Name == a.Value)
{
d.axisLine = (AxisLine)axisLines_[j];
found = true;
}
}
if (!found)
{
ErrorHandler.Instance.CriticalError( "AxisLine not found" );
}
break;
case "physicalmin":
try
{
d.Min = Convert.ToInt32( a.Value );
}
catch
{
ErrorHandler.Instance.CriticalError( "min value not numeric" );
}
if (d.Min< 0 || d.Min > 100)
{
ErrorHandler.Instance.CriticalError( "min value must be between 0 and 100" );
}
break;
case "physicalmax":
try
{
d.Max = Convert.ToInt32( a.Value );
}
catch
{
ErrorHandler.Instance.CriticalError( "max value not numeric" );
}
if (d.Max < 0 || d.Max > 100)
{
ErrorHandler.Instance.CriticalError( "max value must be between 0 and 100" );
}
break;
default:
ErrorHandler.Instance.CriticalError( "unknown attribute: " + a.Name );
break;
}
}
return d;
}
private AxisLine parseAxisLine( XmlNode node )
{
AxisLine l = new AxisLine();
for (int i=0; i<node.Attributes.Count; ++i)
{
XmlAttribute a = node.Attributes[i];
switch (a.Name.ToLower())
{
case "name":
l.Name = a.Value;
break;
case "orientation":
if (a.Value.ToLower() == "horizontal")
l.Orientation = AxisLine.OrientationType.Horizontal;
else if (a.Value.ToLower() == "vertical")
l.Orientation = AxisLine.OrientationType.Vertical;
else
{
ErrorHandler.Instance.CriticalError( "Unexpected orientation :" + a.Value.ToString() );
}
break;
case "position":
try
{
l.Position = Convert.ToInt32( a.Value );
}
catch
{
ErrorHandler.Instance.CriticalError( "position not numeric" );
}
if (l.Position < 0 || l.Position > 100)
{
ErrorHandler.Instance.CriticalError( "axis position must be between 0 and 100" );
}
break;
default:
ErrorHandler.Instance.CriticalError( "unknown axis line attribute: " + a.Name );
break;
}
}
return l;
}
public void SetDefinition( )
{
Assembly ass = Assembly.GetExecutingAssembly();
System.IO.Stream xmlStream =
ass.GetManifestResourceStream( "NPlot.PlotSurfaceDefinitions.OppositeCloned.xml" );
// load xml
XmlDocument xmlDoc = null;
try
{
xmlDoc = new XmlDocument();
xmlDoc.Load( xmlStream );
}
catch
{
ErrorHandler.Instance.CriticalError( "PlotSurface2D definition file malformed" );
}
XmlElement el = xmlDoc.DocumentElement;
// check we're a PlotSurface2D.
if (el.Name.ToLower() != "plotsurface2d")
{
ErrorHandler.Instance.CriticalError( "Root element must be PlotSurface2D" );
return;
}
// enforce only one axis set for now.
if (el.ChildNodes.Count != 1)
{
ErrorHandler.Instance.CriticalError( "need one and only one axis set." );
return;
}
// loop around all AxisSets.
foreach (XmlNode n in el.ChildNodes)
{
if (n.Name.ToLower() != "axisset")
{
ErrorHandler.Instance.CriticalError( "Expected AxisSet node" );
return;
}
// loop around all nodes in this axis set.
foreach (XmlNode n2 in n.ChildNodes)
{
switch (n2.Name.ToLower())
{
case "axisline":
{
axisLines_.Add( parseAxisLine(n2) );
break;
}
case "axis":
{
axisDefinitions_.Add( parseAxis(n2) );
break;
}
default:
{
ErrorHandler.Instance.CriticalError( "Unexpected node type encountered: " + n2.Name );
return;
}
}
} // end loop around each node in axis set
// add all axes to class
for (int i=0; i<axisDefinitions_.Count; ++i)
{
//axes_.Add( ((AxisDefinition)axisDefinitions_[i]).Name, null );
}
} // end loop around axis sets.
}
/// <summary>
/// The distance in pixels to leave between of the edge of the bounding rectangle
/// supplied to the Draw method, and the markings that make up the plot.
/// </summary>
public int Padding
{
get
{
return padding_;
}
set
{
padding_ = value;
}
}
private int padding_;
private void Init()
{
axes_ = null;
drawables_ = new ArrayList();
xAxisPositions_ = new ArrayList();
yAxisPositions_ = new ArrayList();
axisLines_ = new ArrayList();
axisDefinitions_ = new ArrayList();
padding_ = 10;
}
/// <summary>
/// Draw the the PlotSurface2D and all contents [axes, drawables, and legend] on the
/// supplied graphics surface.
/// </summary>
/// <param name="g">The graphics surface on which to draw.</param>
/// <param name="bounds">A bounding box on this surface that denotes the area on the
/// surface to confine drawing to.</param>
public void Draw( Graphics g, Rectangle bounds )
{
Rectangle realBounds = new Rectangle(
bounds.X + padding_ / 2,
bounds.Y + padding_ / 2,
bounds.Width - padding_,
bounds.Height - padding_
);
// create initial set of physical axes. These will
// be moved later to ensure everything is drawn ok.
ArrayList physicalAxes = new ArrayList();
for (int i=0; i<axisDefinitions_.Count; ++i)
{
AxisDefinition d = (AxisDefinition)axisDefinitions_[i];
Point physicalMin = new Point(0,0);
Point physicalMax = new Point(0,0);
if (d.axisLine.Orientation == AxisLine.OrientationType.Horizontal)
{
int yPos = (int)(realBounds.Top + ((float)d.axisLine.Position/100.0 * realBounds.Height));
physicalMin.X = realBounds.Left;
physicalMin.Y = yPos;
physicalMax.X = realBounds.Right;
physicalMax.Y = yPos;
}
else
{
int xPos = (int)(realBounds.Left + ((float)d.axisLine.Position/100.0 * realBounds.Width));
physicalMin.X = xPos;
physicalMin.Y = realBounds.Bottom;
physicalMax.X = xPos;
physicalMax.Y = realBounds.Top;
}
physicalAxes.Add( new PhysicalAxis( new LinearAxis(0.0,1.0), physicalMin, physicalMax ) );
}
for (int i=0; i<physicalAxes.Count; ++i)
{
Rectangle axisBounds;
((PhysicalAxis)physicalAxes[i]).Draw( g, out axisBounds );
}
}
private void UpdateAxes()
{
// make sure drawable lists exist.
if (drawables_.Count==0 || xAxisPositions_.Count==0 || yAxisPositions_.Count==0)
{
ErrorHandler.Instance.ContinuingError( "UpdateAxes called from function other than Add." );
}
int last = drawables_.Count - 1;
if ( last != xAxisPositions_.Count-1 || last != yAxisPositions_.Count-1 )
{
ErrorHandler.Instance.CriticalError( "plots and axis position arrays our of sync" );
}
// make sure axes exit.
AxisDefinition xAxisDefinition = null;
AxisDefinition yAxisDefinition = null;
for (int i=0; i<this.axisDefinitions_.Count; ++i)
{
AxisDefinition def = (AxisDefinition)axisDefinitions_[i];
if (def.Name == (string)xAxisPositions_[last])
xAxisDefinition = def;
if (def.Name == (string)yAxisPositions_[last])
yAxisDefinition = def;
}
if (xAxisDefinition == null || yAxisDefinition == null)
{
ErrorHandler.Instance.CriticalError( "Axis does not exist." );
}
IPlot p = (IPlot)drawables_[last];
// update x axis.
if (axes_[xAxisDefinition.Name] == null)
{
this.axes_[xAxisDefinition.Name] = p.SuggestXAxis();
}
else
{
((Axis)this.axes_[xAxisDefinition.Name]).LUB( p.SuggestXAxis() );
}
// update y axis.
if (axes_[yAxisDefinition.Name] == null)
{
this.axes_[yAxisDefinition.Name] = p.SuggestYAxis();
}
else
{
((Axis)this.axes_[yAxisDefinition.Name]).LUB( p.SuggestYAxis() );
}
}
/// <summary>
/// Adds a drawable object to the plot surface against the specified axes. If
/// the object is an IPlot, the PlotSurface2D axes will also be updated.
/// </summary>
/// <param name="p">the IDrawable object to add to the plot surface</param>
/// <param name="xAxis">the x-axis to add the plot against.</param>
/// <param name="yAxis">the y-axis to add the plot against.</param>
public void Add( IDrawable p, string xAxis, string yAxis )
{
drawables_.Add( p );
xAxisPositions_.Add( xAxis );
yAxisPositions_.Add( yAxis );
if ( p is IPlot )
{
this.UpdateAxes();
}
}
}
}
*/

64
lib/PlotSurface3D.cs Normal file
Просмотреть файл

@ -0,0 +1,64 @@
// ******** experimental ********
/*
NPlot - A charting library for .NET
PlotSurface3D.cs
Copyright (C) 2003
Matt Howlett
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the following text in
the documentation and / or other materials provided with the
distribution:
"This product includes software developed as part of
the NPlot charting library project available from:
http://www.nplot.com/"
------------------------------------------------------------------------
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
$Id: PlotSurface3D.cs,v 1.9 2004/11/17 10:39:19 mhowlett Exp $
*/
/*
using System;
namespace NPlot
{
/// <summary>
/// TODO
/// </summary>
public class PlotSurface3D : IPlotSurface3D
{
/// <summary>
/// TODO
/// </summary>
public PlotSurface3D()
{
}
}
}
*/

Просмотреть файл

@ -0,0 +1,26 @@
<!-- ******** experimental ******** -->
<?xml version="1.0" encoding="utf-8" ?>
<PlotSurface2D name="CrossedAxes">
<AxisSet rotation="0">
<AxisLine name="MiddleHorizontalLine" type="X" placement="80" ExtendDirection=-90/>
<AxisLine name="MiddleVerticalLine" type="Y" placement="50" ExtendDirection=-90/>
<Axis type="X" name="XAxis">
<Placement line="MiddleHorizontalLine" PhysicalMin=0 PhysicalMax=100 />
</Axis>
<Axis type="Y" name="YAxis">
<Placement line="MiddleVerticalLine" PhysicalMin=0 PhysicalMax=100 />
</Axis>
<Axis type="Y" name="YAxis2">
<Placement line="MiddleVerticalLine" PhysicalMin=0 PhysicalMax=100 />
</Axis>
</AxisSet>
</PlotSurface2D>

Просмотреть файл

@ -0,0 +1,21 @@
<!-- ******** experimental ******** -->
<?xml version="1.0" encoding="utf-8" ?>
<PlotSurface2D>
<AxisSet rotation="0">
<AxisLine Name="MiddleHorizontalLine" orientation="Horizontal" position="20" />
<AxisLine name="MiddleVerticalLine" orientation="Vertical" position="50" />
<Axis name="XAxis" axisLine="MiddleHorizontalLine" physicalMin="0" physicalMax="100">
</Axis>
<Axis name="YAxis" axisLine="MiddleVerticalLine" physicalMin="0" physicalMax="100">
</Axis>
</AxisSet>
</PlotSurface2D>

Просмотреть файл

@ -0,0 +1,14 @@
<!-- ******** experimental ******** -->
<?xml version="1.0" encoding="utf-8" ?>
<PlotSurface name="Standard">
<AxisSet rotation="0">
<AxisLine name="MiddleHorizontalLine" type="X" placement="80" ExtendDire/>
<AxisLine name="MiddleVerticalLine" type="Y" placement="50"/>
</AxisSet>
</PlotSurface>

91
lib/PointD.cs Normal file
Просмотреть файл

@ -0,0 +1,91 @@
/*
NPlot - A charting library for .NET
PointD.cs
Copyright (C) 2003-2004
Matt Howlett
Redistribution and use of NPlot or parts there-of in source and
binary forms, with or without modification, are permitted provided
that the following conditions are met:
1. Re-distributions in source form must retain at the head of each
source file the above copyright notice, this list of conditions
and the following disclaimer.
2. Any product ("the product") that makes use NPlot or parts
there-of must either:
(a) allow any user of the product to obtain a complete machine-
readable copy of the corresponding source code for the
product and the version of NPlot used for a charge no more
than your cost of physically performing source distribution,
on a medium customarily used for software interchange, or:
(b) reproduce the following text in the documentation, about
box or other materials intended to be read by human users
of the product that is provided to every human user of the
product:
"This product includes software developed as
part of the NPlot library project available
from: http://www.nplot.com/"
The words "This product" may optionally be replace with
the actual name of the product.
------------------------------------------------------------------------
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
namespace NPlot
{
/// <summary>
/// Represtents a point in two-dimensional space. Used for representation
/// of points world coordinates.
/// </summary>
public struct PointD
{
/// <summary>
/// X-Coordinate of the point.
/// </summary>
public double X;
/// <summary>
/// Y-Coordinate of the point.
/// </summary>
public double Y;
/// <summary>
/// Constructor
/// </summary>
/// <param name="x">X-Coordinate of the point.</param>
/// <param name="y">Y-Coordinate of the point.</param>
public PointD( double x, double y )
{
X = x;
Y = y;
}
/// <summary>
/// returns a string representation of the point.
/// </summary>
/// <returns>string representation of the point.</returns>
public override string ToString()
{
return X.ToString() + "\t" + Y.ToString();
}
}
}

45
lib/PointD3D.cs Normal file
Просмотреть файл

@ -0,0 +1,45 @@
// ******** experimental ********
/*
using System;
namespace NPlot
{
/// <summary>
/// Represtents a point in three-dimensional space. Used for representation
/// of points world coordinates.
/// </summary>
public struct PointD3D
{
/// <summary>
/// X-Coordinate of the point.
/// </summary>
public double X;
/// <summary>
/// Y-Coordinate of the point.
/// </summary>
public double Y;
/// <summary>
/// Z-Coordinate of the point.
/// </summary>
public double Z;
/// <summary>
/// Constructor
/// </summary>
/// <param name="x">X-Coordinate of the point.</param>
/// <param name="y">Y-Coordinate of the point.</param>
/// <param name="z">Z-Coordinate of the point.</param>
public PointD3D( double x, double y, double z )
{
X = x;
Y = y;
Z = z;
}
}
}
*/

182
lib/PointPlot.cs Normal file
Просмотреть файл

@ -0,0 +1,182 @@
/*
NPlot - A charting library for .NET
PointPlot.cs
Copyright (C) 2003
Matt Howlett, Paolo Pierini
Redistribution and use of NPlot or parts there-of in source and
binary forms, with or without modification, are permitted provided
that the following conditions are met:
1. Re-distributions in source form must retain at the head of each
source file the above copyright notice, this list of conditions
and the following disclaimer.
2. Any product ("the product") that makes use NPlot or parts
there-of must either:
(a) allow any user of the product to obtain a complete machine-
readable copy of the corresponding source code for the
product and the version of NPlot used for a charge no more
than your cost of physically performing source distribution,
on a medium customarily used for software interchange, or:
(b) reproduce the following text in the documentation, about
box or other materials intended to be read by human users
of the product that is provided to every human user of the
product:
"This product includes software developed as
part of the NPlot library project available
from: http://www.nplot.com/"
The words "This product" may optionally be replace with
the actual name of the product.
------------------------------------------------------------------------
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
using System;
using System.Drawing;
namespace NPlot
{
/// <summary>
/// Encapsulates functionality for drawing data as a series of points.
/// </summary>
public class PointPlot : BaseSequencePlot, ISequencePlot, IPlot
{
private Marker marker_;
/// <summary>
/// Default Constructor
/// </summary>
public PointPlot()
{
marker_ = new Marker();
}
/// <summary>
/// Constructor for the marker plot.
/// </summary>
/// <param name="marker">The marker to use.</param>
public PointPlot( Marker marker )
{
marker_ = marker;
}
/// <summary>
/// Draws the point plot on a GDI+ surface against the provided x and y axes.
/// </summary>
/// <param name="g">The GDI+ surface on which to draw.</param>
/// <param name="xAxis">The X-Axis to draw against.</param>
/// <param name="yAxis">The Y-Axis to draw against.</param>
public virtual void Draw( Graphics g, PhysicalAxis xAxis, PhysicalAxis yAxis )
{
SequenceAdapter data_ =
new SequenceAdapter( this.DataSource, this.DataMember, this.OrdinateData, this.AbscissaData );
float leftCutoff_ = xAxis.PhysicalMin.X - marker_.Size;
float rightCutoff_ = xAxis.PhysicalMax.X + marker_.Size;
for (int i=0; i<data_.Count; ++i)
{
if ( !Double.IsNaN(data_[i].X) && !Double.IsNaN(data_[i].Y) )
{
PointF xPos = xAxis.WorldToPhysical( data_[i].X, false);
if (xPos.X < leftCutoff_ || rightCutoff_ < xPos.X)
continue;
PointF yPos = yAxis.WorldToPhysical( data_[i].Y, false);
marker_.Draw( g, (int)xPos.X, (int)yPos.Y );
if (marker_.DropLine)
{
PointD yMin = new PointD( data_[i].X, Math.Max( 0.0f, yAxis.Axis.WorldMin ) );
PointF yStart = yAxis.WorldToPhysical( yMin.Y, false );
g.DrawLine( marker_.Pen, new Point((int)xPos.X,(int)yStart.Y), new Point((int)xPos.X,(int)yPos.Y) );
}
}
}
}
/// <summary>
/// Returns an x-axis that is suitable for drawing this plot.
/// </summary>
/// <returns>A suitable x-axis.</returns>
public Axis SuggestXAxis()
{
SequenceAdapter data_ =
new SequenceAdapter( this.DataSource, this.DataMember, this.OrdinateData, this.AbscissaData );
return data_.SuggestXAxis();
}
/// <summary>
/// Returns a y-axis that is suitable for drawing this plot.
/// </summary>
/// <returns>A suitable y-axis.</returns>
public Axis SuggestYAxis()
{
SequenceAdapter data_ =
new SequenceAdapter( this.DataSource, this.DataMember, this.OrdinateData, this.AbscissaData );
return data_.SuggestYAxis();
}
/// <summary>
/// Draws a representation of this plot in the legend.
/// </summary>
/// <param name="g">The graphics surface on which to draw.</param>
/// <param name="startEnd">A rectangle specifying the bounds of the area in the legend set aside for drawing.</param>
public void DrawInLegend( Graphics g, Rectangle startEnd )
{
if (marker_.Size > 0)
{
marker_.Draw(g, (startEnd.Left + startEnd.Right) / 2, (startEnd.Top + startEnd.Bottom) / 2);
}
else if (marker_.Pen.Width > 0)
{
g.DrawLine(marker_.Pen,
(startEnd.Left + startEnd.Right) / 2, (startEnd.Top + startEnd.Bottom - marker_.Pen.Width) / 2,
(startEnd.Left + startEnd.Right) / 2, (startEnd.Top + startEnd.Bottom + marker_.Pen.Width) / 2);
}
}
/// <summary>
/// The Marker object used for the plot.
/// </summary>
public Marker Marker
{
set
{
marker_ = value;
}
get
{
return marker_;
}
}
}
}

65
lib/PointPlot3D.cs Normal file
Просмотреть файл

@ -0,0 +1,65 @@
// ******** experimental ********
/*
using System;
using System.Drawing;
namespace NPlot
{
/// <summary>
/// Think we should just implement point plot first, unless you need
/// other stuff.
/// </summary>
public class PointPlot3D : BasePlot3D, IPlot3D
{
/// <summary>
/// Constructor
/// </summary>
public PointPlot3D()
{
}
/// <summary>
/// Draws the points on the supplied axes. TODO.
/// </summary>
/// <param name="g"></param>
/// <param name="xAxis"></param>
/// <param name="yAxis"></param>
/// <param name="zAxis"></param>
void Draw( Graphics g, PhysicalAxis xAxis, PhysicalAxis yAxis, PhysicalAxis zAxis )
{
}
/// <summary>
/// The method used to set the default x axis.
/// </summary>
public Axis SuggestXAxis()
{
return null;
}
/// <summary>
/// The method used to set the default y axis.
/// </summary>
public Axis SuggestYAxis()
{
return null;
}
/// <summary>
/// The method used to set the default z axis.
/// </summary>
public Axis SuggestZAxis()
{
return null;
}
}
}
*/

1953
lib/RectangleBrushes.cs Normal file

Разница между файлами не показана из-за своего большого размера Загрузить разницу

143
lib/RectangleD.cs Normal file
Просмотреть файл

@ -0,0 +1,143 @@
/*
NPlot - A charting library for .NET
RectangleD.cs
Copyright (C) 2005
Matt Howlett
Redistribution and use of NPlot or parts there-of in source and
binary forms, with or without modification, are permitted provided
that the following conditions are met:
1. Re-distributions in source form must retain at the head of each
source file the above copyright notice, this list of conditions
and the following disclaimer.
2. Any product ("the product") that makes use NPlot or parts
there-of must either:
(a) allow any user of the product to obtain a complete machine-
readable copy of the corresponding source code for the
product and the version of NPlot used for a charge no more
than your cost of physically performing source distribution,
on a medium customarily used for software interchange, or:
(b) reproduce the following text in the documentation, about
box or other materials intended to be read by human users
of the product that is provided to every human user of the
product:
"This product includes software developed as
part of the NPlot library project available
from: http://www.nplot.com/"
The words "This product" may optionally be replace with
the actual name of the product.
------------------------------------------------------------------------
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
using System;
using System.Drawing;
namespace NPlot
{
/// <summary>
/// Stores a set of four double numbers that represent the location and size of
/// a rectangle. TODO: implement more functionality similar to Drawing.RectangleF.
/// </summary>
public struct RectangleD
{
/// <summary>
/// Constructor
/// </summary>
public RectangleD( double x, double y, double width, double height )
{
x_ = x;
y_ = y;
width_ = width;
height_ = height;
}
/// <summary>
/// The rectangle height.
/// </summary>
public double Height
{
get
{
return height_;
}
set
{
height_ = value;
}
}
/// <summary>
/// The rectangle width.
/// </summary>
public double Width
{
get
{
return width_;
}
set
{
width_ = value;
}
}
/// <summary>
/// The minimum x coordinate of the rectangle.
/// </summary>
public double X
{
get
{
return x_;
}
set
{
x_ = value;
}
}
/// <summary>
/// The minimum y coordinate of the rectangle.
/// </summary>
public double Y
{
get
{
return y_;
}
set
{
y_ = value;
}
}
private double x_;
private double y_;
private double width_;
private double height_;
}
}

330
lib/SequenceAdapter.cs Normal file
Просмотреть файл

@ -0,0 +1,330 @@
/*
NPlot - A charting library for .NET
SequenceAdapter.cs
Copyright (C) 2003-2004
Matt Howlett
Redistribution and use of NPlot or parts there-of in source and
binary forms, with or without modification, are permitted provided
that the following conditions are met:
1. Re-distributions in source form must retain at the head of each
source file the above copyright notice, this list of conditions
and the following disclaimer.
2. Any product ("the product") that makes use NPlot or parts
there-of must either:
(a) allow any user of the product to obtain a complete machine-
readable copy of the corresponding source code for the
product and the version of NPlot used for a charge no more
than your cost of physically performing source distribution,
on a medium customarily used for software interchange, or:
(b) reproduce the following text in the documentation, about
box or other materials intended to be read by human users
of the product that is provided to every human user of the
product:
"This product includes software developed as
part of the NPlot library project available
from: http://www.nplot.com/"
The words "This product" may optionally be replace with
the actual name of the product.
------------------------------------------------------------------------
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
using System;
using System.Collections;
using System.Data;
namespace NPlot
{
/// <summary>
/// This class is responsible for interpreting the various ways you can
/// specify data to plot objects using the DataSource, DataMember, ordinateData
/// and AbscissaData properties. It is a bridge that provides access to this
/// data via a single interface.
/// </summary>
public class SequenceAdapter
{
private AdapterUtils.IAxisSuggester XAxisSuggester_;
private AdapterUtils.IAxisSuggester YAxisSuggester_;
private AdapterUtils.ICounter counter_;
private AdapterUtils.IDataGetter xDataGetter_;
private AdapterUtils.IDataGetter yDataGetter_;
/// <summary>
/// Constructor. The data source specifiers must be specified here.
/// </summary>
/// <param name="dataSource">The source containing a list of values to plot.</param>
/// <param name="dataMember">The specific data member in a multimember data source to get data from.</param>
/// <param name="ordinateData">The source containing a list of values to plot on the ordinate axis, or a the name of the column to use for this data.</param>
/// <param name="abscissaData">The source containing a list of values to plot on the abscissa axis, or a the name of the column to use for this data.</param>
public SequenceAdapter( object dataSource, string dataMember, object ordinateData, object abscissaData )
{
if (dataSource == null && dataMember == null)
{
if (ordinateData is IList)
{
this.YAxisSuggester_ = new AdapterUtils.AxisSuggester_IList((IList)ordinateData);
if (ordinateData is Double[])
this.yDataGetter_ = new AdapterUtils.DataGetter_DoublesArray((Double[])ordinateData);
else
this.yDataGetter_ = new AdapterUtils.DataGetter_IList((IList)ordinateData);
this.counter_ = new AdapterUtils.Counter_IList((IList)ordinateData);
if (abscissaData is IList)
{
this.XAxisSuggester_ = new AdapterUtils.AxisSuggester_IList((IList)abscissaData);
if (abscissaData is Double[])
this.xDataGetter_ = new AdapterUtils.DataGetter_DoublesArray((Double[])abscissaData);
else
this.xDataGetter_ = new AdapterUtils.DataGetter_IList((IList)abscissaData);
return;
}
else if (abscissaData is StartStep)
{
this.XAxisSuggester_ = new AdapterUtils.AxisSuggester_StartStep((StartStep)abscissaData, (IList)ordinateData);
this.xDataGetter_ = new AdapterUtils.DataGetter_StartStep((StartStep)abscissaData);
return;
}
else if (abscissaData == null)
{
this.XAxisSuggester_ = new AdapterUtils.AxisSuggester_Auto((IList)ordinateData);
this.xDataGetter_ = new AdapterUtils.DataGetter_Count();
return;
}
}
else if (ordinateData == null)
{
if (abscissaData == null)
{
this.XAxisSuggester_ = new AdapterUtils.AxisSuggester_Null();
this.YAxisSuggester_ = new AdapterUtils.AxisSuggester_Null();
this.counter_ = new AdapterUtils.Counter_Null();
this.xDataGetter_ = new AdapterUtils.DataGetter_Null();
this.yDataGetter_ = new AdapterUtils.DataGetter_Null();
return;
}
else if (abscissaData is IList)
{
this.XAxisSuggester_ = new AdapterUtils.AxisSuggester_IList((IList)abscissaData);
this.YAxisSuggester_ = new AdapterUtils.AxisSuggester_Auto((IList)abscissaData);
this.counter_ = new AdapterUtils.Counter_IList((IList)abscissaData);
if (abscissaData is Double[])
this.xDataGetter_ = new AdapterUtils.DataGetter_DoublesArray((Double[])abscissaData);
else
this.xDataGetter_ = new AdapterUtils.DataGetter_IList((IList)abscissaData);
this.yDataGetter_ = new AdapterUtils.DataGetter_Count();
return;
}
else
{
// unknown.
}
}
else
{
// unknown
}
}
else if (dataSource is IList && dataMember == null)
{
if (dataSource is DataView)
{
DataView data = (DataView)dataSource;
this.counter_ = new AdapterUtils.Counter_DataView(data);
this.xDataGetter_ = new AdapterUtils.DataGetter_DataView(data, (string)abscissaData);
this.yDataGetter_ = new AdapterUtils.DataGetter_DataView(data, (string)ordinateData);
this.XAxisSuggester_ = new AdapterUtils.AxisSuggester_DataView(data, (string)abscissaData);
this.YAxisSuggester_ = new AdapterUtils.AxisSuggester_DataView(data, (string)ordinateData);
return;
}
else
{
this.YAxisSuggester_ = new AdapterUtils.AxisSuggester_IList((IList)dataSource);
this.counter_ = new AdapterUtils.Counter_IList((IList)dataSource);
this.yDataGetter_ = new AdapterUtils.DataGetter_IList((IList)dataSource);
if ((ordinateData == null) && (abscissaData == null))
{
this.XAxisSuggester_ = new AdapterUtils.AxisSuggester_Auto((IList)dataSource);
this.xDataGetter_ = new AdapterUtils.DataGetter_Count();
return;
}
else if ((ordinateData == null) && (abscissaData is StartStep))
{
this.XAxisSuggester_ = new AdapterUtils.AxisSuggester_StartStep((StartStep)abscissaData, (IList)ordinateData);
this.xDataGetter_ = new AdapterUtils.DataGetter_StartStep((StartStep)abscissaData);
return;
}
else if ((ordinateData == null) && (abscissaData is IList))
{
this.XAxisSuggester_ = new AdapterUtils.AxisSuggester_IList((IList)abscissaData);
this.xDataGetter_ = new AdapterUtils.DataGetter_IList((IList)abscissaData);
return;
}
else
{
// unknown.
}
}
}
else if ( ((dataSource is DataTable) && (dataMember == null)) || (dataSource is DataSet) )
{
DataRowCollection rows = null;
if (dataSource is DataSet)
{
if (dataMember != null)
{
rows = ((DataTable)((DataSet)dataSource).Tables[dataMember]).Rows;
}
else
{
rows = ((DataTable)((DataSet)dataSource).Tables[0]).Rows;
}
}
else
{
rows = ((DataTable)dataSource).Rows;
}
this.yDataGetter_ = new AdapterUtils.DataGetter_Rows(rows, (string)ordinateData);
this.YAxisSuggester_ = new AdapterUtils.AxisSuggester_Rows(rows, (string)ordinateData);
this.counter_ = new AdapterUtils.Counter_Rows(rows);
if ((abscissaData is string) && (ordinateData is string))
{
this.XAxisSuggester_ = new AdapterUtils.AxisSuggester_Rows(rows, (string)abscissaData);
this.xDataGetter_ = new AdapterUtils.DataGetter_Rows(rows, (string)abscissaData);
return;
}
else if ((abscissaData == null) && (ordinateData is string))
{
this.XAxisSuggester_ = new AdapterUtils.AxisSuggester_RowAuto(rows);
this.xDataGetter_ = new AdapterUtils.DataGetter_Count();
return;
}
else
{
// unknown.
}
}
else
{
// unknown.
}
throw new NPlotException( "Do not know how to interpret data provided to chart." );
}
/// <summary>
/// Returns the number of points.
/// </summary>
public int Count
{
get
{
return counter_.Count;
}
}
/// <summary>
/// Returns the ith point.
/// </summary>
public PointD this[int i]
{
get
{
return new PointD( this.xDataGetter_.Get(i), this.yDataGetter_.Get(i) );
}
}
/// <summary>
/// Returns an x-axis that is suitable for drawing the data.
/// </summary>
/// <returns>A suitable x-axis.</returns>
public Axis SuggestXAxis()
{
return this.XAxisSuggester_.Get();
}
/// <summary>
/// Returns a y-axis that is suitable for drawing the data.
/// </summary>
/// <returns>A suitable y-axis.</returns>
public Axis SuggestYAxis()
{
Axis a = this.YAxisSuggester_.Get();
// TODO make 0.08 a parameter.
a.IncreaseRange( 0.08 );
return a;
}
/// <summary>
/// Writes data out as text.
/// </summary>
/// <param name="sb">StringBuilder to write to.</param>
/// <param name="region">Only write out data in this region if onlyInRegion is true.</param>
/// <param name="onlyInRegion">If true, only data in region is written, else all data is written.</param>
public void WriteData( System.Text.StringBuilder sb, RectangleD region, bool onlyInRegion )
{
for (int i=0; i<this.Count; ++i)
{
if ( !(onlyInRegion &&
(this[i].X >= region.X && this[i].X <= region.X+region.Width) &&
(this[i].Y >= region.Y && this[i].Y <= region.Y+region.Height)) )
continue;
sb.Append( this[i].ToString() );
sb.Append( "\r\n" );
}
}
}
}

28
lib/SequenceAdapter3D.cs Normal file
Просмотреть файл

@ -0,0 +1,28 @@
// ******** experimental ********
/*
using System;
namespace NPlot
{
/// <summary>
/// This class will be analogous to SequenceAdapter for 2D charting.
/// Don't use it initially - offer only one method of getting in data
/// for similicity.
/// TODO. Not implemented.
/// </summary>
public class SequenceAdapter3D
{
/// <summary>
/// Constructor. TODO.
/// </summary>
public SequenceAdapter3D()
{
}
}
}
*/

111
lib/StartStep.cs Normal file
Просмотреть файл

@ -0,0 +1,111 @@
/*
NPlot - A charting library for .NET
StartStep.cs
Copyright (C) 2004
Matt Howlett
Redistribution and use of NPlot or parts there-of in source and
binary forms, with or without modification, are permitted provided
that the following conditions are met:
1. Re-distributions in source form must retain at the head of each
source file the above copyright notice, this list of conditions
and the following disclaimer.
2. Any product ("the product") that makes use NPlot or parts
there-of must either:
(a) allow any user of the product to obtain a complete machine-
readable copy of the corresponding source code for the
product and the version of NPlot used for a charge no more
than your cost of physically performing source distribution,
on a medium customarily used for software interchange, or:
(b) reproduce the following text in the documentation, about
box or other materials intended to be read by human users
of the product that is provided to every human user of the
product:
"This product includes software developed as
part of the NPlot library project available
from: http://www.nplot.com/"
The words "This product" may optionally be replace with
the actual name of the product.
------------------------------------------------------------------------
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
using System;
namespace NPlot
{
/// <summary>
/// Encapsulates a Start and Step value. This is useful for specifying a regularly spaced set of
/// abscissa values.
/// </summary>
public class StartStep
{
private double start_;
private double step_;
/// <summary>
/// Constructor
/// </summary>
/// <param name="start">the first value of the set of points specified by this object.</param>
/// <param name="step">the step that specifies the separation between successive points.</param>
public StartStep( double start, double step )
{
this.Start = start;
this.Step = step;
}
/// <summary>
/// The first value of the set of points specified by this object.
/// </summary>
public double Start
{
get
{
return start_;
}
set
{
this.start_ = value;
}
}
/// <summary>
/// The step that specifies the separation between successive points.
/// </summary>
public double Step
{
get
{
return this.step_;
}
set
{
this.step_ = value;
}
}
}
}

149
lib/StepGradient.cs Normal file
Просмотреть файл

@ -0,0 +1,149 @@
/*
NPlot - A charting library for .NET
StepGradient.cs
Copyright (C) 2004
Matt Howlett
Redistribution and use of NPlot or parts there-of in source and
binary forms, with or without modification, are permitted provided
that the following conditions are met:
1. Re-distributions in source form must retain at the head of each
source file the above copyright notice, this list of conditions
and the following disclaimer.
2. Any product ("the product") that makes use NPlot or parts
there-of must either:
(a) allow any user of the product to obtain a complete machine-
readable copy of the corresponding source code for the
product and the version of NPlot used for a charge no more
than your cost of physically performing source distribution,
on a medium customarily used for software interchange, or:
(b) reproduce the following text in the documentation, about
box or other materials intended to be read by human users
of the product that is provided to every human user of the
product:
"This product includes software developed as
part of the NPlot library project available
from: http://www.nplot.com/"
The words "This product" may optionally be replace with
the actual name of the product.
------------------------------------------------------------------------
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
using System;
using System.Drawing;
namespace NPlot
{
/// <summary>
/// Class for creating a rainbow legend.
/// </summary>
public class StepGradient : IGradient
{
/// <summary>
/// Types of step gradient defined.
/// </summary>
public enum Type
{
/// <summary>
/// Rainbow gradient type (colors of the rainbow)
/// </summary>
Rainbow,
/// <summary>
/// RGB gradient type (red, green blud).
/// </summary>
RGB
}
/// <summary>
/// Sets the type of step gradient.
/// </summary>
public Type StepType
{
get
{
return stepType_;
}
set
{
stepType_ = value;
}
}
Type stepType_ = Type.RGB;
/// <summary>
/// Default Constructor
/// </summary>
public StepGradient()
{
}
/// <summary>
/// Constructor
/// </summary>
/// <param name="stepType">type of gradient</param>
public StepGradient( Type stepType )
{
stepType_ = stepType;
}
/// <summary>
/// Gets a color corresponding to a number between 0.0 and 1.0 inclusive. The color will
/// be a linear interpolation of the min and max colors.
/// </summary>
/// <param name="prop">the number to get corresponding color for (between 0.0 and 1.0)</param>
/// <returns>The color corresponding to the supplied number.</returns>
public Color GetColor( double prop )
{
switch (stepType_)
{
case Type.RGB:
{
if (prop < 1.0/3.0) return Color.Red;
if (prop < 2.0/3.0) return Color.Green;
return Color.Blue;
}
case Type.Rainbow:
{
if (prop < 0.125) return Color.Red;
if (prop < 0.25) return Color.Orange;
if (prop < 0.375) return Color.Yellow;
if (prop < 0.5) return Color.Green;
if (prop < 0.625) return Color.Cyan;
if (prop < 0.75) return Color.Blue;
if (prop < 0.825) return Color.Purple;
return Color.Pink;
}
default:
{
return Color.Black;
}
}
}
}
}

347
lib/StepPlot.cs Normal file
Просмотреть файл

@ -0,0 +1,347 @@
/*
NPlot - A charting library for .NET
StepPlot.cs
Copyright (C) 2003
Matt Howlett
Redistribution and use of NPlot or parts there-of in source and
binary forms, with or without modification, are permitted provided
that the following conditions are met:
1. Re-distributions in source form must retain at the head of each
source file the above copyright notice, this list of conditions
and the following disclaimer.
2. Any product ("the product") that makes use NPlot or parts
there-of must either:
(a) allow any user of the product to obtain a complete machine-
readable copy of the corresponding source code for the
product and the version of NPlot used for a charge no more
than your cost of physically performing source distribution,
on a medium customarily used for software interchange, or:
(b) reproduce the following text in the documentation, about
box or other materials intended to be read by human users
of the product that is provided to every human user of the
product:
"This product includes software developed as
part of the NPlot library project available
from: http://www.nplot.com/"
The words "This product" may optionally be replace with
the actual name of the product.
------------------------------------------------------------------------
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
using System;
using System.Drawing;
namespace NPlot
{
/// <summary>
/// Encapsulates functionality for plotting data as a stepped line.
/// </summary>
public class StepPlot : BaseSequencePlot, IPlot, ISequencePlot
{
/// <summary>
/// Constructor.
/// </summary>
public StepPlot()
{
this.Center = false;
}
/// <summary>
/// Draws the step plot on a GDI+ surface against the provided x and y axes.
/// </summary>
/// <param name="g">The GDI+ surface on which to draw.</param>
/// <param name="xAxis">The X-Axis to draw against.</param>
/// <param name="yAxis">The Y-Axis to draw against.</param>
public virtual void Draw( Graphics g, PhysicalAxis xAxis, PhysicalAxis yAxis )
{
SequenceAdapter data =
new SequenceAdapter( this.DataSource, this.DataMember, this.OrdinateData, this.AbscissaData );
double leftCutoff = xAxis.PhysicalToWorld(xAxis.PhysicalMin, false);
double rightCutoff = xAxis.PhysicalToWorld(xAxis.PhysicalMax, false);
for (int i=0; i<data.Count; ++i)
{
PointD p1 = data[i];
if (Double.IsNaN(p1.X) || Double.IsNaN(p1.Y))
{
continue;
}
PointD p2;
PointD p3;
if (i+1 != data.Count)
{
p2 = data[i+1];
if (Double.IsNaN(p2.X) || Double.IsNaN(p2.Y))
{
continue;
}
p2.Y = p1.Y;
p3 = data[i+1];
}
else
{
p2 = data[i-1];
double offset = p1.X - p2.X;
p2.X = p1.X + offset;
p2.Y = p1.Y;
p3 = p2;
}
if ( this.center_ )
{
double offset = ( p2.X - p1.X ) / 2.0f;
p1.X -= offset;
p2.X -= offset;
p3.X -= offset;
}
PointF xPos1 = xAxis.WorldToPhysical( p1.X, false );
PointF yPos1 = yAxis.WorldToPhysical( p1.Y, false );
PointF xPos2 = xAxis.WorldToPhysical( p2.X, false );
PointF yPos2 = yAxis.WorldToPhysical( p2.Y, false );
PointF xPos3 = xAxis.WorldToPhysical( p3.X, false );
PointF yPos3 = yAxis.WorldToPhysical( p3.Y, false );
// do horizontal clipping here, to speed up
if ((p1.X < leftCutoff || p1.X > rightCutoff ) &&
(p2.X < leftCutoff || p2.X > rightCutoff ) &&
(p3.X < leftCutoff || p3.X > rightCutoff ) )
{
continue;
}
if (!this.hideHorizontalSegments_)
{
if (scale_ != 1.0f)
{
float middle = (xPos2.X + xPos1.X) / 2.0f;
float width = xPos2.X - xPos1.X;
width *= this.scale_;
g.DrawLine( Pen, (int)(middle-width/2.0f), yPos1.Y, (int)(middle+width/2.0f), yPos2.Y );
}
else
{
g.DrawLine( Pen, xPos1.X, yPos1.Y, xPos2.X, yPos2.Y );
}
}
if (!this.hideVerticalSegments_)
{
g.DrawLine( Pen, xPos2.X, yPos2.Y, xPos3.X, yPos3.Y );
}
}
}
/// <summary>
/// Returns an X-axis suitable for use by this plot. The axis will be one that is just long
/// enough to show all data.
/// </summary>
/// <returns>X-axis suitable for use by this plot.</returns>
public Axis SuggestXAxis()
{
SequenceAdapter data =
new SequenceAdapter( this.DataSource, this.DataMember, this.OrdinateData, this.AbscissaData );
if (data.Count < 2)
{
return data.SuggestXAxis();
}
// else
Axis a = data.SuggestXAxis();
PointD p1 = data[0];
PointD p2 = data[1];
PointD p3 = data[data.Count-2];
PointD p4 = data[data.Count-1];
double offset1;
double offset2;
if (!center_)
{
offset1 = 0.0f;
offset2 = p4.X - p3.X;
}
else
{
offset1 = (p2.X - p1.X)/2.0f;
offset2 = (p4.X - p3.X)/2.0f;
}
a.WorldMin -= offset1;
a.WorldMax += offset2;
return a;
}
/// <summary>
/// Returns an Y-axis suitable for use by this plot. The axis will be one that is just long
/// enough to show all data.
/// </summary>
/// <returns>Y-axis suitable for use by this plot.</returns>
public Axis SuggestYAxis()
{
SequenceAdapter data =
new SequenceAdapter( this.DataSource, this.DataMember, this.OrdinateData, this.AbscissaData );
return data.SuggestYAxis();
}
/// <summary>
/// Gets or sets whether or not steps should be centered. If true, steps will be centered on the
/// X abscissa values. If false, the step corresponding to a given x-value will be drawn between
/// this x-value and the next x-value at the current y-height.
/// </summary>
public bool Center
{
set
{
center_ = value;
}
get
{
return center_;
}
}
private bool center_;
/// <summary>
/// Draws a representation of this plot in the legend.
/// </summary>
/// <param name="g">The graphics surface on which to draw.</param>
/// <param name="startEnd">A rectangle specifying the bounds of the area in the legend set aside for drawing.</param>
public virtual void DrawInLegend(Graphics g, Rectangle startEnd)
{
g.DrawLine(pen_, startEnd.Left, (startEnd.Top + startEnd.Bottom) / 2,
startEnd.Right, (startEnd.Top + startEnd.Bottom) / 2);
}
/// <summary>
/// The pen used to draw the plot
/// </summary>
public System.Drawing.Pen Pen
{
get
{
return pen_;
}
set
{
pen_ = value;
}
}
private System.Drawing.Pen pen_ = new Pen(Color.Black);
/// <summary>
/// The color of the pen used to draw lines in this plot.
/// </summary>
public System.Drawing.Color Color
{
set
{
if (pen_ != null)
{
pen_.Color = value;
}
else
{
pen_ = new Pen(value);
}
}
get
{
return pen_.Color;
}
}
/// <summary>
/// If true, then vertical lines are hidden.
/// </summary>
public bool HideVerticalSegments
{
get
{
return hideVerticalSegments_;
}
set
{
hideVerticalSegments_ = value;
}
}
bool hideVerticalSegments_ = false;
/// <summary>
/// If true, then vertical lines are hidden.
/// </summary>
public bool HideHorizontalSegments
{
get
{
return hideHorizontalSegments_;
}
set
{
hideHorizontalSegments_ = value;
}
}
bool hideHorizontalSegments_ = false;
/// <summary>
/// The horizontal line length is multiplied by this amount. Default
/// corresponds to a value of 1.0.
/// </summary>
public float WidthScale
{
get
{
return scale_;
}
set
{
scale_ = value;
}
}
private float scale_ = 1.0f;
}
}

Двоичные данные
lib/StrongName.snk Normal file

Двоичный файл не отображается.

178
lib/TextItem.cs Normal file
Просмотреть файл

@ -0,0 +1,178 @@
/*
NPlot - A charting library for .NET
TextItem.cs
Copyright (C) 2003
Matt Howlett
Redistribution and use of NPlot or parts there-of in source and
binary forms, with or without modification, are permitted provided
that the following conditions are met:
1. Re-distributions in source form must retain at the head of each
source file the above copyright notice, this list of conditions
and the following disclaimer.
2. Any product ("the product") that makes use NPlot or parts
there-of must either:
(a) allow any user of the product to obtain a complete machine-
readable copy of the corresponding source code for the
product and the version of NPlot used for a charge no more
than your cost of physically performing source distribution,
on a medium customarily used for software interchange, or:
(b) reproduce the following text in the documentation, about
box or other materials intended to be read by human users
of the product that is provided to every human user of the
product:
"This product includes software developed as
part of the NPlot library project available
from: http://www.nplot.com/"
The words "This product" may optionally be replace with
the actual name of the product.
------------------------------------------------------------------------
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
using System;
using System.Drawing;
namespace NPlot
{
/// <summary>
/// This class implements drawing text against two physical axes.
/// </summary>
public class TextItem : IDrawable
{
private void Init()
{
FontFamily fontFamily = new FontFamily("Arial");
font_ = new Font(fontFamily, 10, FontStyle.Regular, GraphicsUnit.Pixel);
}
/// <summary>
/// Constructor
/// </summary>
/// <param name="position">The position the text starts.</param>
/// <param name="text">The text.</param>
public TextItem( PointD position, string text )
{
start_ = position;
text_ = text;
Init();
}
/// <summary>
/// Text associated.
/// </summary>
public string Text
{
get
{
return text_;
}
set
{
text_ = value;
}
}
private string text_ = "";
/// <summary>
/// The starting point for the text.
/// </summary>
public PointD Start
{
get
{
return start_;
}
set
{
start_ = value;
}
}
private PointD start_;
/// <summary>
/// Draws the text on a plot surface.
/// </summary>
/// <param name="g">graphics surface on which to draw</param>
/// <param name="xAxis">The X-Axis to draw against.</param>
/// <param name="yAxis">The Y-Axis to draw against.</param>
public void Draw( System.Drawing.Graphics g, PhysicalAxis xAxis, PhysicalAxis yAxis )
{
Point startPoint = new Point(
(int)xAxis.WorldToPhysical( start_.X, true ).X,
(int)yAxis.WorldToPhysical( start_.Y, true ).Y );
g.DrawString(text_, font_, textBrush_,(int)startPoint.X,(int)startPoint.Y);
}
/// <summary>
/// The brush used to draw the text.
/// </summary>
public Brush TextBrush
{
get
{
return textBrush_;
}
set
{
textBrush_ = value;
}
}
/// <summary>
/// Set the text to be drawn with a solid brush of this color.
/// </summary>
public Color TextColor
{
set
{
textBrush_ = new SolidBrush( value );
}
}
/// <summary>
/// The font used to draw the text associated with the arrow.
/// </summary>
public Font TextFont
{
get
{
return this.font_;
}
set
{
this.font_ = value;
}
}
private Brush textBrush_ = new SolidBrush( Color.Black );
private Pen pen_ = new Pen( Color.Black );
private Font font_;
}
}

713
lib/TradingDateTimeAxis.cs Normal file
Просмотреть файл

@ -0,0 +1,713 @@
/*
NPlot - A charting library for .NET
TradingDateTimeAxis.cs
Copyright (C) 2006
Pawel Konieczny
Redistribution and use of NPlot or parts there-of in source and
binary forms, with or without modification, are permitted provided
that the following conditions are met:
1. Re-distributions in source form must retain at the head of each
source file the above copyright notice, this list of conditions
and the following disclaimer.
2. Any product ("the product") that makes use NPlot or parts
there-of must either:
(a) allow any user of the product to obtain a complete machine-
readable copy of the corresponding source code for the
product and the version of NPlot used for a charge no more
than your cost of physically performing source distribution,
on a medium customarily used for software interchange, or:
(b) reproduce the following text in the documentation, about
box or other materials intended to be read by human users
of the product that is provided to every human user of the
product:
"This product includes software developed as
part of the NPlot library project available
from: http://www.nplot.com/"
The words "This product" may optionally be replace with
the actual name of the product.
------------------------------------------------------------------------
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
using System;
using System.Drawing;
using System.Collections;
namespace NPlot
{
/// <summary>
/// Provides a DateTime axis that removes non-trading days.
/// </summary>
public class TradingDateTimeAxis : DateTimeAxis
{
// we keep shadow "virtual" copies of WorldMin/Max for speed
// which are already remapped, so it is essential that changes
// to WorldMin/Max are captured here
/// <summary>
/// The axis world min value.
/// </summary>
public override double WorldMin
{
get
{
return base.WorldMin;
}
set
{
base.WorldMin = value;
virtualWorldMin_ = SparseWorldRemap(value);
}
}
private double virtualWorldMin_ = double.NaN;
/// <summary>
/// The axis world max value.
/// </summary>
public override double WorldMax
{
get
{
return base.WorldMax;
}
set
{
base.WorldMax = value;
virtualWorldMax_ = SparseWorldRemap(value);
}
}
private double virtualWorldMax_ = double.NaN;
/// <summary>
/// Optional time at which trading begins.
/// All data points earlied than that (same day) will be collapsed.
/// </summary>
public virtual TimeSpan StartTradingTime
{
get
{
return new TimeSpan(startTradingTime_);
}
set
{
startTradingTime_ = value.Ticks;
tradingTimeSpan_ = endTradingTime_ - startTradingTime_;
}
}
private long startTradingTime_;
/// <summary>
/// Optional time at which trading ends.
/// All data points later than that (same day) will be collapsed.
/// </summary>
public virtual TimeSpan EndTradingTime
{
get
{
return new TimeSpan(endTradingTime_);
}
set
{
endTradingTime_ = value.Ticks;
tradingTimeSpan_ = endTradingTime_ - startTradingTime_;
}
}
private long endTradingTime_;
private long tradingTimeSpan_;
/// <summary>
/// Get whether or not this axis is linear.
/// </summary>
public override bool IsLinear
{
get
{
return false;
}
}
/// <summary>
/// Constructor
/// </summary>
public TradingDateTimeAxis() : base()
{
Init();
}
/// <summary>
/// Copy Constructor
/// </summary>
/// <param name="a">construct a TradingDateTimeAxis based on this provided axis.</param>
public TradingDateTimeAxis(Axis a) : base(a)
{
Init();
if (a is TradingDateTimeAxis)
DoClone((TradingDateTimeAxis)a, this);
else if (a is DateTimeAxis)
DoClone((DateTimeAxis)a, this);
else
{
DoClone(a, this);
this.NumberFormat = null;
}
}
/// <summary>
/// Helper function for constructors.
/// </summary>
private void Init()
{
startTradingTime_ = 0;
endTradingTime_ = TimeSpan.TicksPerDay;
tradingTimeSpan_ = endTradingTime_ - startTradingTime_;
virtualWorldMin_ = SparseWorldRemap(WorldMin);
virtualWorldMax_ = SparseWorldRemap(WorldMax);
}
/// <summary>
/// Deep copy of DateTimeAxis.
/// </summary>
/// <returns>A copy of the DateTimeAxis Class.</returns>
public override object Clone()
{
TradingDateTimeAxis a = new TradingDateTimeAxis();
// ensure that this isn't being called on a derived type. If it is, then oh no!
if (this.GetType() != a.GetType())
{
throw new NPlotException( "Clone not defined in derived type. Help!" );
}
DoClone( this, a );
return a;
}
/// <summary>
/// Helper method for Clone.
/// </summary>
/// <param name="a">The cloned target object.</param>
/// <param name="b">The cloned source object.</param>
protected static void DoClone(TradingDateTimeAxis b, TradingDateTimeAxis a)
{
DateTimeAxis.DoClone(b, a);
a.startTradingTime_ = b.startTradingTime_;
a.endTradingTime_ = b.endTradingTime_;
a.tradingTimeSpan_ = b.tradingTimeSpan_;
a.WorldMin = b.WorldMin;
a.WorldMax = b.WorldMax;
}
/// <summary>
/// World to physical coordinate transform.
/// </summary>
/// <param name="coord">The coordinate value to transform.</param>
/// <param name="physicalMin">The physical position corresponding to the world minimum of the axis.</param>
/// <param name="physicalMax">The physical position corresponding to the world maximum of the axis.</param>
/// <param name="clip">if false, then physical value may extend outside worldMin / worldMax. If true, the physical value returned will be clipped to physicalMin or physicalMax if it lies outside this range.</param>
/// <returns>The transformed coordinates.</returns>
/// <remarks>Not sure how much time is spent in this often called function. If it's lots, then
/// worth optimizing (there is scope to do so).</remarks>
public override PointF WorldToPhysical(
double coord,
PointF physicalMin,
PointF physicalMax,
bool clip)
{
// (1) account for reversed axis. Could be tricky and move
// this out, but would be a little messy.
PointF _physicalMin;
PointF _physicalMax;
if (this.Reversed)
{
_physicalMin = physicalMax;
_physicalMax = physicalMin;
}
else
{
_physicalMin = physicalMin;
_physicalMax = physicalMax;
}
// (2) if want clipped value, return extrema if outside range.
if (clip)
{
if (WorldMin < WorldMax)
{
if (coord > WorldMax)
{
return _physicalMax;
}
if (coord < WorldMin)
{
return _physicalMin;
}
}
else
{
if (coord < WorldMax)
{
return _physicalMax;
}
if (coord > WorldMin)
{
return _physicalMin;
}
}
}
// (3) we are inside range or don't want to clip.
coord = SparseWorldRemap(coord);
double range = virtualWorldMax_ - virtualWorldMin_;
double prop = (double)((coord - virtualWorldMin_) / range);
//double range = WorldMax - WorldMin;
//double prop = (double)((coord - WorldMin) / range);
//if (range1 != range)
// range1 = range;
// Force clipping at bounding box largeClip times that of real bounding box
// anyway. This is effectively at infinity.
const double largeClip = 100.0;
if (prop > largeClip && clip)
prop = largeClip;
if (prop < -largeClip && clip)
prop = -largeClip;
if (range == 0)
{
if (coord >= virtualWorldMin_)
prop = largeClip;
if (coord < virtualWorldMin_)
prop = -largeClip;
}
// calculate the physical coordinate.
PointF offset = new PointF(
(float)(prop * (_physicalMax.X - _physicalMin.X)),
(float)(prop * (_physicalMax.Y - _physicalMin.Y)));
return new PointF(_physicalMin.X + offset.X, _physicalMin.Y + offset.Y);
}
/// <summary>
/// Transforms a physical coordinate to an axis world
/// coordinate given the physical extremites of the axis.
/// </summary>
/// <param name="p">the point to convert</param>
/// <param name="physicalMin">the physical minimum extremity of the axis</param>
/// <param name="physicalMax">the physical maximum extremity of the axis</param>
/// <param name="clip">whether or not to clip the world value to lie in the range of the axis if it is outside.</param>
/// <returns></returns>
public override double PhysicalToWorld(
PointF p,
PointF physicalMin,
PointF physicalMax,
bool clip)
{
// (1) account for reversed axis. Could be tricky and move
// this out, but would be a little messy.
PointF _physicalMin;
PointF _physicalMax;
if (this.Reversed)
{
_physicalMin = physicalMax;
_physicalMax = physicalMin;
}
else
{
_physicalMin = physicalMin;
_physicalMax = physicalMax;
}
// normalised axis dir vector
float axis_X = _physicalMax.X - _physicalMin.X;
float axis_Y = _physicalMax.Y - _physicalMin.Y;
float len = (float)Math.Sqrt(axis_X * axis_X + axis_Y * axis_Y);
axis_X /= len;
axis_Y /= len;
// point relative to axis physical minimum.
PointF posRel = new PointF(p.X - _physicalMin.X, p.Y - _physicalMin.Y);
// dist of point projection on axis, normalised.
float prop = (axis_X * posRel.X + axis_Y * posRel.Y) / len;
//double world = prop * (WorldMax - WorldMin) + WorldMin;
double world = prop * (virtualWorldMax_ - virtualWorldMin_) + virtualWorldMin_;
world = ReverseSparseWorldRemap(world);
// if want clipped value, return extrema if outside range.
if (clip)
{
world = Math.Max(world, WorldMin);
world = Math.Min(world, WorldMax);
}
return world;
}
/// <summary>
/// Remap a world coordinate into a "virtual" world, where non-trading dates and times are collapsed.
/// </summary>
/// <remarks>
/// This code works under asumption that there are exactly 24*60*60 seconds in a day
/// This is strictly speaking not correct but apparently .NET 2.0 does not count leap seconds.
/// Luckilly, Ticks == 0 =~= 0001-01-01T00:00 =~= Monday
/// First tried a version fully on floating point arithmetic,
/// but failed hopelessly due to rounding errors.
/// </remarks>
/// <param name="coord">world coordinate to transform.</param>
/// <returns>equivalent virtual world coordinate.</returns>
protected double SparseWorldRemap(double coord)
{
long ticks = (long)coord;
long whole_days = ticks / TimeSpan.TicksPerDay;
long ticks_in_last_day = ticks % TimeSpan.TicksPerDay;
long full_weeks = whole_days / 7;
long days_in_last_week = whole_days % 7;
if (days_in_last_week >= 5)
{
days_in_last_week = 5;
ticks_in_last_day = 0;
}
if (ticks_in_last_day < startTradingTime_) ticks_in_last_day = startTradingTime_;
else if (ticks_in_last_day > endTradingTime_) ticks_in_last_day = endTradingTime_;
ticks_in_last_day -= startTradingTime_;
long whole_working_days = (full_weeks * 5 + days_in_last_week);
long working_ticks = whole_working_days * tradingTimeSpan_;
long new_ticks = working_ticks + ticks_in_last_day;
return (double)new_ticks;
}
/// <summary>
/// Remaps a "virtual" world coordinates back to true world coordinates.
/// </summary>
/// <param name="coord">virtual world coordinate to transform.</param>
/// <returns>equivalent world coordinate.</returns>
protected double ReverseSparseWorldRemap(double coord)
{
long ticks = (long)coord;
//ticks += startTradingTime_;
long ticks_in_last_day = ticks % tradingTimeSpan_;
ticks /= tradingTimeSpan_;
long full_weeks = ticks / 5;
long week_part = ticks % 5;
long day_ticks = (full_weeks * 7 + week_part) * TimeSpan.TicksPerDay;
return (double)(day_ticks + ticks_in_last_day + startTradingTime_);
}
/// <summary>
/// Adds a delta amount to the given world coordinate in such a way that
/// all "sparse gaps" are skipped. In other words, the returned value is
/// in delta distance from the given in the "virtual" world.
/// </summary>
/// <param name="coord">world coordinate to shift.</param>
/// <param name="delta">shif amount in "virtual" units.</param>
/// <returns></returns>
public double SparseWorldAdd(double coord, double delta)
{
return ReverseSparseWorldRemap(SparseWorldRemap(coord) + delta);
}
/// <summary>
/// World extent in virtual (sparse) units.
/// </summary>
public double SparseWorldLength
{
get
{
return SparseWorldRemap(WorldMax) - SparseWorldRemap(WorldMin);
}
}
/// <summary>
/// Check whether the given coordinate falls within defined trading hours.
/// </summary>
/// <param name="coord">world coordinate in ticks to check.</param>
/// <returns>true if in trading hours, false if in non-trading gap.</returns>
public bool WithinTradingHours(double coord)
{
long ticks = (long)coord;
long whole_days = ticks / TimeSpan.TicksPerDay;
long ticks_in_last_day = ticks % TimeSpan.TicksPerDay;
long days_in_last_week = whole_days % 7;
if (days_in_last_week >= 5)
return false;
if (ticks_in_last_day < startTradingTime_) return false;
if (ticks_in_last_day >= endTradingTime_) return false;
return true;
}
/// <summary>
/// Check whether the given coordinate falls on trading days.
/// </summary>
/// <param name="coord">world coordinate in ticks to check.</param>
/// <returns>true if on Mon - Fri.</returns>
public bool OnTradingDays(double coord)
{
long ticks = (long)coord;
long whole_days = ticks / TimeSpan.TicksPerDay;
long days_in_last_week = whole_days % 7;
return (days_in_last_week < 5);
}
/// <summary>
/// Determines the positions of all Large and Small ticks.
/// </summary>
/// <remarks>
/// The method WorldTickPositions_FirstPass() from the base works just fine, except that it
/// does not account for non-trading gaps in time, therefore, when less than two days are visible
/// an own algorithm is used (to show intraday time). Otherwise the base class implementation is used
/// but the output is corrected to remove ticks on non-trading days (Sat, Sun).
/// </remarks>
/// <param name="physicalMin">The physical position corresponding to the world minimum of the axis.</param>
/// <param name="physicalMax">The physical position corresponding to the world maximum of the axis.</param>
/// <param name="largeTickPositions">ArrayList containing the positions of the large ticks.</param>
/// <param name="smallTickPositions">null</param>
internal override void WorldTickPositions_FirstPass(
Point physicalMin,
Point physicalMax,
out ArrayList largeTickPositions,
out ArrayList smallTickPositions
)
{
if (LargeTickStep != TimeSpan.Zero || SparseWorldLength > 2.0 * (double)tradingTimeSpan_) // utilise base class
{
ArrayList largeTickPositions_FirstPass;
base.WorldTickPositions_FirstPass(physicalMin, physicalMax, out largeTickPositions_FirstPass, out smallTickPositions);
if (largeTickPositions_FirstPass.Count < 2)
{
// leave it alone, whatever that single tick may be (better something than nothing...)
largeTickPositions = largeTickPositions_FirstPass;
}
else if ((double)largeTickPositions_FirstPass[1] - (double)largeTickPositions_FirstPass[0] > 27.0 * (double)TimeSpan.TicksPerDay)
{
// For distances between ticks in months or longer, just accept all ticks
largeTickPositions = largeTickPositions_FirstPass;
}
else
{
// for daily ticks, ignore non-trading hours but obey (skip) non-trading days
largeTickPositions = new ArrayList();
foreach (object tick in largeTickPositions_FirstPass)
{
if (OnTradingDays((double)tick))
largeTickPositions.Add(tick);
}
}
}
else // intraday ticks, own algorithm
{
smallTickPositions = null;
largeTickPositions = new ArrayList();
TimeSpan timeLength = new TimeSpan((long)SparseWorldLength);
DateTime worldMinDate = new DateTime( (long)this.WorldMin );
DateTime worldMaxDate = new DateTime( (long)this.WorldMax );
DateTime currentTickDate;
long skip; // in time ticks
// The following if-else flow establishes currentTickDate to the beginning of series
// and skip to the optimal distance between ticks
// if less than 10 minutes, then large ticks on second spacings.
if ( timeLength < new TimeSpan(0,0,10,0,0) )
{
this.LargeTickLabelType_ = LargeTickLabelType.hourMinuteSeconds;
int secondsSkip;
if (timeLength < new TimeSpan( 0,0,0,10,0 ) )
secondsSkip = 1;
else if ( timeLength < new TimeSpan(0,0,0,20,0) )
secondsSkip = 2;
else if ( timeLength < new TimeSpan(0,0,0,50,0) )
secondsSkip = 5;
else if ( timeLength < new TimeSpan(0,0,2,30,0) )
secondsSkip = 15;
else
secondsSkip = 30;
int second = worldMinDate.Second;
second -= second % secondsSkip;
currentTickDate = new DateTime(
worldMinDate.Year,
worldMinDate.Month,
worldMinDate.Day,
worldMinDate.Hour,
worldMinDate.Minute,
second,0 );
skip = secondsSkip * TimeSpan.TicksPerSecond;
}
// Less than 2 hours, then large ticks on minute spacings.
else if ( timeLength < new TimeSpan(0,2,0,0,0) )
{
this.LargeTickLabelType_ = LargeTickLabelType.hourMinute;
int minuteSkip;
if ( timeLength < new TimeSpan(0,0,10,0,0) )
minuteSkip = 1;
else if ( timeLength < new TimeSpan(0,0,20,0,0) )
minuteSkip = 2;
else if ( timeLength < new TimeSpan(0,0,50,0,0) )
minuteSkip = 5;
else if ( timeLength < new TimeSpan(0,2,30,0,0) )
minuteSkip = 15;
else //( timeLength < new TimeSpan( 0,5,0,0,0) )
minuteSkip = 30;
int minute = worldMinDate.Minute;
minute -= minute % minuteSkip;
currentTickDate = new DateTime(
worldMinDate.Year,
worldMinDate.Month,
worldMinDate.Day,
worldMinDate.Hour,
minute,0,0 );
skip = minuteSkip * TimeSpan.TicksPerMinute;
}
// Else large ticks on hour spacings.
else
{
this.LargeTickLabelType_ = LargeTickLabelType.hourMinute;
int hourSkip;
if (timeLength < new TimeSpan(0, 10, 0, 0, 0))
hourSkip = 1;
else if (timeLength < new TimeSpan(0, 20, 0, 0, 0))
hourSkip = 2;
else
hourSkip = 6;
int hour = worldMinDate.Hour;
hour -= hour % hourSkip;
currentTickDate = new DateTime(
worldMinDate.Year,
worldMinDate.Month,
worldMinDate.Day,
hour, 0, 0, 0);
skip = hourSkip * TimeSpan.TicksPerHour;
}
// place ticks
while (currentTickDate < worldMaxDate)
{
double world = (double)currentTickDate.Ticks;
if (!WithinTradingHours(world))
{
// add gap boundary instead
world = ReverseSparseWorldRemap(SparseWorldRemap(world)); // moves forward
long gap = (long)world;
gap -= gap % skip;
currentTickDate = new DateTime(gap);
}
if (world >= this.WorldMin && world <= this.WorldMax)
{
largeTickPositions.Add(world);
}
currentTickDate = currentTickDate.AddTicks(skip);
}
}
}
/// <summary>
/// Get an appropriate label name, given the DateTime of a label
/// </summary>
/// <param name="tickDate">the DateTime to get the label name for</param>
/// <returns>A label name appropriate to the supplied DateTime.</returns>
protected override string LargeTickLabel(DateTime tickDate)
{
string label;
if ( this.NumberFormat == null
&& (LargeTickLabelType_ == LargeTickLabelType.hourMinute ||
LargeTickLabelType_ == LargeTickLabelType.hourMinuteSeconds)
&& tickDate.TimeOfDay == StartTradingTime)
{
// in such case always show the day date
label = (tickDate.Day).ToString();
label += " ";
label += tickDate.ToString("MMM");
}
else
{
label = base.LargeTickLabel(tickDate);
}
return label;
}
}
}

190
lib/Transform2D.cs Normal file
Просмотреть файл

@ -0,0 +1,190 @@
/*
NPlot - A charting library for .NET
Transform2D.cs
Copyright (C) 2003
Matt Howlett
Redistribution and use of NPlot or parts there-of in source and
binary forms, with or without modification, are permitted provided
that the following conditions are met:
1. Re-distributions in source form must retain at the head of each
source file the above copyright notice, this list of conditions
and the following disclaimer.
2. Any product ("the product") that makes use NPlot or parts
there-of must either:
(a) allow any user of the product to obtain a complete machine-
readable copy of the corresponding source code for the
product and the version of NPlot used for a charge no more
than your cost of physically performing source distribution,
on a medium customarily used for software interchange, or:
(b) reproduce the following text in the documentation, about
box or other materials intended to be read by human users
of the product that is provided to every human user of the
product:
"This product includes software developed as
part of the NPlot library project available
from: http://www.nplot.com/"
The words "This product" may optionally be replace with
the actual name of the product.
------------------------------------------------------------------------
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
using System;
using System.Drawing;
namespace NPlot
{
/// <summary>
/// Encapsulates functionality for transforming world to physical coordinates optimally.
/// </summary>
/// <remarks>The existence of the whole ITransform2D thing might need revising. Not convinced it's the best way.</remarks>
public class Transform2D
{
/// <summary>
/// Constructs the optimal ITransform2D object for the supplied x and y axes.
/// </summary>
/// <param name="xAxis">The xAxis to use for the world to physical transform.</param>
/// <param name="yAxis">The yAxis to use for the world to physical transform.</param>
/// <returns>An ITransform2D derived object for converting from world to physical coordinates.</returns>
public static ITransform2D GetTransformer( PhysicalAxis xAxis, PhysicalAxis yAxis )
{
ITransform2D ret = null;
// if (xAxis.Axis.IsLinear && yAxis.Axis.IsLinear && !xAxis.Axis.Reversed && !yAxis.Axis.Reversed)
// ret = new FastTransform2D( xAxis, yAxis );
// else
// ret = new DefaultTransform2D( xAxis, yAxis );
ret = new DefaultTransform2D( xAxis, yAxis );
return ret;
}
/// <summary>
/// This class does world -> physical transforms for the general case
/// </summary>
public class DefaultTransform2D : ITransform2D
{
private PhysicalAxis xAxis_;
private PhysicalAxis yAxis_;
/// <summary>
/// Constructor
/// </summary>
/// <param name="xAxis">The x-axis to use for transforms</param>
/// <param name="yAxis">The y-axis to use for transforms</param>
public DefaultTransform2D( PhysicalAxis xAxis, PhysicalAxis yAxis )
{
xAxis_ = xAxis;
yAxis_ = yAxis;
}
/// <summary>
/// Transforms the given world point to physical coordinates
/// </summary>
/// <param name="x">x coordinate of world point to transform.</param>
/// <param name="y">y coordinate of world point to transform.</param>
/// <returns>the corresponding physical point.</returns>
public PointF Transform( double x, double y )
{
return new PointF(
xAxis_.WorldToPhysical( x, false ).X,
yAxis_.WorldToPhysical( y, false ).Y );
}
/// <summary>
/// Transforms the given world point to physical coordinates
/// </summary>
/// <param name="worldPoint">the world point to transform</param>
/// <returns>the corresponding physical point</returns>
public PointF Transform( PointD worldPoint )
{
return new PointF(
xAxis_.WorldToPhysical( worldPoint.X, false ).X,
yAxis_.WorldToPhysical( worldPoint.Y, false ).Y );
}
}
/// <summary>
/// This class does highly efficient world->physical and physical->world transforms
/// for linear axes.
/// </summary>
public class FastTransform2D : ITransform2D
{
private PageAlignedPhysicalAxis xAxis_;
private PageAlignedPhysicalAxis yAxis_;
/// <summary>
/// Constructor
/// </summary>
/// <param name="xAxis">The x-axis to use for transforms</param>
/// <param name="yAxis">The y-axis to use for transforms</param>
public FastTransform2D( PhysicalAxis xAxis, PhysicalAxis yAxis )
{
xAxis_ = new PageAlignedPhysicalAxis( xAxis );
yAxis_ = new PageAlignedPhysicalAxis( yAxis );
}
/// <summary>
/// Transforms the given world point to physical coordinates
/// </summary>
/// <param name="x">x coordinate of world point to transform.</param>
/// <param name="y">y coordinate of world point to transform.</param>
/// <returns>the corresponding physical point.</returns>
public PointF Transform( double x, double y )
{
return new PointF(
xAxis_.WorldToPhysicalClipped( x ),
yAxis_.WorldToPhysicalClipped( y ) );
}
/// <summary>
/// Transforms the given world point to physical coordinates
/// </summary>
/// <param name="worldPoint">the world point to transform</param>
/// <returns>the corresponding physical point</returns>
public PointF Transform( PointD worldPoint )
{
return new PointF(
xAxis_.WorldToPhysical( worldPoint.X ),
yAxis_.WorldToPhysical( worldPoint.Y ) );
}
}
}
}

379
lib/Utils.cs Normal file
Просмотреть файл

@ -0,0 +1,379 @@
/*
NPlot - A charting library for .NET
Utils.cs
Copyright (C) 2003-2004
Matt Howlett
Redistribution and use of NPlot or parts there-of in source and
binary forms, with or without modification, are permitted provided
that the following conditions are met:
1. Re-distributions in source form must retain at the head of each
source file the above copyright notice, this list of conditions
and the following disclaimer.
2. Any product ("the product") that makes use NPlot or parts
there-of must either:
(a) allow any user of the product to obtain a complete machine-
readable copy of the corresponding source code for the
product and the version of NPlot used for a charge no more
than your cost of physically performing source distribution,
on a medium customarily used for software interchange, or:
(b) reproduce the following text in the documentation, about
box or other materials intended to be read by human users
of the product that is provided to every human user of the
product:
"This product includes software developed as
part of the NPlot library project available
from: http://www.nplot.com/"
The words "This product" may optionally be replace with
the actual name of the product.
------------------------------------------------------------------------
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
using System;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Data;
using System.Collections;
namespace NPlot
{
/// <summary>
/// General purpose utility functions used internally.
/// </summary>
internal class Utils
{
/// <summary>
/// Numbers less than this are considered insignificant. This number is
/// bigger than double.Epsilon.
/// </summary>
public const double Epsilon = double.Epsilon * 1000.0;
/// <summary>
/// Returns true if the absolute difference between parameters is less than Epsilon
/// </summary>
/// <param name="a">first number to compare</param>
/// <param name="b">second number to compare</param>
/// <returns>true if equal, false otherwise</returns>
public static bool DoubleEqual( double a, double b )
{
if ( System.Math.Abs(a-b) < Epsilon )
{
return true;
}
return false;
}
/// <summary>
/// Swaps the value of two doubles.
/// </summary>
/// <param name="a">first value to swap.</param>
/// <param name="b">second value to swap.</param>
public static void Swap( ref double a, ref double b )
{
double c = a;
a = b;
b = c;
}
/// <summary>
/// Calculate the distance between two points, a and b.
/// </summary>
/// <param name="a">First point</param>
/// <param name="b">Second point</param>
/// <returns>Distance between points a and b</returns>
public static float Distance( PointF a, PointF b )
{
return (float)System.Math.Sqrt( (a.X - b.X)*(a.X - b.X) + (a.Y - b.Y)*(a.Y - b.Y) );
}
/// <summary>
/// Calculate the distance between two points, a and b.
/// </summary>
/// <param name="a">First point</param>
/// <param name="b">Second point</param>
/// <returns>Distance between points a and b</returns>
public static int Distance( Point a, Point b )
{
return (int)System.Math.Sqrt( (a.X - b.X)*(a.X - b.X) + (a.Y - b.Y)*(a.Y - b.Y) );
}
/// <summary>
/// Converts an object of type DateTime or IConvertible to double representation.
/// Mapping is 1:1. Note: the System.Convert.ToDouble method can not convert a boxed
/// DateTime to double. This implementation can - but the "is" check probably makes
/// it much slower.
/// </summary>
/// <remarks>Compare speed with System.Convert.ToDouble and revise code that calls this if significant speed difference.</remarks>
/// <param name="o">The object to convert to double.</param>
/// <returns>double value associated with the object.</returns>
public static double ToDouble( object o )
{
if (o is DateTime)
{
return (double)(((DateTime)o).Ticks);
}
else if (o is IConvertible)
{
return System.Convert.ToDouble(o);
}
throw new NPlotException( "Invalid datatype" );
}
/// <summary>
/// Returns the minimum and maximum values in an IList. The members of the list
/// can be of different types - any type for which the function Utils.ConvertToDouble
/// knows how to convert into a double.
/// </summary>
/// <param name="a">The IList to search.</param>
/// <param name="min">The minimum value.</param>
/// <param name="max">The maximum value.</param>
/// <returns>true if min max set, false otherwise (a == null or zero length).</returns>
public static bool ArrayMinMax( IList a, out double min, out double max )
{
if ( a == null || a.Count == 0 )
{
min = 0.0;
max = 0.0;
return false;
}
min = Utils.ToDouble(a[0]);
max = Utils.ToDouble(a[0]);
foreach ( object o in a )
{
double e = Utils.ToDouble(o);
if ( (min.Equals (double.NaN)) && (!e.Equals (double.NaN)) )
{
// if min/max are double.NaN and the current value not, then
// set them to the current value.
min = e;
max = e;
}
if (!double.IsNaN(e))
{
if (e < min)
{
min = e;
}
if (e > max)
{
max = e;
}
}
}
if (min.Equals (double.NaN))
{
// if min == double.NaN, then max is also double.NaN
min = 0.0;
max = 0.0;
return false;
}
return true;
}
/// <summary>
/// Returns the minimum and maximum values in a DataRowCollection.
/// </summary>
/// <param name="rows">The row collection to search.</param>
/// <param name="min">The minimum value.</param>
/// <param name="max">The maximum value.</param>
/// <param name="columnName">The name of the column in the row collection to search over.</param>
/// <returns>true is min max set, false otherwise (a = null or zero length).</returns>
public static bool RowArrayMinMax( DataRowCollection rows,
out double min, out double max, string columnName )
{
// double[] is a reference type and can be null, if it is then I reckon the best
// values for min and max are also null. double is a value type so can't be set
// to null. So min an max return object, and we understand that if it is not null
// it is a boxed double (same trick I use lots elsewhere in the lib). The
// wonderful comment I didn't write at the top should explain everything.
if ( rows == null || rows.Count == 0 )
{
min = 0.0;
max = 0.0;
return false;
}
min = Utils.ToDouble( (rows[0])[columnName] );
max = Utils.ToDouble( (rows[0])[columnName] );
foreach ( DataRow r in rows )
{
double e = Utils.ToDouble( r[columnName] );
if ( (min.Equals (double.NaN)) && (!e.Equals (double.NaN)) )
{
// if min/max are double.NaN and the current value not, then
// set them to the current value.
min = e;
max = e;
}
if (!double.IsNaN(e))
{
if (e < min)
{
min = e;
}
if (e > max)
{
max = e;
}
}
}
if (min.Equals (double.NaN))
{
// if min == double.NaN, then max is also double.NaN
min = 0.0;
max = 0.0;
return false;
}
return true;
}
/// <summary>
/// Returns the minimum and maximum values in a DataView.
/// </summary>
/// <param name="data">The DataView to search.</param>
/// <param name="min">The minimum value.</param>
/// <param name="max">The maximum value.</param>
/// <param name="columnName">The name of the column in the row collection to search over.</param>
/// <returns>true is min max set, false otherwise (a = null or zero length).</returns>
public static bool DataViewArrayMinMax( DataView data,
out double min, out double max, string columnName )
{
// double[] is a reference type and can be null, if it is then I reckon the best
// values for min and max are also null. double is a value type so can't be set
// to null. So min an max return object, and we understand that if it is not null
// it is a boxed double (same trick I use lots elsewhere in the lib). The
// wonderful comment I didn't write at the top should explain everything.
if ( data == null || data.Count == 0 )
{
min = 0.0;
max = 0.0;
return false;
}
min = Utils.ToDouble( (data[0])[columnName] );
max = Utils.ToDouble( (data[0])[columnName] );
for (int i=0; i<data.Count; ++i)
{
double e = Utils.ToDouble( data[i][columnName] );
if (e < min)
{
min = e;
}
if (e > max)
{
max = e;
}
}
return true;
}
/// <summary>
/// Returns unit vector along the line a->b.
/// </summary>
/// <param name="a">line start point.</param>
/// <param name="b">line end point.</param>
/// <returns>The unit vector along the specified line.</returns>
public static PointF UnitVector( PointF a, PointF b )
{
PointF dir = new PointF( b.X - a.X, b.Y - a.Y );
double dirNorm = System.Math.Sqrt( dir.X*dir.X + dir.Y*dir.Y );
if ( dirNorm > 0.0f )
{
dir = new PointF(
(float)((1.0f/dirNorm)*dir.X),
(float)((1.0f/dirNorm)*dir.Y) ); // normalised axis direction vector
}
return dir;
}
/// <summary>
/// Get a Font exactly the same as the passed in one, except for scale factor.
/// </summary>
/// <param name="initial">The font to scale.</param>
/// <param name="scale">Scale by this factor.</param>
/// <returns>The scaled font.</returns>
public static Font ScaleFont( Font initial, double scale )
{
FontStyle fs = initial.Style;
GraphicsUnit gu = initial.Unit;
double sz = initial.Size;
sz = sz * scale ;
string nm = initial.Name;
return new Font( nm, (float)sz, fs, gu );
}
/// <summary>
/// Creates a bitmap from another that is tiled size times in each direction.
/// </summary>
/// <param name="image">bitmap to tile</param>
/// <param name="size">number of times to tile in each direction.</param>
/// <returns>the tiled bitmap.</returns>
public static System.Drawing.Bitmap TiledImage( System.Drawing.Bitmap image, Size size )
{
System.Drawing.Bitmap final = new System.Drawing.Bitmap( size.Width, size.Height );
for (int i=0; i<(size.Width / image.Width)+1; ++i)
{
for (int j=0; j<(size.Height / image.Height)+1; ++j)
{
Graphics.FromImage( final ).DrawImage( image, i*image.Width, j*image.Height );
}
}
return final;
}
}
}

293
lib/VerticalLine.cs Normal file
Просмотреть файл

@ -0,0 +1,293 @@
/*
NPlot - A charting library for .NET
VerticalLine.cs
Copyright (C) 2003
Matt Howlett
Redistribution and use of NPlot or parts there-of in source and
binary forms, with or without modification, are permitted provided
that the following conditions are met:
1. Re-distributions in source form must retain at the head of each
source file the above copyright notice, this list of conditions
and the following disclaimer.
2. Any product ("the product") that makes use NPlot or parts
there-of must either:
(a) allow any user of the product to obtain a complete machine-
readable copy of the corresponding source code for the
product and the version of NPlot used for a charge no more
than your cost of physically performing source distribution,
on a medium customarily used for software interchange, or:
(b) reproduce the following text in the documentation, about
box or other materials intended to be read by human users
of the product that is provided to every human user of the
product:
"This product includes software developed as
part of the NPlot library project available
from: http://www.nplot.com/"
The words "This product" may optionally be replace with
the actual name of the product.
------------------------------------------------------------------------
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
using System;
using System.Drawing;
namespace NPlot
{
/// <summary>
/// Encapsulates functionality for drawing a vertical line on a plot surface.
/// </summary>
public class VerticalLine : IPlot
{
/// <summary>
/// Constructor
/// </summary>
/// <param name="abscissaValue">abscissa (X) value of line.</param>
public VerticalLine( double abscissaValue )
{
this.value_ = abscissaValue;
}
/// <summary>
/// Constructor
/// </summary>
/// <param name="abscissaValue">abscissa (X) value of line.</param>
/// <param name="color">draw the line using this color.</param>
public VerticalLine( double abscissaValue, Color color )
{
this.value_ = abscissaValue;
this.pen_ = new Pen( color );
}
/// <summary>
/// Constructor
/// </summary>
/// <param name="abscissaValue">abscissa (X) value of line.</param>
/// <param name="pen">Pen to use to draw the line.</param>
public VerticalLine( double abscissaValue, Pen pen )
{
this.value_ = abscissaValue;
this.pen_ = pen;
}
/// <summary>
/// Draws a representation of the line in the legend
/// </summary>
/// <param name="g">The graphics surface on which to draw.</param>
/// <param name="startEnd">A rectangle specifying the bounds of the area in the legend set aside for drawing.</param>
public void DrawInLegend(System.Drawing.Graphics g, System.Drawing.Rectangle startEnd)
{
g.DrawLine( pen_, startEnd.Left, (startEnd.Top + startEnd.Bottom)/2,
startEnd.Right, (startEnd.Top + startEnd.Bottom)/2 );
}
/// <summary>
/// A label to associate with the plot - used in the legend.
/// </summary>
public string Label
{
get
{
return label_;
}
set
{
this.label_ = value;
}
}
private string label_ = "";
/// <summary>
/// Whether or not to include an entry for this plot in the legend if it exists.
/// </summary>
public bool ShowInLegend
{
get
{
return showInLegend_;
}
set
{
this.showInLegend_ = value;
}
}
private bool showInLegend_ = false;
/// <summary>
/// Returns an x-axis that is suitable for drawing this plot.
/// </summary>
/// <returns>A suitable x-axis.</returns>
public Axis SuggestXAxis()
{
return new LinearAxis( value_, value_ );
}
/// <summary>
/// Returns null indicating that y extremities of the line are variable.
/// </summary>
/// <returns>null</returns>
public Axis SuggestYAxis()
{
return null;
}
/// <summary>
/// Writes text data describing the vertical line object to the supplied string builder. It is
/// possible to specify that the data will be written only if the line is in the specified
/// region.
/// </summary>
/// <param name="sb">the StringBuilder object to write to.</param>
/// <param name="region">a region used if onlyInRegion is true.</param>
/// <param name="onlyInRegion">If true, data will be written only if the line is in the specified region.</param>
public void WriteData(System.Text.StringBuilder sb, RectangleD region, bool onlyInRegion)
{
// return if line is not in plot region and
if (value_ > region.X+region.Width || value_ < region.X)
{
if (onlyInRegion)
{
return;
}
}
sb.Append( "Label: " );
sb.Append( this.Label );
sb.Append( "\r\n" );
sb.Append( value_.ToString() );
sb.Append( "\r\n" );
}
/// <summary>
/// Draws the vertical line plot on a GDI+ surface against the provided x and y axes.
/// </summary>
/// <param name="g">The GDI+ surface on which to draw.</param>
/// <param name="xAxis">The X-Axis to draw against.</param>
/// <param name="yAxis">The Y-Axis to draw against.</param>
public void Draw(System.Drawing.Graphics g, PhysicalAxis xAxis, PhysicalAxis yAxis)
{
int yMin = yAxis.PhysicalMin.Y;
int yMax = yAxis.PhysicalMax.Y;
yMin -= pixelIndent_;
yMax += pixelIndent_;
float length = Math.Abs(yMax - yMin);
float lengthDiff = length - length*scale_;
float indentAmount = lengthDiff/2;
yMin -= (int)indentAmount;
yMax += (int)indentAmount;
int xPos = (int)xAxis.WorldToPhysical( value_, false ).X;
g.DrawLine( pen_, new System.Drawing.Point( xPos, yMin ), new System.Drawing.Point( xPos, yMax ) );
// todo: clip and proper logic for flipped axis min max.
}
/// <summary>
/// abscissa (X) value to draw horizontal line at.
/// </summary>
public double AbscissaValue
{
get
{
return value_;
}
set
{
value_ = value;
}
}
/// <summary>
/// Pen to use to draw the horizontal line.
/// </summary>
public Pen Pen
{
get
{
return pen_;
}
set
{
pen_ = value;
}
}
private double value_;
private Pen pen_ = new Pen( Color.Black );
/// <summary>
/// Each end of the line is indented by this many pixels.
/// </summary>
public int PixelIndent
{
get
{
return pixelIndent_;
}
set
{
pixelIndent_ = value;
}
}
private int pixelIndent_ = 0;
/// <summary>
/// The line length is multiplied by this amount. Default
/// corresponds to a value of 1.0.
/// </summary>
public float LengthScale
{
get
{
return scale_;
}
set
{
scale_ = value;
}
}
private float scale_ = 1.0f;
}
}

Просмотреть файл

@ -0,0 +1,121 @@
/*
NPlot - A charting library for .NET
Web.PlotSurface2d.cs
Copyright (C) 2003
Matt Howlett, Paolo Pierini
Redistribution and use of NPlot or parts there-of in source and
binary forms, with or without modification, are permitted provided
that the following conditions are met:
1. Re-distributions in source form must retain at the head of each
source file the above copyright notice, this list of conditions
and the following disclaimer.
2. Any product ("the product") that makes use NPlot or parts
there-of must either:
(a) allow any user of the product to obtain a complete machine-
readable copy of the corresponding source code for the
product and the version of NPlot used for a charge no more
than your cost of physically performing source distribution,
on a medium customarily used for software interchange, or:
(b) reproduce the following text in the documentation, about
box or other materials intended to be read by human users
of the product that is provided to every human user of the
product:
"This product includes software developed as
part of the NPlot library project available
from: http://www.nplot.com/"
The words "This product" may optionally be replace with
the actual name of the product.
------------------------------------------------------------------------
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
using System;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.ComponentModel;
using NPlot;
namespace NPlot
{
namespace Web
{
namespace Design
{
/// <summary>
/// The Design Time rendered for the NPlot.web.PlotSurface2D control.
/// </summary>
public class PlotSurface2D : System.Web.UI.Design.ControlDesigner
{
/// <summary>
/// The design time generated HTML for the control.
/// </summary>
/// <returns>A string containing the HTML rendering.</returns>
public override string GetDesignTimeHtml()
{
// Extremely simple design time rendering!
// will work on something better sooner or later.
// This acts as a placeholder.
Web.PlotSurface2D plot = (Web.PlotSurface2D)Component;
int xs = Convert.ToInt32(plot.Width.Value);
if ( xs < 1 ) return "";
int ys = Convert.ToInt32(plot.Height.Value);
if ( ys < 1 ) return "";
StringWriter sw = new StringWriter();
HtmlTextWriter output= new HtmlTextWriter(sw);
output.AddAttribute("border",plot.BorderWidth.ToString());
output.AddAttribute("borderColor",plot.BorderColor.ToKnownColor().ToString());
output.AddAttribute("cellSpacing","0");
output.AddAttribute("cellPadding","0");
output.AddAttribute("width",xs.ToString());
output.RenderBeginTag("table ");
output.RenderBeginTag("tr");
output.AddAttribute("vAlign","center");
output.AddAttribute("align","middle");
output.AddAttribute("height",ys.ToString());
output.RenderBeginTag("td");
output.RenderBeginTag("P");
output.Write("PlotSurface2D:" + plot.Title);
output.RenderEndTag();
output.RenderEndTag();
output.RenderEndTag();
output.RenderEndTag();
output.Flush();
return sw.ToString();
}
}
}
}
}

671
lib/Web.PlotSurface2D.cs Normal file
Просмотреть файл

@ -0,0 +1,671 @@
/*
NPlot - A charting library for .NET
Web.PlotSurface2d.cs
Copyright (C) 2003
Matt Howlett, Paolo Pierini
Redistribution and use of NPlot or parts there-of in source and
binary forms, with or without modification, are permitted provided
that the following conditions are met:
1. Re-distributions in source form must retain at the head of each
source file the above copyright notice, this list of conditions
and the following disclaimer.
2. Any product ("the product") that makes use NPlot or parts
there-of must either:
(a) allow any user of the product to obtain a complete machine-
readable copy of the corresponding source code for the
product and the version of NPlot used for a charge no more
than your cost of physically performing source distribution,
on a medium customarily used for software interchange, or:
(b) reproduce the following text in the documentation, about
box or other materials intended to be read by human users
of the product that is provided to every human user of the
product:
"This product includes software developed as
part of the NPlot library project available
from: http://www.nplot.com/"
The words "This product" may optionally be replace with
the actual name of the product.
------------------------------------------------------------------------
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
using System;
using System.Drawing;
using System.Drawing.Imaging;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.ComponentModel;
using System.IO;
using System.Collections;
using System.Text;
namespace NPlot
{
namespace Web
{
/// <summary>
/// A PlotSurface2D web control. Rather than use this control, I generally create bitmaps
/// using Bitmap.PlotSurface2D, then use the ToBrowser() method in Bitmap.PlotSurface2D to
/// return them as a page request response (and point the src in an image tag to this page).
///
/// This is not as nice from a users perspective but is more efficient.
///
/// Note: this control can chew up memory until the user session ends if the client cancels
/// the page load before the image has loaded.
/// </summary>
[
DefaultProperty("Title"),
ToolboxData("<{0}:PlotSurface2D runat=server></{0}:PlotSurface2D>"),
Designer(typeof(NPlot.Web.Design.PlotSurface2D))
]
public class PlotSurface2D : System.Web.UI.WebControls.WebControl, IPlotSurface2D
{
private NPlot.PlotSurface2D ps_ = new NPlot.PlotSurface2D();
/// <summary>
/// Default constructor.
/// </summary>
public PlotSurface2D() :
base()
{
}
/// <summary>
/// The URL to redirect for the plot.
/// </summary>
private string plotUrl;
/// <summary>
/// the prefix used for the session variables
/// </summary>
private string prefix()
{
string toReturn = "__PlotSurface2D_";
toReturn += this.ClientID;
toReturn += "_";
toReturn += this.Page.ToString();
toReturn += "_";
return toReturn;
}
/// <summary>
/// Clears the plot.
/// </summary>
public void Clear()
{
ps_.Clear();
}
/// <summary>
/// Adds a drawable object to the plot surface. If the object is an IPlot,
/// the PlotSurface2D axes will also be updated.
/// </summary>
/// <param name="p">The IDrawable object to add to the plot surface.</param>
public void Add( IDrawable p )
{
ps_.Add( p );
}
/// <summary>
/// Adds a drawable object to the plot surface against the specified axes. If
/// the object is an IPlot, the PlotSurface2D axes will also be updated.
/// </summary>
/// <param name="p">the IDrawable object to add to the plot surface</param>
/// <param name="xp">the x-axis to add the plot against.</param>
/// <param name="yp">the y-axis to add the plot against.</param>
public void Add( IDrawable p, NPlot.PlotSurface2D.XAxisPosition xp, NPlot.PlotSurface2D.YAxisPosition yp )
{
ps_.Add( p, xp, yp );
}
/// <summary>
/// Adds a drawable object to the plot surface. If the object is an IPlot,
/// the PlotSurface2D axes will also be updated.
/// </summary>
/// <param name="p">The IDrawable object to add to the plot surface.</param>
/// <param name="zOrder">The z-ordering when drawing (objects with lower numbers are drawn first)</param>
public void Add( IDrawable p, int zOrder )
{
ps_.Add( p, zOrder );
}
/// <summary>
/// Adds a drawable object to the plot surface against the specified axes. If
/// the object is an IPlot, the PlotSurface2D axes will also be updated.
/// </summary>
/// <param name="p">the IDrawable object to add to the plot surface</param>
/// <param name="xp">the x-axis to add the plot against.</param>
/// <param name="yp">the y-axis to add the plot against.</param>
/// <param name="zOrder">The z-ordering when drawing (objects with lower numbers are drawn first)</param>
public void Add( IDrawable p, NPlot.PlotSurface2D.XAxisPosition xp,
NPlot.PlotSurface2D.YAxisPosition yp, int zOrder )
{
ps_.Add( p, xp, yp , zOrder);
}
/// <summary>
/// The plot surface title.
/// </summary>
[
Browsable(true),
Bindable(true)
]
public string Title
{
get
{
return ps_.Title;
}
set
{
ps_.Title = value;
}
}
/// <summary>
/// The plot title font.
/// </summary>
[
Browsable(true)
]
public System.Drawing.Font TitleFont
{
get
{
return ps_.TitleFont;
}
set
{
ps_.TitleFont = value;
}
}
/// <summary>
/// The distance in pixels to leave between of the edge of the bounding rectangle
/// supplied to the Draw method, and the markings that make up the plot.
/// </summary>
[
Browsable(true),
Category("Data"),
Bindable(true)
]
public int Padding
{
get
{
return ps_.Padding;
}
set
{
ps_.Padding = value;
}
}
/// <summary>
/// The first abscissa axis.
/// </summary>
[
Browsable(false),
Bindable(false)
]
public Axis XAxis1
{
get
{
return ps_.XAxis1;
}
set
{
ps_.XAxis1 = value;
}
}
/// <summary>
/// The first ordinate axis.
/// </summary>
[
Browsable(false),
Bindable(false)
]
public Axis YAxis1
{
get
{
return ps_.YAxis1;
}
set
{
ps_.YAxis1 = value;
}
}
/// <summary>
/// The second abscissa axis.
/// </summary>
[
Browsable(false),
Bindable(false)
]
public Axis XAxis2
{
get
{
return ps_.XAxis2;
}
set
{
ps_.XAxis2 = value;
}
}
/// <summary>
/// The second ordinate axis.
/// </summary>
[
Browsable(false),
Bindable(false)
]
public Axis YAxis2
{
get
{
return ps_.YAxis2;
}
set
{
ps_.YAxis2 = value;
}
}
/// <summary>
/// A color used to paint the plot background. Mutually exclusive with PlotBackImage and PlotBackBrush
/// </summary>
[
Bindable(true),
Browsable(true)
]
public System.Drawing.Color PlotBackColor
{
set
{
ps_.PlotBackColor = value;
}
}
/// <summary>
/// An imaged used to paint the plot background. Mutually exclusive with PlotBackColor and PlotBackBrush
/// </summary>
public System.Drawing.Bitmap PlotBackImage
{
set
{
ps_.PlotBackImage = value;
}
}
/// <summary>
/// A Rectangle brush used to paint the plot background. Mutually exclusive with PlotBackColor and PlotBackBrush
/// </summary>
public IRectangleBrush PlotBackBrush
{
set
{
ps_.PlotBackBrush = value;
}
}
/// <summary>
/// Gets or Sets the legend to use with this plot surface.
/// </summary>
[
Bindable(false),
Browsable(false)
]
public NPlot.Legend Legend
{
get
{
return ps_.Legend;
}
set
{
ps_.Legend = value;
}
}
/// <summary>
/// Gets or Sets the legend z-order.
/// </summary>
[
Bindable(true),
Browsable(true)
]
public int LegendZOrder
{
get
{
return ps_.LegendZOrder;
}
set
{
ps_.LegendZOrder = value;
}
}
/// <summary>
/// Smoothing mode to use when drawing plots.
/// </summary>
[
Bindable(true),
Browsable(true)
]
public System.Drawing.Drawing2D.SmoothingMode SmoothingMode
{
get
{
return ps_.SmoothingMode;
}
set
{
ps_.SmoothingMode = value;
}
}
/// <summary>
/// The bitmap background color outside the bounds of the plot surface.
/// </summary>
[
Bindable(true),
Browsable(true)
]
public override Color BackColor
{
set
{
backColor_ = value;
}
}
object backColor_ = null;
/// <summary>
/// Ivan Ivanov wrote this function. From his email:
/// If the request string contains encoded parameters values [e.g. # - %23].
/// The call to request.Url.ToString() will decode values [e.g. instead of %23
/// it will return #]. On the subsequent request to the page that contains the
/// nplot control [when the actual drawing of the image takes place] the request
/// url will be cut up to the unformated value [e.g. #] and since the PlotSurface2D_
/// is added at the end of the query string, it will be missing.
/// </summary>
/// <returns></returns>
private String buildPlotURL()
{
StringBuilder urlParams = new StringBuilder();
foreach (string getParamName in Context.Request.QueryString.AllKeys)
{
urlParams.Append(getParamName + "=" +
Context.Server.UrlEncode(Context.Request.QueryString[getParamName]) + "&");
}
return Context.Request.Url.AbsolutePath +
(urlParams.Length > 0 ?
"?" + urlParams.Append("PlotSurface2D_" + this.ClientID + "=1").ToString() :
"?PlotSurface2D_" + this.ClientID + "=1");
}
/// <summary>
/// Initialization event.
/// </summary>
/// <param name="e"></param>
protected override void OnInit(EventArgs e)
{
System.Web.HttpRequest request = Context.Request;
System.Web.HttpResponse response = Context.Response;
if (request.Params["PlotSurface2D_" + this.ClientID] != null)
{
// retrieve the bitmap and display
response.Clear();
try
{
response.ContentType = "Image/Png";
System.Drawing.Bitmap bmp = (System.Drawing.Bitmap) Context.Session[prefix()+"PNG"];
// don't ask why, but if I write directly to the response
// I have a GDI+ error, if I first write to a MemoryStream and
// then to the response.OutputStream I don't get an error.
System.IO.MemoryStream s = new System.IO.MemoryStream();
bmp.Save( s, System.Drawing.Imaging.ImageFormat.Png);
s.WriteTo(response.OutputStream);
Context.Session.Remove(prefix()+"PNG");
}
catch (Exception ex)
{
response.ContentType = "Text/HTML";
response.Write( ex.Message );
}
finally
{
response.Flush();
response.End();
}
}
this.plotUrl = this.buildPlotURL();
base.OnInit (e);
}
/// <summary>
/// Render this control as an HTML stream.
/// </summary>
/// <param name="output">The HTML writer to write out to.</param>
protected override void Render(HtmlTextWriter output)
{
// first of all render the bitmap;
System.Drawing.Bitmap b = new System.Drawing.Bitmap( (int)this.Width.Value, (int)this.Height.Value );
if (backColor_!=null)
{
Graphics g = Graphics.FromImage( b );
g.FillRectangle( (new Pen( (Color)this.backColor_)).Brush,0,0,b.Width,b.Height );
}
ps_.Draw( Graphics.FromImage(b), new System.Drawing.Rectangle(0,0,b.Width,b.Height) );
// then store in context memory.
Context.Session[prefix()+"PNG"] = b;
// now render html.
if (this.BorderStyle == BorderStyle.None)
{
output.AddAttribute("border","0");
}
else
{
output.AddAttribute("border",this.BorderWidth.ToString());
output.AddAttribute("borderColor",this.BorderColor.ToKnownColor().ToString());
}
output.AddAttribute("cellSpacing","0");
output.AddAttribute("cellPadding","0");
output.RenderBeginTag("table");
output.RenderBeginTag("tr");
output.AddAttribute("vAlign","center");
output.AddAttribute("align","middle");
output.RenderBeginTag("td");
output.RenderBeginTag("P");
output.AddAttribute("src",this.plotUrl);
output.AddAttribute("alt",this.ToolTip);
output.RenderBeginTag("img");
output.RenderEndTag();
output.RenderEndTag();
output.RenderEndTag();
output.RenderEndTag();
output.RenderEndTag();
output.Flush();
}
/// <summary>
/// Add an axis constraint to the plot surface. Axis constraints can
/// specify relative world-pixel scalings, absolute axis positions etc.
/// </summary>
/// <param name="c">The axis constraint to add.</param>
public void AddAxesConstraint( AxesConstraint c )
{
ps_.AddAxesConstraint( c );
}
/// <summary>
/// Whether or not the title will be scaled according to size of the plot
/// surface.
/// </summary>
[
Browsable(true),
Bindable(true)
]
public bool AutoScaleTitle
{
get
{
return ps_.AutoScaleTitle;
}
set
{
ps_.AutoScaleTitle = value;
}
}
/// <summary>
/// When plots are added to the plot surface, the axes they are attached to
/// are immediately modified to reflect data of the plot. If
/// AutoScaleAutoGeneratedAxes is true when a plot is added, the axes will
/// be turned in to auto scaling ones if they are not already [tick marks,
/// tick text and label size scaled to size of plot surface]. If false,
/// axes will not be autoscaling.
/// </summary>
[
Browsable(true),
Bindable(true),
]
public bool AutoScaleAutoGeneratedAxes
{
get
{
return ps_.AutoScaleAutoGeneratedAxes;
}
set
{
ps_.AutoScaleAutoGeneratedAxes = value;
}
}
/// <summary>
/// Sets the title to be drawn using a solid brush of this color.
/// </summary>
[
Browsable(true),
Bindable(true)
]
public Color TitleColor
{
set
{
ps_.TitleColor = value;
}
}
/// <summary>
/// The brush used for drawing the title.
/// </summary>
[
Browsable(false)
]
public Brush TitleBrush
{
get
{
return ps_.TitleBrush;
}
set
{
ps_.TitleBrush = value;
}
}
/// <summary>
/// Remove a drawable object from the plot surface.
/// </summary>
/// <param name="p">the drawable to remove</param>
/// <param name="updateAxes">whether or not to update the axes after removing the idrawable.</param>
public void Remove( IDrawable p, bool updateAxes )
{
ps_.Remove( p, updateAxes );
}
/// <summary>
/// Gets an array list containing all drawables currently added to the PlotSurface2D.
/// </summary>
[
Browsable(false)
]
public ArrayList Drawables
{
get
{
return ps_.Drawables;
}
}
}
}
}

113
lib/Windows.PlotSurface.cs Normal file
Просмотреть файл

@ -0,0 +1,113 @@
using System;
using System.Collections;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Windows.Forms;
namespace NPlot.Windows
{
/// <summary>
/// An all encompasing Windows.Forms PlotSurface. This class allows you
/// to place a single control in your form layout and draw to any type of
/// plot surface (PlotSurface2D, PlotSurface3D etc) on it. As there is only
/// one type of plot surface currently, this
/// class isn't necessary... but more a planned soon.
/// Also, the implementation isn't finished.
/// </summary>
public class PlotSurface : System.Windows.Forms.UserControl
{
/// <summary>
/// control resize handler.
/// </summary>
/// <param name="e">event args.</param>
protected override void OnResize( EventArgs e )
{
this.Refresh();
base.OnResize(e);
}
/// <summary>
/// control paint handler.
/// </summary>
/// <param name="pe">paint event args.</param>
protected override void OnPaint( PaintEventArgs pe )
{
surface_.DoPaint( pe, this.Width, this.Height );
base.OnPaint(pe);
}
/// <summary>
/// Mouse down event handler.
/// </summary>
/// <param name="e">mouse event args</param>
protected override void OnMouseDown(MouseEventArgs e)
{
surface_.DoMouseDown(e);
base.OnMouseDown(e);
}
/// <summary>
/// Mouse Up event handler.
/// </summary>
/// <param name="e">mouse event args.</param>
protected override void OnMouseUp(MouseEventArgs e)
{
surface_.DoMouseUp(e, this);
base.OnMouseUp(e);
}
/// <summary>
/// Mouse Move event handler.
/// </summary>
/// <param name="e">mouse event args.</param>
protected override void OnMouseMove(MouseEventArgs e)
{
surface_.DoMouseMove(e, this);
base.OnMouseMove(e);
}
/*
enum Type
{
PlotSurface2D,
PlotSurface2Dnew,
PlotSurface3D,
PieChart
}
*/
ISurface surface_ = null;
/// <summary>
/// Gets the underlying plot surface.
/// </summary>
public ISurface Surface
{
get
{
return surface_;
}
}
/// <summary>
/// Constructor.
/// </summary>
public PlotSurface()
{
// double buffer, and update when resize.
base.SetStyle(ControlStyles.AllPaintingInWmPaint, true);
base.SetStyle(ControlStyles.DoubleBuffer, true);
base.SetStyle(ControlStyles.UserPaint, true);
base.ResizeRedraw = true;
surface_ = new NPlot.Windows.PlotSurface2D();
}
}
}

Просмотреть файл

@ -0,0 +1,42 @@
<?xml version="1.0" encoding="utf-8" ?>
<root>
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="ResMimeType">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="Version">
<value>1.0.0.0</value>
</resheader>
<resheader name="Reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="Writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
</root>

2942
lib/Windows.PlotSurface2D.cs Normal file

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -0,0 +1,106 @@
<?xml version="1.0" encoding="utf-8" ?>
<root>
<!--
Microsoft ResX Schema
Version 1.3
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">1.3</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1">this is my long string</data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
[base64 mime encoded serialized .NET Framework object]
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
[base64 mime encoded string representing a byte array form of the .NET Framework object]
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used forserialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>1.3</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<data name="$this.TrayLargeIcon" type="System.Boolean, mscorlib, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>False</value>
</data>
<data name="$this.Name">
<value>PlotSurface2D</value>
</data>
</root>

Просмотреть файл

@ -0,0 +1,155 @@
// ******** experimental ********
/*
using System;
using System.Collections;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Windows.Forms;
using System.IO;
namespace NPlot.Windows
{
/// <summary>
/// Experimental
/// </summary>
public class PlotSurface2Dnew : System.Windows.Forms.UserControl, IPlotSurface2Dnew
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.Container components = null;
/// <summary>
/// Constructor
/// </summary>
public PlotSurface2Dnew()
{
// This call is required by the Windows.Forms Form Designer.
InitializeComponent();
// double buffer, and update when resize.
base.SetStyle(ControlStyles.AllPaintingInWmPaint, true);
base.SetStyle(ControlStyles.DoubleBuffer, true);
base.SetStyle(ControlStyles.UserPaint, true);
base.ResizeRedraw = true;
}
/// <summary>
/// Clean up any resources being used.
/// </summary>
protected override void Dispose( bool disposing )
{
if( disposing )
{
if( components != null )
components.Dispose();
}
base.Dispose( disposing );
}
#region Component Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
components = new System.ComponentModel.Container();
}
#endregion
private NPlot.PlotSurface2Dnew Inner = new NPlot.PlotSurface2Dnew();
/// <summary>
/// Experimental
/// </summary>
public void SetDefinition( )
{
Inner.SetDefinition( );
}
/// <summary>
/// the paint event callback.
/// </summary>
/// <param name="pe">paint event arguments - used to get graphics surface to draw on.</param>
protected override void OnPaint( PaintEventArgs pe )
{
Graphics g = pe.Graphics;
Rectangle border = new Rectangle( 0, 0, this.Width, this.Height );
if ( g == null )
{
ErrorHandler.Instance.CriticalError( "graphics context null" );
}
if ( border == Rectangle.Empty )
{
ErrorHandler.Instance.CriticalError( "Control has zero extent" );
return;
}
this.Draw( g, border );
base.OnPaint(pe);
}
/// <summary>
/// Draws the plot surface on the supplied graphics surface [not the control surface].
/// </summary>
/// <param name="g">The graphics surface on which to draw</param>
/// <param name="bounds">A bounding box on this surface that denotes the area on the
/// surface to confine drawing to.</param>
public void Draw( Graphics g, Rectangle bounds )
{
try
{
Inner.Draw( g, bounds );
}
catch (Exception ex)
{
System.Diagnostics.Debugger.Log( 1, "", "Exception drawing plot:" + ex + "\r\n" );
}
}
/// <summary>
/// Padding of this width will be left between what is drawn and the control border.
/// </summary>
[
Category("PlotSurface2D"),
Description("Padding of this width will be left between what is drawn and the control border."),
Browsable(true)
]
public int Padding
{
get
{
return Inner.Padding;
}
set
{
Inner.Padding = value;
}
}
/// <summary>
/// Adds a drawable object to the plot surface against the specified axes. If
/// the object is an IPlot, the PlotSurface2D axes will also be updated.
/// </summary>
/// <param name="p">the IDrawable object to add to the plot surface</param>
/// <param name="xAxis">the x-axis to add the plot against.</param>
/// <param name="yAxis">the y-axis to add the plot against.</param>am>
public void Add( IDrawable p, string xAxis, string yAxis )
{
this.Inner.Add( p, xAxis, yAxis );
}
}
}
*/

1214
lib/asx_jbh.xml Normal file

Разница между файлами не показана из-за своего большого размера Загрузить разницу

295
lib/changelog.txt Normal file
Просмотреть файл

@ -0,0 +1,295 @@
0.9.9.2 28 Feb 2006
Fixed bug in DateTimeAxis.WorldTickPositions_FirstPass reported by Pawel Konieczny.
Fixed a bug in WorldTickPositions_SecondPass - thanks to Pawel Konieczny.
Fixed a problem in Axis.WorldToPhysical - Thanks to Pawel Konieczny again for this one.
Adding TradingDateTimeAxis contributed by Pawel Konieczny.
Made changes to DateTimeAxis to allow TradingDateTimeAxis to work.
Added Line in legend for point plot in appropriate case (thanks to Pawel Konieczny).
Pawel Konieczny: Fixing suggested axes in BarPlot, which did not take into account
all Y points originally. Made bar width configurable
Pawel Konieczny: A small fix for vertical and horizontal guidelines, to remove
their remnants from the plot. The remnants can be left over when the
mouse move is fast such that the interaction does not get enough move
even to remove itself. This fix does not really solve all problems with
guidelines; for instance, try the following: run a demo application with
a plot with a guideline, cover part of the plot by a window of another
program, then hover the mouse over the not obscured area of the plot.
Pawel Konieczny: A fix in CandlePlot.CalculatePhysicalSeparation(). The
original code bombs with a null pointer exception when there are exactly
three points.
Pawel Konieczny: fixed bugs in horizontal and vertical drag interactions when
the axis is non-linear. It fixes also a small bug for a linear axes,
which led to a slight and steady zoom-in process when dragging the plot
somewhat longer.
Pawel Konieczny: fixed bugs in axis drag interaction for non-linear axes.
Pawel Konieczny: MouseWheelZoom (which actually does scroll) adapted to
non-linear axes. Additionally, Interaction.MouseWheelZoom improved to do
zoom and handle Y axis too.
Pawel Konieczny: Performance enhancements to CandlePlot
Pawel Konieczny: Performance enhancements to LinePlot
Pawel Konieczny: Performance enhancements to Transform2D
Pawel Konieczny: Performance enhancements to SequenceAdapter
Pawel Konieczny: Performance enhancements to PointPlot
Pawel Konieczny: DataGetter_DoublesArray added to AdapeterUtils
Pawel Konieczny: Performance enhancements to Windows.PlotSurface2D and
contained classes.
Added comments to uncommented public methods.
Pawel Konieczny: This one makes HorizontalRangeSelection forgiving accidental
clicks. Originally, a single click on a plot area with
HorizontalRangeSelection active would immediately zoom into an
indefinitely small zoom window. The change makes the interaction to
ignore very small selections, that may be made accidentally (I suppose
nobody would try to make deliberately such small selections, simply
because it is very hard to make them accurately with a mouse).
Matt: Added a property to set minimum select width in pixels in
HorizontalRangeSelection.
Pawel Konieczny: This one allows changing list of interactions on MouseUp.
Originally, on MouseUp, the list of the registered interactions is
looped through to dispatch the event. However, since the list is being
looped, it cannot be modified during that process (otherwise an
exception occurs).
Pawel Konieczny: I have added handling of "MouseLeave" to the list of events
that interaction may react to. This fine tunes the problem of "cleaning
up" the guidelines (not unconditionally anymore), and is used in some
new interactions I will send you later.
Pawel Konieczny: I have disable the check whether the candle width is not
zero. The effect was that when the amount of data displayed increases
(e.g. zoom out) and the candles got thinner and thinner, suddenly they
become thick again, overlapping each other. It may be even so, that by
scrolling left or right, due to different rounding errors, they become
thin again, and then again thick. I don't think it is useful to
prohibit candles of zero width (there always will be the vertical line
visible), since in such cases the distance between them is so small that
they form an almost contiguous fill region.
Pawel Konieczny: A few changes to ImagePlot. The point here is that the
ImagePlot by default uses the gradient to span from the minimum value to
maximum value. This is sometimes useful, but sometimes not. For
instance, when the image plot is used to show a sort of a topographic
map, where each color should correspond to some absolute value. The
changes here allow to explicitly set the values corresponding to the
gradient boundaries. Values outside the boundaries are mapped to the
boundary colors (that functionality was already present in the
gradient code, except that some debug check was throwing an exception
when it happened - I had to remove that too). For instance, values of
0.0 and all negatives could be mapped to black. I have also added a
possibility of a "void" color, which is used for NaN values. I use NaN
values to indicate that no data is present for a given point.
Pawel Konieczny: A small patch in drawing a shadow of the legend box. In the
original NPlot, the shadow is not really a shadow - it is a light gray
opaque rectangle box.
Small fix from Rosco to allow zero height bars in BarPlot.
Added data clipping speed up code to StepPlot (similar to code in Line, Point
and CandlePlot).
Added SmallestAllowedRange property to HorizontalRangeSelection interaction.
0.9.9.1 20 Feb 2006 (not released).
Fixed bug with Linear Axis Offset and Scale properties which caused incorrect display.
0.9.9 22 July 2005
Added LegendZOrder to PlotSurface2D.
Added PhysicalSpacingMin to LabelAxis
Added RemoveInteraction method to Windows.PlotSurface2D. Thanks to Måns Erlandson.
Fixed bug in Windows.PlotSurface2D.DoMouseMove reported by Måns Erlandson.
Added StepGradient with RGB and Rainbow types.
Ivan Ivanov fixed a bug in the Web Control when url contains params.
Image stored in session variable is now explicitly deleted (known issue, but thanks
to Ivan Ivanov for pointing this out also).
Fixed up designer attributes in web control.
Other (substantial) tweaking of web control. Note that this will eventually use the
DynamicImage control in ASP.NET 2.0, this control will be much more efficient.
Revised attributes (Bindable, Browsable, Description, Category) on relevant public
properties on Windows.PlotSurface2D.
Rosco Hill pointed out a bug in RefreshZOrdering.
Spent quite a lot of time designing MultiLinePlot and MultiSequenceAdapter classes
and supporting functions in AdapterUtils. There are issues remaining. I have
left this out of pre 1.0 releases.
Now prints title in centre of plot if there is no data.
Took StringFormat construction out of PlotSurface2D.Draw method and put in
constructor (to avoid unnecessarily creating this many times).
Removed PlotSurface3D and all related.
Removed PlotSurface2Dnew and all related.
Removed BubblePlot.cs
Removed PLotSurface and all related.
Removed StartStep and all related.
Removed MathExtra from Utils (3D calculations)
Finished commenting AdapterUtils
Filled in missing comments from other classes as well.
Deleted ErrorHandler class (wasn't a good move that one...).
Added NPlotException class - all NPlot exceptions throw of this type.
Added quick fix from Rosco Hill for fixing weird behaviour when Legend is wider
than plotting surface.
Changed ToBrowser method in Bitmap.PlotSurface2D to ToStream and to take image
format parameter.
0.9.8.9 [21 May 2005]
Gareth Hayter found the bug introduced in 0.9.8.8 whereby LinePlots are sometimes
not drawn.
Added LengthScale and PixelIndent properties to VerticalLine and HorizontalLine
Added ability to have multiple lines of text in the title.
Added HideVerticalLines property to StepPlot
Added HideHorizontalLines property to StepPlot.
Added ScaleWidth property to StepPlot.
Added zOffset to Windows.PlotSurface2D Web.PlotSurface2D and Bitmap.PlotSurface2D
classes.
Legends can now have items placed in a grid (not just vertically).
Added BarPlot for charting a series of two ordinate values as bars. This still
has work to go - the horizontal spacing is just a hack at the moment.
Added ability of legend to grow horizontally or vertically, and to specify the
maximum in the other direction.
Ticks can be placed between labels in the label axis.
0.9.8.8 [15 May 2005]
Added functionality to Filled region such that VerticalLine or Horizontal lines
can be specified in the bounds.
Added functionality that allows data to be obtained from arrays in CandleAdapter
class. Code implemented was a more general version of that contributed Gareth
Hayter.
Added new demo plot to demonstrate this.
Fixed problem with PlotSurface2D.Remove reported by Jonne van Wijngaarden.
Added patch from Jonne van Wijngaarden that makes axes drag expand from the point
clicked rather than the center.
Bug fix by Rosco Hill in line plot when zoomed right in.
Rosco Hill added code to draw small ticks in DateTime axis when in year mode.
Anton fixed a bug in Web.PlotSurface2D.
Change by Mike Miller for drawing Large Tickes on DateTime axes for time-spans
greater than 30 years.
Fix by Mike Miller in WorldToPhysical. Great work traking this one down.
Implemented z-ordering in PlotSurface2D Add methods after suggestion by Gareth
Hayter.
Revised default positioning of candle bars based on justification by Mike Miller.
Added Centered property to CandlePlot to chose between old default and new
default positioning of bars.
Converted back to VS2003 solution file.
René van Kleef fixed a bug in linear axis on large zooms.
Fixed Reversed flag not working anymore bug reported by "Steven". Thanks to
René van Kleef for finding the problem.
Fixed error found by René van Kleef in MarkerItem - incorrectly derived from
Marker
Added Constructors to MarkerItem as suggested by René van Kleef.
Added TextItem implementation submitted by René van Kleef.
0.9.8.7 []
DateTimeAxis now scales down to second resolution.
Added strong name key.
Windows.Plotsurface2D.Draw no longer catches exceptions.
Implemented interactions (lots of additions here).
Large Chunk of 3D Plotsurface and related classes implemented.
Changed axisCache variables in Windows.PlotSurface2D to zoomAxisCache.
Changed "Zoom Back" to "Original Dimensions".
Changed AllowSelection to EnableSelection.
Added EnableDrag property and implementation.
Arrow is not displayed if outside area of chart.
Made threads created in demo STA. Made CopyToClipboard copy = true.
Changed DateTimeAxis such that if scaled such that tick spacings every 2, 7, or 14 days, ticks
are always placed in the same spot regardless of WorldMin / WorldMax.
Changed Axis.Length property name to Axis.WorldLength.
Added LabelOffsetAbsolute property to Axis class.
0.9.8.5 [15 February 2005]
Przemyslaw Grodzki pointed out a Windows bug which caused "copy data to
clipboard" to crash, and provided a solution.
Added check for null in RightMenu property of Windows.PlotSurface2D.
Made NumberFormat null on DateTimeAxis Axis copy constructor to avoid formatting
problems when constrructing from non DateTime axes.
Changed the space between values in "copy data to clipboard" to a tab. This
makes it easier to insert values into Microsoft Excel and other programs.
Removed redundent WorldMin and WorldMax properties from DateTimeAxis.
0.9.8.4 [13 February 2005]
Removed context menu from Windows.PlotSurface2D and provided public methods for all functions
previously only available through the ContextMenu in Windows.PlotSurface2D.
Created PlotContextMenu class and associated classes which allow the right context menu to be
completely customized and extended.
Created the PlotSurface class and rearranged PlotSurface2D such that this is possible. PlotSurface
is not working completely yet, but the concept is proved. This is going to be an all encompasing
class for all types of plot surfaces (PiePlotSurface, RadialPlotSurface PlotSurface3D etc). Thanks
to Roberto Peña for useful discussions on this topic.
Added Drawables property to PlotSurface2D
Added CopyDataToClipboard functionality. This needs modifying now so that values reflect axis types.
Minor changes to LogAxis (object->double).
Added LabelOffset and LabelOffsetScaled to Axis class.
Changed the default Axis Label offset so it looks better.
Added HorizontalLine class to make drawing horizontal lines easy (it takes a bit of
effort to set up a LinePlot to do this).
Added VerticalLine class as well.
Added PiAxis class. Currently this can only print labels at integral values of Pi.
Added placeholder for TextItem. This IDrawable is needed.
Added RectangleD. This is used for CopyDataToClipboard
When no tick marks are shown, the Axis label position is now shown in a more reasonable position.
Rearranged the demo.
Bug when O/L/C/H value is NaN fixed in CandlePlot by Florian Hoertlehner.
Roberto Peña fixed a bug in LegendBase in the case that there are no lines.
0.9.8.3 [23 January 2005]
Florian Hoertlehner provided better NaN handling ability in Utils.RowArrayMinMax.
NPlot now is, and is marked CLSCompliant. Thanks to Roberto Peña for point this out.
Added lots of pre-defined Solid RectangleBrushes. Still need to add lots of predefined other style brushes.
Fixed bug whereby sometimes on Windows.Forms resize, the world bounds were randomly changing. The problem
turned out to be in OnMouseUp function [proved v. hard to track down!].
Cleaned up the demo code a bit.
Removed PropertyGrid from Windows.PlotSurface2D. I've left all the object selection code in there as it
will be useful in the future, but I don't wan't ProperyGrid to be on the control itself.
0.9.8.2 [12 January 2005]
Added patch by Rosco Hill for removing drawables from PlotSurfaces.
Fixed bug introduced in 0.9.8.1 that prevented LogAxes from working correctly. This
involved improvements to Transform2D and related classes.
0.9.8.1 [3 December 2004]
Przemyslaw Grodzki fixed a small internationalization bug in the demo.
PlotSurface gradient backgrounds.
PlotSurface Bitmap backgrounds.
Added some ready to go RectangleBrushes.
Improved efficiency of Line drawing - using optimized transform class.
Added shadow property for line class.
Juraj Skripsky fixed a bug in the SuggestYAxis method in HistogramPlot for stacked histograms.
Fixed "shakey lines" bug due to sub-optimal rounding. Thanks to René van Kleef for pointing this out.
Made Physical Axis Caches public in Windows.PlotSurface2D. Thanks to Stephan Puchegger for pointing this out.
0.9.8 [17 November 2004]
SequenceAdapter can now handle DataViews.
Revised implementation and interaction of Color, Pen and Brush properties in appropriate classes.
Added ArrowItem Drawable object.
Added skeleton code for 3D plots. No implementation yet.
Added Miguel's patch that reduces excessive memory allocations due to font scaling.
Applied many other similar optimizations.
In process of rethinking license.
ScreenAlignedPhysicalAxis (not in use yet).
Transform2D class skeleton (not in use yet).
Cleaned up Marker.cs. Removed creation of Brush object in every call to Draw.
Added MarkerItem IDrawable.
Made RectangleBrush classes [moving out of HistogramPlot].
Changed lots of floats to ints - convention:
* double in world domain.
* in physical domain: float only where need for accurate calculations, otherwise int.
* float for angles (not doubles) - as with .net Graphics class.
made candle widths depend on distance between successive points.
Added patches by Alexander Kucheravy relating to angled tick labels and large tick spacing for DateTime Axes.
0.9.7 [4 November 2004]
change log started.

94
lib/house_rules.txt Normal file
Просмотреть файл

@ -0,0 +1,94 @@
House Rules and random notes:
Note: I haven't followed these always. They reflect my current preferences, which
vary a little from time to time. Anything reasonably close is good enough.
o Classes begin with a capital letter and each world is capitalized. Eg:
HistogramPlot
o Class member functions begin with capital letter and each word is capitalized. Eg:
public void DrawTicks()
o Class member variables begin with a lower case letter, each word there-after capitalized.
Trailing underscore. Eg:
float worldMax_
o variables begin with a lower case letter, each world there-after capitalized.
This includes variables in a argumant list. Eg:
float worldMax
public void DrawTicks( float myArgument )
o use ++i over i++. (habbit from c++, ++i never less efficient than i++, sometimes more).
o always use braces. Do:
if ( a == 3 )
{
return;
}
not
if ( a == 3 )
return;
o add your name to the copyright list of a file if you do significant modifications
to it, or create it.
o Don't use hungarian notation. :-). It's not the done thing in C#, and the other
rules here allow differentiation between identifier types.
o braces like this:
if (a == 3)
{
Console.WriteLine( "Hello world\n" );
}
not like this:
if (a == 3) {
Console.WriteLine( "Hello world\n" );
}
o spaces like this:
if (a == 3)
not like this:
if( a == 3 )
or this:
if (a==3)
or this:
if(a==3)
o Comments:
(1) Avoid obvious comments, they annoy me.
(2) Make sure you _really_ understand what is going on before commenting. No comment is much much better than an incorrect comment.
(3) Use comments to leave notes to other coders (in particular me), so that I can quickly
see what has changed. I'll feel free to delete them.
o CVS:
Don't check in code that doesn't compile and run.

Двоичные данные
lib/icon.ico Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 318 B

44
lib/license.txt Normal file
Просмотреть файл

@ -0,0 +1,44 @@
NPlot - A charting library for .NET
Copyright (C) 2003-2005 Matt Howlett and others.
Redistribution and use of NPlot or parts there-of in source and
binary forms, with or without modification, are permitted provided
that the following conditions are met:
1. Re-distributions in source form must retain at the head of each
source file the above copyright notice, this list of conditions
and the following disclaimer.
2. Any product ("the product") that makes use NPlot or parts
there-of must either:
(a) allow any user of the product to obtain a complete machine-
readable copy of the corresponding source code for the
product and the version of NPlot used for a charge no more
than your cost of physically performing source distribution,
on a medium customarily used for software interchange, or:
(b) reproduce the following text in the documentation, about
box or other materials intended to be read by human users
of the product that is provided to every human user of the
product:
"This product includes software developed as
part of the NPlot library project available
from: http://www.nplot.com/"
The words "This product" may optionally be replace with
the actual name of the product.
------------------------------------------------------------------------
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше