65.9K
CodeProject 正在变化。 阅读更多。
Home

Hypocycloid

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.87/5 (48投票s)

2009 年 12 月 22 日

CPOL

3分钟阅读

viewsIcon

64537

downloadIcon

597

一个 Windows Forms 控件,用于模拟内摆线的行为。

引言

数学问题本身就有一种魅力。 此外,它们有助于培养程序员的技能。 在这里,我们描述一个学生的考试任务:“开发一个模拟内摆线的应用程序”。

App.jpg

背景

摆线是由圆轮边缘上的一个点在圆轮沿直线滚动时所经过的路径定义的曲线。 它由伽利略于 1599 年命名 (http://en.wikipedia.org/wiki/Cycloid)。

内摆线是由一个小圆在一个大圆内滚动时,小圆上一个固定点的轨迹生成的曲线。 它与摆线类似,但不同之处在于,圆不是沿直线滚动,而是在圆内滚动。

使用 Google 查找 Eli Maor 的一本精彩书籍,Trigonometric Delights(新泽西州普林斯顿)。 以下段落摘自本书。

我相信程序开发人员必须热爱公式推导。 因此,让我们找到内摆线的参数方程。

Hypocycloid.png

半径为 r 的圆上的一个点在半径为 R 的固定圆的内侧滚动。 令 C 为滚动圆的中心,P 为移动圆上的一个点。 当滚动圆顺时针旋转一个角度时,C 会逆时针方向绘制一个角宽度为 t 的弧。 假设运动从 P 与固定圆接触时开始(左图),我们选择一个坐标系,其中原点位于 O 处,x 轴指向 PP 相对于 C 的坐标是

(r cos b; -r sin b)

第二个坐标中的负号是因为 b 是顺时针测量的。 C 相对于 O 的坐标是

((R - r) cos t, (R - r) sin t)

注意,角度 b 可以表示为

b = t + β; β = b - t

因此,P 相对于 O 的坐标是

((R - r) cos t + r cos β, (R - r) sin t - r sin β) (1)

但是角度 tb 不是独立的:随着运动的进行,固定圆和移动圆接触的弧的长度必须相等 L

L = R t L = r b

使用此关系式将 b 表示为 t,我们得到

b = R t / r

方程 (1) 变为

x = (R - r) cos t + r cos ((R / r - 1) t) (2)
y = (R - r) sin t - r sin ((R / r - 1) t)

方程 (2) 是内摆线的参数方程,角度 t 是参数(如果滚动圆以恒定的角速度旋转,则 t 将与运动开始后经过的时间成正比)。 曲线的一般形状取决于比率 R/r。 如果这个比率是一个最简分数 m/n,则曲线将有 m 个尖点(角),并且在车轮围绕内缘移动 n 次后将完全描绘出来。 如果 R/r 是无理数,则曲线永远不会闭合,尽管围绕边缘移动多次几乎可以闭合它。

使用代码

本文提供的演示应用程序使用从 UserControl 派生的 Hypocycloid 控件来模拟上述内摆线的行为。

内摆线的功能在 Hypocycloid 类中实现。 它有一个 GraphicsPath path 数据字段,用于帮助随着时间的推移渲染内摆线路径。 浮点变量 angle 对应于前面描述的角度 t

  • 变量 ratio = R / r
  • delta = R - r

所有数学运算都在计时器 Tick 事件处理程序中完成。

void timer_Tick(object sender, EventArgs e)
{
   angle += step;
   double
    cosa = Math.Cos(angle),
    sina = Math.Sin(angle),
    ct = ratio * angle;

   movingCenter.X = (float)(centerX + delta * cosa);
   movingCenter.Y = (float)(centerY + delta * sina);
   PointF old = point;
   point = new PointF(
     movingCenter.X + r * (float)Math.Cos(ct),
     movingCenter.Y - r * (float)Math.Sin(ct));
   int n = (int)(angle / pi2);
   if (n > round)
   {
     round = n;
     ParentNotify(msg + ";" + round);
   }
   if (round < nRounds)
    path.AddLine(old, point);
   else if (!stopPath)
   {
     ParentNotify(msg + ";" + round + ";" + path.PointCount);
     stopPath = true;
   }
   parent.Invalidate();
}

ParentNotify 是通用委托类型 Action<string> 的事件。

public event Action<string> ParentNotify;

我们使用它来通知父控件当前角度(圆形)。

除了构造函数之外,该类还具有以下公共方法:ResetDrawStartStopSaveToFile。 还要记住,Windows 窗口中的 Y 轴向下。

Hypocycloid - CodeProject - 代码之家
© . All rights reserved.