WPF 太阳轮齿用于 Spirograph 生成器
引言
九年前,我父亲送了我一套出色的原创 Meccano 金属结构系统,这让我至今仍痴迷于机械系统。六年之后,我拥有了第一台连接电视的家用电脑,开始用 BASIC 语言编写一些关于力学和解析几何问题的代码。其中之一就是模拟点在行星齿轮上的运动并生成漂亮的形状。最近,我回想起这段代码,想把它作为一篇有用的文章发布,但遗憾的是,我在网上找到了一个类似的文章,它使用的方程比我之前推导的更简单。所以...
y(t) = A Sin(n t) (on polar coordinates)
因此,我决定添加一些新东西,而且花费的时间也不多。我添加了第三个额外的齿轮,使其位于第二个齿轮内部,第二个齿轮又位于第一个齿轮内部,看看会产生什么结果,这非常令人印象深刻,如图所示。
这些形状并非毫无意义,就像我们中的一些人可能认为的那样,通过简单的方程,游戏和图形设计师可以生成如此复杂的形状,装饰设计师也可以做到。在一个大医院的入口处,我看到其中一个地板是由水射流切割机制作的弯曲马赛克花岗岩瓷砖。如果您想增加您的知识,请参考以下链接:
http://en.wikipedia.org/wiki/Mohamed_Hashish,(磨料水射流切割发明者)
https://www.flickr.com/search/?q=spirograph,
http://www.syrstone.com/Syrstone/Award_WINNING_Culinary_Institute.html,
它还可以用于在织物上打印图案、设计徽标等...
您也可以参考以下视频:
背景
这是一张简单的行星齿轮与齿圈啮合的图片,它的名字来源于它与行星围绕彼此运动的相似性。现在想象一下,内侧的红色臂被迫围绕齿圈的中心旋转,这将使行星齿轮也围绕其自身中心旋转,两个旋转之间有一个固定的比例。
seta_2 = seta_1 * R1 / R2 * slider4.Value;
此比例可以通过 slider4
的值来改变。
此比例来自旋转角度(以弧度为单位)的方程。
Ɵ = 该弧相对于此角度 / 半径。
由于两个齿轮啮合,因此它们扫过的弧是相同的,所以:
Arc1 = Arc2
Ɵ1 / R1= Ɵ2 / R2 ................ 如代码所示( seta_2/R2= seta1/R1 )
请查看以下图表,让我们描述行星齿轮的蓝色中心点相对于齿圈的黑色中心点的位置。
此位置可以用笛卡尔平面中点 P(x2,y2) 的分量来描述,如下所示:
X2 = R1 * Math.Cos(seta_1) + R2 * Math.Cos(seta_2) + X1; Y2 = R1 * Math.Sin(seta_1) + R2 * Math.Sin (seta_2) + Y1;
其中
R1 是第一个半径。
R2 是第二个半径。
Ɵ1 红色角度是臂的旋转角度。
Ɵ2 绿色角度是行星齿轮的旋转结果角度,可以是(seta_2 = seta_1 * R1 / R2)。
将旋转的红点相对于红角 Ɵ1 的位置绘制出来,将产生此类 Spirograph 形状。
现在,让我们引入一个额外的齿轮,如果我们把这个齿轮组件放进一个大的齿圈里,我们就会在里面有两个旋转的齿轮,如下图所示。
红点相对于新齿轮中心的相对位置可以通过向量 R1
、R2
、R3
的和来计算,或者可以如下计算:
X3 = R2 * Math.Cos(seta_2) + R3 * Math.Cos(seta_3) + X2; Y3 = R2 * Math.Sin(seta_2) + R3 * Math.Sin(seta_3) + Y2;
绘制此方程计算点位置 X3
、Y3
相对于 seta1
,并改变其参数,将产生这些令人惊叹的新图形。
Using the Code
大部分代码都很容易理解,但让我们在此重点介绍以下几行:
让我们摆脱齿轮的齿,让行星齿轮以 seta1 的比例旋转和滑动,从而产生新的形状,所以重新计算如下:
seta_2 = seta_1 * R1 / R2 * slider4.Value; seta_3 = seta_2 * R2 / R3 * slider5.Value;
这产生了以下效果:
字符串形状

奖牌形状
我添加了滑块来控制三个半径,但我注意到一个非常小的变化(可能在 0.1 的范围内)可能会改变形状,这里接下来是与此问题相关的一个有用原理。
有用原理
物理上,很难同时以非常高的精度控制大值中的任何物理量,通常精度仅限于一定范围,例如,要控制公里范围内的质量位置,您不能期望获得微米级别的精度。
同样,我们无法用手轻松地以十分之几的精度控制滑块的位置,所以我为每个“参数控制滑块”旁边添加了另一个滑块,以控制小数部分的值。
在所有这些滑块下方,您都可以找到一个 TextBlock 来显示滑块的值(Silder.Value),这些 TextBlock 的文本都绑定到其上方的滑块,如 TextBlock1 的示例代码所示。
<TextBlock Height="23" Name="textBlock1" Width="57" Text="{Binding Path=Value}" DataContext="{Binding ElementName=slider1}" Canvas.Left="10" Canvas.Top="606" />
渐变色也是一个想法,它能给图形带来阴影效果。
我们从中心向外移动时,通过添加以下行,蓝色会变暗:
double D = Math.Sqrt( Math.Pow(PtsX[n] - X1 , 2) + Math.Pow(PtsY[n] - Y1,2) ); Byte LineColor = (Byte) (180-((D *Scale)/ (canvas2.Height/2 )) * 140); myLine.Stroke = new SolidColorBrush(Color.FromRgb(00,LineColor,255));
我添加了最右边的两个滑块:“比例滑块”用于以不同大小查看形状,另一个是“历史滑块”。“历史滑块”的灵感来自于我很久以前在设计连接计算机并行端口的简单存储示波器电路时使用的类似想法,让计算机尽可能快地收集数据然后将其存储在数组中(不让它忙于绘制数据),这样就可以单独检查图形,查看发生了什么的历史记录,并且随着滑块的上下移动,可以回顾绘图的历史,您可以查看形状在绘制时的样子,以选择最好的一个。
最后,我倾向于用直线连接点而不是曲线,因为我发现它更容易绘制,速度也更快。您可以在下面的绘图循环中找到它,该循环绘制一系列有限的直线。
for (int n=1; n<cnt; n+=1) { myLine = new Line(); myLine.Stroke = System.Windows.Media.Brushes.Violet; double D = Math.Sqrt( Math.Pow(PtsX[n] - X1 , 2) + Math.Pow(PtsY[n] - Y1,2) ); Byte LineColor = (Byte) (180-((D *Scale)/ (canvas2.Height/2 )) * 140); myLine.Stroke = new SolidColorBrush(Color.FromRgb(00,LineColor,255)); myLine.X1 = PtsX[n-1] * Scale + canvas2.Width/2; myLine.Y1 = PtsY[n-1] * Scale + canvas2.Height/2; myLine.X2 = PtsX[n] * Scale + canvas2.Width/2; myLine.Y2 = PtsY[n] * Scale + canvas2.Height/2; myLine.StrokeThickness = 1; canvas2.Children.Add(myLine); }
应用以下滑块值并检查图形。
180 |
181 |
30 |
100 |
1 |
1 |
180 |
181 |
40 |
100 |
1 |
1 |
180 |
182 |
30 |
100 |
1 |
1 |
180 |
182 |
30 |
40 |
1.91 |
1.4 |
180 |
119.07 |
50.5 |
41 |
1.21 |
1.6 |
180 |
181 |
30.27 |
100 |
1 |
1 |
180 |
181 |
30.30 |
100 |
1 |
1 |
180 |
181 |
30.35 |
100 |
1 |
1 |
177 |
179 |
29.9 |
55.8 |
1 |
1 |
99 |
176 |
0 |
100 |
1 |
1 |
103 |
97 |
30 |
100 |
1 |
1 |
183 |
150 |
13.4 |
50 |
1 |
1 |
有许多想法可以添加以生成更多令人惊叹的形状,例如添加渐变色,这应该使其更加生动和奇妙,还可以改变线条笔触等等。
历史
第一段代码写于 27 年前,而这段代码是它的一个改进版本。