Нарисуйте анимированный эпитрохоид в C#
В этом примере показан один из способов рисования анимированного эпитрохоида. (См. Пример
Программа использует следующий код для сохранения точек и углов.
// Точки кривой. 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); // Найти точки. Listpoint_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.