Нарисуйте анимированный эпитрохоид в C#
В этом примере показан один из способов рисования анимированного эпитрохоида. (См. Пример для объяснения того, как нарисуйте эпитрохоид.) Эта программа генерирует все точки, необходимые для рисования полной кривой. Затем каждый раз, когда срабатывает его Timer, он набирает точки до определенной позиции в списке точек. Чтобы нарисовать круги, которые генерируют кривую, он также сохраняет углы, которые используются для генерации точек.
Программа использует следующий код для сохранения точек и углов.
// Точки кривой.
private PointF[] Points = null;
private float[] Thetas = null;
...
// Делаем точки кривой.
private void MakeEpitrochoidPoints(
float a, float b, float h, float dt)
{
// Вычислить значение остановки для t.
float stop_t = (float)(b * 2 * Math.PI);
// Найти точки.
List point_list = new List();
List theta_list = new List();
point_list.Add(new PointF(X(a, b, h, 0), Y(a, b, h, 0)));
theta_list.Add(0);
for (float t = dt; t <= stop_t; t += dt)
{
point_list.Add(new PointF(X(a, b, h, t), Y(a, b, h, t)));
theta_list.Add(t);
}
point_list.Add(new PointF(X(a, b, h, 0), Y(a, b, h, 0)));
theta_list.Add(0);
Points = point_list.ToArray();
Thetas = theta_list.ToArray();
}
// Параметрическая функция X (t).
private float X(float a, float b, float h, float t)
{
return (float)((a + b) * Math.Cos(t) -
h * Math.Cos(t * (a + b) / b));
}
// Параметрическая функция Y (t).
private float Y(float a, float b, float h, float t)
{
return (float)((a + b) * Math.Sin(t) -
h * Math.Sin(t * (a + b) / b));
}
Метод MakeEpitrochoidPoints вычисляет значения угла, который он должен пересечь, чтобы нарисовать всю кривую. Затем он перебирает эти значения, сохраняя точки кривой и углы в списках. Он заканчивается путем преобразования списков в массивы.
Методы X и Y - это параметрические функции, которые генерируют кривую.
Следующий код показывает, как программа рисует кривую.
// Нарисуем еще одну точку.
private void tmrDraw_Tick(object sender, EventArgs e)
{
MaxPointToDraw++;
if (MaxPointToDraw >= Points.Length - 1)
{
tmrDraw.Enabled = false;
Cursor = Cursors.Default;
}
picCanvas.Refresh();
}
// Рисуем эпитрохоид.
private void picCanvas_Paint(object sender, PaintEventArgs e)
{
e.Graphics.Clear(picCanvas.BackColor);
if (Points == null) return;
e.Graphics.SmoothingMode = SmoothingMode.AntiAlias;
// Масштаб и центр.
float scale = Math.Min(
picCanvas.ClientSize.Width * 0.45f,
picCanvas.ClientSize.Height * 0.45f);
e.Graphics.ScaleTransform(
scale / (a + b + h), scale / (a + b + h));
e.Graphics.TranslateTransform(
picCanvas.ClientSize.Width / 2,
picCanvas.ClientSize.Height / 2,
MatrixOrder.Append);
// Нарисуем круги.
using (Pen black_pen = new Pen(Color.Black, 0))
{
// Внутренний круг.
e.Graphics.DrawEllipse(black_pen, -a, -a, 2 * a, 2 * a);
// Внешняя окружность.
float theta = Thetas[MaxPointToDraw];
float cx = (float)((a + b) * Math.Cos(theta));
float cy = (float)((a + b) * Math.Sin(theta));
e.Graphics.DrawEllipse(black_pen,
cx - b, cy - b, 2 * b, 2 * b);
// Линейный сегмент.
e.Graphics.DrawLine(black_pen, cx, cy,
Points[MaxPointToDraw].X, Points[MaxPointToDraw].Y);
}
// Рисуем кривую.
using (Pen white_pen = new Pen(Color.White, 0))
{
for (int i = 0; i < MaxPointToDraw; i++)
{
e.Graphics.DrawLine(white_pen,
Points[i], Points[i + 1]);
}
}
}
Когда срабатывает Timer, он увеличивает MaxPointToDraw, чтобы нарисовать другую точку, а затем обновляет picCanvas PictureBox.
