using System;
using System.Collections.Generic;
using System.Text;
using System.Windows.Forms;
using System.Drawing;
using Chart;
namespace Chart
{
/// <summary>
/// Performer of chart
/// </summary>
public class ChartPerformer
{
/// <summary>
/// Shift delta
/// </summary>
const int DELTA = 5;
/// <summary>
/// Control to draw
/// </summary>
protected Control control = null;
/// <summary>
/// internal insets
/// </summary>
protected int[,] internalInsets = new int[,] { { 0, 0 }, { 0, 0 } };
/// <summary>
/// Array of series
/// </summary>
protected List<ISeries> series = new List<ISeries>();
protected Dictionary<ISeries, ISeriesPainter> painters = new Dictionary<ISeries, ISeriesPainter>();
/// <summary>
/// Size of canvas
/// </summary>
protected int[] size = new int[2];
/// <summary>
/// Physical size
/// </summary>
protected double[,] dSize = new double[2, 2];
/// <summary>
/// Insets
/// </summary>
protected int[,] insets;
/// <summary>
/// Temporary buffer
/// </summary>
protected Image iTemp;
/// <summary>
/// Buffer
/// </summary>
protected Image image;
/// <summary>
/// Auxiliary variable
/// </summary>
protected int xp;
/// <summary>
/// Auxiliary variable
/// </summary>
protected int yp;
/// <summary>
/// Auxiliary variable
/// </summary>
protected int xc;
/// <summary>
/// Auxiliary variable
/// </summary>
protected int yc;
/// <summary>
/// Rectangle for drawing
/// </summary>
protected Rectangle r = new Rectangle();
/// <summary>
/// Painter of coordinates
/// </summary>
protected ICoordPainter coordPainter = null;
/// <summary>
/// The "is mouse moved" sign
/// </summary>
protected bool isMoved;
/// <summary>
/// Pen for coordinates drawing
/// </summary>
protected Pen linePen;
/// <summary>
/// Source rectangle
/// </summary>
protected Rectangle sR;
/// <summary>
/// Descination rectangle
/// </summary>
protected Rectangle dR;
/// <summary>
/// The invert x - axis sign
/// </summary>
protected bool invertX = false;
/// <summary>
/// The invert y - axis sign
/// </summary>
protected bool invertY = false;
/// <summary>
/// Background color
/// </summary>
protected Color backColor;
/// <summary>
/// Step along x axis
/// </summary>
protected int stepX = 0;
/// <summary>
/// Step alogn y axis
/// </summary>
protected int stepY = 0;
/// <summary>
/// Constructor
/// </summary>
/// <param name="control">Control to draw</param>
/// <param name="insets">Insets</param>
public ChartPerformer(Control control, int[,] insets)
{
this.control = control;
this.insets = insets;
control.MouseDown += new MouseEventHandler(onMouseDown);
control.MouseUp += new MouseEventHandler(onMouseUp);
control.MouseMove += new MouseEventHandler(onMouseMove);
control.MouseLeave += new EventHandler(onMouseLeave);
linePen = new Pen(Color.Black);
sR = new Rectangle();
dR = new Rectangle();
}
/// <summary>
/// Constructor
/// </summary>
/// <param name="size">Size</param>
/// <param name="insets">insets</param>
public ChartPerformer(int[] size, int[,] insets, Color backColor)
{
this.size = size;
this.insets = insets;
this.backColor = backColor;
linePen = new Pen(Color.Black);
sR = new Rectangle();
dR = new Rectangle();
image = new Bitmap(size[0], size[1]);
iTemp = new Bitmap(size[0], size[1]);
Image im = image;
Graphics g = Graphics.FromImage(im);
Color back = bkgnd;
g.FillRectangle(new SolidBrush(back), 0, 0, im.Width, im.Height);
g.Dispose();
im = iTemp;
g = Graphics.FromImage(im);
g.FillRectangle(new SolidBrush(back), 0, 0, im.Width, im.Height);
g.Dispose();
}
/// <summary>
/// Constuctor
/// </summary>
protected ChartPerformer()
{
}
/// <summary>
/// Adds histogram
/// </summary>
/// <param name="histogram">Histogram</param>
/// <param name="color">Color</param>
/* public void AddHistogram(double[,] histogram, Color color)
{
histograms.Add(new object[] { histogram, color });
}*/
/// <summary>
/// Access to size
/// </summary>
public double this[int i, int j]
{
get
{
return dSize[i, j];
}
set
{
dSize[i, j] = value;
}
}
/// <summary>
/// Step along x axis
/// </summary>
public int StepX
{
get
{
return stepX;
}
set
{
stepX = value;
}
}
/// <summary>
/// Step alogn y axis
/// </summary>
public int StepY
{
get
{
return stepY;
}
set
{
stepY = value;
}
}
/// <summary>
/// Internal insets
/// </summary>
public int[,] InternalInsets
{
get
{
return internalInsets;
}
}
/// <summary>
/// The invert x - axis sign
/// </summary>
public bool InvertX
{
get
{
return invertX;
}
set
{
invertX = value;
}
}
/// <summary>
/// The invert y - axis sign
/// </summary>
public bool InvertY
{
get
{
return invertY;
}
set
{
invertY = value;
}
}
/// <summary>
/// Painter of coordinates
/// </summary>
public ICoordPainter Coordinator
{
set
{
coordPainter = value;
}
}
/// <summary>
/// Adds series
/// </summary>
/// <param name="s">Series to add</param>
public void AddSeries(ISeries s, Color color)
{
series.Add(s);
painters[s] = new SimpleSeriesPainter(this, color);
}
public void AddSeries(ISeries s, ISeriesPainter painter)
{
series.Add(s);
painters[s] = painter;
}
/// <summary>
/// Access to series
/// </summary>
public ISeries this[int n]
{
get
{
return series[n];
}
}
/// <summary>
/// Count of series
/// </summary>
public int Count
{
get
{
return series.Count;
}
}
/// <summary>
/// The last series
/// </summary>
public ISeries Last
{
get
{
if (series.Count == 0)
{
return null;
}
return this[Count - 1];
}
}
/// <summary>
/// Removes all series
/// </summary>
public void RemoveAll()
{
series.Clear();
//histograms.Clear();
}
/// <summary>
/// Removes a series
/// </summary>
/// <param name="s">The series to remove</param>
public void Remove(ISeries s)
{
series.Remove(s);
if (painters.ContainsKey(s))
{
painters.Remove(s);
}
}
/// <summary>
/// Size calculation
/// </summary>
public void CalculateSize()
{
for (int i = 0; i < Count; i++)
{
ISeries s = this[i];
double[,] size = s.Size;
if (i == 0)
{
for (int j = 0; j < 2; j++)
{
for (int k = 0; k < 2; k++)
{
dSize[j, k] = size[j, k];
}
}
continue;
}
for (int j = 0; j < 2; j++)
{
if (size[0, j] < dSize[0, j])
{
dSize[0, j] = size[0, j];
}
if (size[1, j] > dSize[1, j])
{
dSize[1, j] = size[1, j];
}
}
}
//resizeHistograms();
for (int i = 0; i < 2; i++)
{
double[] p = new double[3];
double a = size[i] + internalInsets[i, 0] + internalInsets[i, 1];
p[0] = (double)internalInsets[0, i] / a;
p[1] = (double)size[i] / a;
p[2] = (double)internalInsets[1, i] / a;
double min = dSize[0, i];
double max = dSize[1, i];
dSize[0, i] = min - p[0] * (max - min);
dSize[1, i] = max + p[2] * (max - min);
}
for (int i = 0; i < 2; i++)
{
if (dSize[0, i] == dSize[1, i])
{
if (dSize[1, i] > 0)
{
dSize[0, i] = 0;
dSize[1, i] *= 1.1;
}
else if (dSize[1, i] < 0)
{
dSize[1, i] = 0;
dSize[0, i] *= 1.1;
}
else
{
dSize[0, i] = -1;
dSize[1, i] = 1;
}
}
}
for (int i = 0; i < 2; i++)
{
for (int j = 0; j < 2; j++)
{
if (Double.IsNaN(dSize[i, j]))
{
throw new Exception("NaN");
}
}
}
}
public void Transform(double[] x, int[] point)
{
if (InvertX)
{
point[0] = (int)((double)(size[0])
* ((x[0] - dSize[1, 0]) / (dSize[0, 0] - dSize[1, 0])));
}
else
{
point[0] = (int)((double)((size[0])
* (x[0] - dSize[0, 0]) / (dSize[1, 0] - dSize[0, 0])));
}
if (InvertY)
{
point[1] = size[1]
- (int)((double)((size[1])
* ((x[1] - dSize[1, 1]) / (dSize[0, 1] - dSize[1, 1]))));
}
else
{
point[1] = size[1] - (int)((double)((size[1])
* ((x[1] - dSize[0, 1]) / (dSize[1, 1] - dSize[0, 1]))));
}
}
/// <summary>
/// Size of canvas
/// </summary>
public int[] CanvasSize
{
get
{
return size;
}
}
/// <summary>
/// Resizes itself
/// </summary>
public void Resize()
{
if (control != null)
{
size[0] = control.Width - insets[0, 0] - insets[1, 0];
size[1] = control.Height - insets[0, 1] - insets[1, 1];
image = new Bitmap(size[0], size[1]);
iTemp = new Bitmap(size[0], size[1]);
}
else
{
image = new Bitmap(size[0], size[1]);
iTemp = new Bitmap(size[0], size[1]);
Image im = image;
Graphics g = Graphics.FromImage(im);
Color back = bkgnd;
g.FillRectangle(new SolidBrush(back), 0, 0, im.Width, im.Height);
g.Dispose();
im = iTemp;
g = Graphics.FromImage(im);
g.FillRectangle(new SolidBrush(back), 0, 0, im.Width, im.Height);
g.Dispose();
}
CalculateSize();
}
/// <summary>
/// Bitmap
/// </summary>
public Image Image
{
get
{
Bitmap bitmap = new Bitmap(size[0] + insets[0, 0] + insets[1, 0],
size[1] + insets[0, 1] + insets[1, 1]);
Paint();
Graphics g = Graphics.FromImage(bitmap);
g.FillRectangle(new SolidBrush(backColor), 0, 0, bitmap.Width, bitmap.Height);
g.DrawImage(image, insets[0, 0], insets[0, 1]);
if (coordPainter != null)
{
coordPainter.DrawCoord(g, insets, dSize, size);
}
g.Dispose();
return bitmap;
}
}
/// <summary>
/// Paints itself
/// </summary>
public void Paint()
{
if (image == null)
{
return;
}
Brush brush = new SolidBrush(bkgnd);
Graphics gi = Graphics.FromImage(image);
gi.FillRectangle(brush, 0, 0, image.Width, image.Height);
for (int i = 0; i < 2; i++)
{
for (int j = 0; j < 2; j++)
{
if (Double.IsNaN(dSize[i, j]))
{
return;
}
}
}
if (coordPainter != null)
{
coordPainter.DrawCoord(gi, dSize, size);
}
for (int i = 0; i < Count; i++)
{
ISeries s = this[i];
ISeriesPainter p = null;
if (painters.ContainsKey(s))
{
p = painters[s];
}
else
{
p = new SimpleSeriesPainter(this, Color.Black);
painters[s] = p;
}
if (p != null)
{
p.Draw(s, gi);
}
}
//drawHistograms(gi);
gi.Dispose();
gi = Graphics.FromImage(iTemp);
gi.DrawImage(image, 0, 0);
gi.Dispose();
}
/// <summary>
/// Paints itself
/// </summary>
/// <param name="g">Graphics to paint</param>
public void Paint(Graphics g)
{
if (image == null)
{
return;
}
g.DrawImage(iTemp, insets[0, 0], insets[0, 1]);
for (int i = 0; i < 2; i++)
{
for (int j = 0; j < 2; j++)
{
if (Double.IsNaN(dSize[i, j]))
{
return;
}
}
}
if (coordPainter != null)
{
if (control != null)
{
coordPainter.ClearInsets(control, insets);
Graphics gc = Graphics.FromHwnd(control.Handle);
coordPainter.DrawCoord(gc, insets, dSize, size);
gc.Dispose();
}
}
}
/// <summary>
/// Performs all refresh operations
/// </summary>
public virtual void RefreshAll()
{
Resize();
CalculateSize();
Paint();
if (coordPainter != null)
{
if (control != null)
{
coordPainter.ClearInsets(control, insets);
}
}
if (control != null)
{
Graphics g = Graphics.FromHwnd(control.Handle);
Paint(g);
}
}
/// <summary>
/// Refreshs itself
/// </summary>
public void Refresh()
{
//Resize();
//CalculateSize();
Paint();
if (coordPainter != null)
{
if (control != null)
{
coordPainter.ClearInsets(control, insets);
}
}
if (control != null)
{
control.Refresh();
}
}
/// <summary>
/// The temporary buffer
/// </summary>
public Image Buffer
{
get
{
return iTemp;
}
}
/// <summary>
/// Physical - screen transformation
/// </summary>
/// <param name="x">Physical x - coordinate</param>
/// <param name="y">Physical y - coordinate</param>
/// <param name="p">Screen coordinates</param>
public void Transform(double x, double y, int[] p)
{
if (invertX)
{
p[0] = (int)((double)size[0] * ((x - dSize[1, 0]) / (dSize[0, 0] - dSize[1, 0])));
}
else
{
p[0] = (int)((double)size[0] * ((x - dSize[0, 0]) / (dSize[1, 0] - dSize[0, 0])));
}
if (invertY)
{
p[1] = size[1] - (int)((double)size[1] * ((y - dSize[1, 1]) /
(dSize[0, 1] - dSize[1, 1])));
}
else
{
p[1] = size[1] - (int)((double)size[1] * ((y - dSize[0, 1]) /
(dSize[1, 1] - dSize[0, 1])));
}
}
/// <summary>
/// On mouse down event handler
/// </summary>
/// <param name="sender">The sender</param>
/// <param name="e">The event arguments</param>
protected void onMouseDown(object sender, MouseEventArgs e)
{
xp = e.X - insets[0, 0];
yp = e.Y - insets[0, 1];
isMoved = true;
}
/// <summary>
/// Draws histogram
/// </summary>
/// <param name="o">Histogram object</param>
/// <param name="g">Graphics</param>
protected void drawHistogram(object[] o, Graphics g)
{
double[,] hist = (double[,])o[0];
Color color = (Color)o[1];
double step = hist[1, 0] - hist[0, 0];
double[] x = new double[2];
int[] il = new int[2];
int[] ir = new int[2];
Pen pen = new Pen(Color.Black);
Brush brush = new SolidBrush(color);
for (int i = 0; i < hist.GetLength(0); i++)
{
x[0] = hist[i, 0];
x[1] = hist[i, 1];
Transform(x, il);
x[0] += step;
x[1] = 0;
Transform(x, ir);
int w = ir[0] - il[0];
int h = ir[1] - il[1];
g.FillRectangle(brush, il[0], il[1], w, h);
g.DrawRectangle(pen, il[0], il[1], w, h);
}
}
/// <summary>
/// Draws all histograms
/// </summary>
/// <param name="g">Graphics to draw</param>
/* protected void drawHistograms(Graphics g)
{
foreach (object[] o in histograms)
{
drawHistogram(o, g);
}
}*/
/// <summary>
/// On mouse up event handler
/// </summary>
/// <param name="sender">The sender</param>
/// <param name="e">The event arguments</param>
protected void onMouseUp(object sender, MouseEventArgs e)
{
if ((xp < xc) & (yp < yc))
{
double xb = dSize[0, 0];
double xd = dSize[1, 0] - dSize[0, 0];
dSize[0, 0] = xb + (double)xp * xd / (double)(size[0]);
dSize[1, 0] = xb + (double)xc * xd / (double)(size[0]);
double yb = dSize[1, 1];
double yd = dSize[1, 1] - dSize[0, 1];
dSize[0, 1] = yb - (double)yc * yd / (double)(size[1]);
dSize[1, 1] = yb - (double)yp * yd / (double)(size[1]);
Refresh();
}
else
{
RefreshAll();
}
Graphics g = Graphics.FromImage(iTemp);
g.DrawImage(image, 0, 0);
g.Dispose();
isMoved = false;
}
/// <summary>
/// On mouse leave event handler
/// </summary>
/// <param name="sender">The sender</param>
/// <param name="e">The event arguments</param>
protected void onMouseLeave(object sender, EventArgs e)
{
if (isMoved)
{
RefreshAll();
isMoved = false;
}
}
/// <summary>
/// On mouse move event handler
/// </summary>
/// <param name="sender">The sender</param>
/// <param name="e">The event arguments</param>
protected void onMouseMove(object sender, MouseEventArgs e)
{
if (!isMoved)
{
return;
}
xc = e.X - insets[0, 0];
yc = e.Y - insets[0, 1];
int xmin, ymin, xmax, ymax;
if (xp > xc)
{
xmin = xc;
xmax = xp;
}
else
{
xmin = xp;
xmax = xc;
}
if (yp > yc)
{
ymin = yc;
ymax = yp;
}
else
{
ymin = yp;
ymax = yc;
}
Graphics g = Graphics.FromImage(iTemp);
dR.X = xmin - DELTA;
dR.Y = ymin - DELTA;
dR.Width = 2 * DELTA + xmax - xmin;
dR.Height = 2 * DELTA + ymax - ymin;
sR.X = xmin - DELTA;
sR.Y = ymin - DELTA;
sR.Width = 2 * DELTA + xmax - xmin;
sR.Height = 2 * DELTA + ymax - ymin;
g.DrawImage(image, dR, sR, GraphicsUnit.Pixel);
g.DrawRectangle(linePen, xmin, ymin, xmax - xmin, ymax - ymin);
g.Dispose();
g = Graphics.FromHwnd(control.Handle);
dR.X = xmin - DELTA + insets[0, 0];
dR.Y = ymin - DELTA + insets[0, 1];
dR.Width = 2 * DELTA + xmax - xmin;
dR.Height = 2 * DELTA + ymax - ymin;
sR.X = xmin - DELTA;
sR.Y = ymin - DELTA;
sR.Width = 2 * DELTA + xmax - xmin;
sR.Height = 2 * DELTA + ymax - ymin;
g.DrawImage(iTemp, dR, sR, GraphicsUnit.Pixel);
g.Dispose();
}
/// <summary>
/// Resizes histogram
/// </summary>
/// <param name="o">Diagram object</param>
protected void resizeHistogram(object[] o)
{
double[,] hist = o[0] as double[,];
if (hist[0, 0] < dSize[0, 0])
{
dSize[0, 0] = hist[0, 0];
}
double a = hist[hist.GetLength(0) - 1, 0] + hist[1, 0] - hist[0, 0];
if (a > dSize[1, 0])
{
dSize[1, 0] = a;
}
if (dSize[0, 1] > 0)
{
dSize[0, 1] = 0;
}
for (int i = 0; i < hist.GetLength(0); i++)
{
a = hist[i, 1];
if (dSize[1, 1] < a)
{
dSize[1, 1] = a;
}
}
}
/// <summary>
/// Resizes all histograms
/// </summary>
/* protected void resizeHistograms()
{
foreach (object[] o in histograms)
{
resizeHistogram(o);
}
}*/
/// <summary>
/// Background color
/// </summary>
protected Color bkgnd
{
get
{
if (control != null)
{
return control.BackColor;
}
return backColor;
}
}
}
}