# Новые средства языка. Индексаторы. Делегат на основе обычного метода класса. Делегаты на основе класса MulticastDelegate, страница 13

public Point2D (float xx, float yy) { x = xx;  y = yy; }

public static Point2D operator+ (Point2D p1, Point2D p2)

{

return new Point2D (p1.x + p2.x, p1.y + p2.y);

}

public static Point2D operator- (Point2D p1, Point2D p2)

{

return new Point2D (p1.x - p2.x, p1.y - p2.y);

}

public static Point2D operator* (Point2D pt, float d)

{

return new Point2D (pt.x * d, pt.y * d);

}

public static float operator* (Point2D p1, Point2D p2)

{

return p1.x * p2.x + p1.y * p2.y;

}

//======= Convert to integer

public Point ToInt()

{

Point p = new Point();

p.X = (int)x; p.Y = (int)y;

return  p;

}

//====== Vector norm

public static float operator! (Point2D pt)

{

return (float)Math.Sqrt (pt.x*pt.x + pt.y*pt.y);

}

public float Dist (Point2D pt)

{

float

dx = x - pt.x,

dy = y - pt.y;

return (float)Math.Sqrt (dx*dx + dy*dy);

}

public float Cos (Point2D pt)

{

return this * pt / (!this * !pt);

}

}

public class MainForm : Form

{

private Container components = null;

private PictureBox pbPos;

private PictureBox pbNeg;

private Label lblPercent;

private ProgressBar progress;

private Plot.PlotControl plot;

public uint nodes;     // Количество узлов сетки

public float charge;   // Величина зарядов диполя

public Point2D pPos, pNeg, pFirst, pLast;

private PointF[] points; // Массив координат точек графика

private bool isDragging = false;

private bool isCalculating = false;

private int x0, y0, x, y;

private Point org;

private Pen penFixed = new Pen (Color.Black, 1);

private Pen penDrag = new Pen (Color.Tan, 0);

private string title = "Electrostatic field";

public uint Nodes

{

get { return nodes; }

set

{

if (value < 4 || 1000 < value)

MessageBox.Show ("Количество узлов должно быть в диапазоне (4, 1000)");

else

nodes = value;

}

}

private void SetDefaults()

{

nodes = 200;

charge = 1e-6f / (4 * (float)Math.PI * 8.85e-12f);

points = new PointF[nodes];

}

public MainForm()

{

InitializeComponent();

SetDefaults();

SetStyle(

ControlStyles.UserPaint |

ControlStyles.AllPaintingInWmPaint |

ControlStyles.DoubleBuffer, true);

int  w = pbPos.Width / 2,

h = pbPos.Height / 2,

y = pbPos.Location.Y,

dx = 140;

org.X = ClientRectangle.Right / 2;

org.Y = y + h;

pbNeg.Location = new Point (org.X + dx - w, y);

pbPos.Location = new Point (org.X - dx - w, y);

pPos = new Point2D (-dx, 0);

pNeg = new Point2D ( dx, 0);

}

private void Draw (Graphics g)

{

g.DrawLine (isDragging ? penDrag : penFixed, x0, y0, x, y);

if (!isDragging)

{

g.FillEllipse (Brushes.Black, x0-4, y0-4, 8, 8);

g.FillEllipse (Brushes.Black, x-4, y-4, 8, 8);

}

}

private void MainForm_MouseDown (object sender, MouseEventArgs e)

{

if (!isCalculating)

{

x0 = e.X; y0 = e.Y;

pFirst = new Point2D (x0-org.X, y0-org.Y);

isDragging = true;

Text = title + String.Format (", x = {0}, y = {1}", x, y);

}

}

private void MainForm_MouseMove (object sender, MouseEventArgs e)

{

if (isDragging)

{

x = e.X; y = e.Y;

Invalidate();

Text = title + String.Format (", x = {0}, y = {1}", x, y);

}

}

private void MainForm_MouseUp (object sender, MouseEventArgs e)

{

if (isDragging)

{

x = e.X; y = e.Y;

pLast = new Point2D (x-org.X, y-org.Y);

isDragging = false;

Graphics g = Graphics.FromHwnd(Handle);

Draw(g);

CalcField field = new CalcField (this, new ProgressHandler(OnProgress));

isCalculating = true;

progress.Show();

lblPercent.Show();

}

}

public void OnProgress (int id, PointF pt)

{

int pos = (int) Math.Ceiling (100 * (double)id / nodes);

progress.Value = pos;

lblPercent.Text = pos.ToString() + '%';

points[id] = pt;

if (id == nodes - 1)

{

plot.Graph.SetData (points,

"Electrostatic field along the line (v/m)", "dist (m)");

plot.Invalidate();

isCalculating = false;

progress.Hide();

lblPercent.Hide();

}

}

protected override void OnPaint(PaintEventArgs e)

{

Draw (e.Graphics);

}

// Здесь следуют Dispose, Windows Form Designer generated code и Main

}