曲线艺术编程 coding curves 第六章 平托图 (Pintographs)

这篇具有很好参考价值的文章主要介绍了曲线艺术编程 coding curves 第六章 平托图 (Pintographs)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

第六章 平托图 (Pintographs)

原作:Keith Peters https://www.bit-101.com/blog/2022/11/coding-curves/

译者:池中物王二狗(sheldon)

blog: http://cnblogs.com/willian/

源码:github: https://github.com/willian12345/coding-curves

曲线艺术编程系列第 6 章

另一个可用于模拟绘制复杂曲线的物理装置叫平托图(Pintograph), 事实上我真的自己弄了一个。

我们将从一个视频开始--这个第一个按 Pintograph 字面意思在 Youtube 找上找到的视频

https://www.youtube.com/embed/1JyNLzdbcz4?feature=oembed

平托图也可以认为是谐波图的一种,但不像谐波图那样是基于钟摆原理,平托图通常是用电动机驱动的(尽管也有一些是手摇的)。一些圆盘连杆在电动机上,连杆又连接在圆盘上,笔又连接到连杆上。连杆上的圆盘尺寸、连杆长度、连接点位置你都可以自已改动,电机的相对速度与和偏移量可以创造出一大堆不同类型的曲线。

很长时间内我都不知道“pintograph”这个名字是怎么来的。最终发现是他创造了这个名词,事实上是他的女儿。它是从“缩放仪pantograph”演变而来,这些转动的轮子看起来像是一辆福特平托。阅读这里获取更多 http://www.fxmtech.com/harmonog.html

以防你对缩放仪(pantograph)不熟悉,我解释一下,这个装置是一般是用来复制绘图的。它有一些旋转的连杆。将一个轴点固定住,将指示器指向这些轴点中的其实一个点,另一头是固定的笔。 当你按原图移动指示器,另一头的笔就绘制出相同的形状。你可以用它复制同样的形状或者调整复制时的大小。这是维基百科对缩放仪(pantograph)的解释 https://en.wikipedia.org/wiki/Pantograph

模拟器

平托图模拟起来相当简单。它由两个旋转的转盘用各自的连杆连连接。在它的反方向上两根连杆连接在一起的点就是虚拟画笔的位置,

首先,我们得先模拟两个盘。它们拥有各自的 x, y 位置,半径,速度和相位。我们将两个盘都变成可视化以便让你知道到是如何运行的。另外它将会是一个非常长且复杂的公式。

我们将创建两个旋转的圆,且在圆周上显示那个连杆连接的点。

每个圆盘将用以下结构表示:

disk: {
  x,
  y,
  radius,
  speed,
  phase,
}

就像之前一样,我们不管它是一个通用对象、结构、类或其它什么的来表示。并且我假定你已经有一个函数用于创建返回这样的结构:

d0 = disk(100, 200, 100, 2, 0.5)
d1 = disk(400, 200, 60, 3, 0.0)

现在我们可以像下面这样设置一个动画:

width = 600
height = 400
canvas = (width, height)
t = 0
 
d0 = disk(100, 200, 100, 2, 0.5)
d1 = disk(400, 200, 60, 3, 0.0)
 
function loop() {
  clearScreen()
 
  circle(d0.x, d0.y, d0.radius)
  stroke()
  x0 = circle.d0.x + cos(t * d0.speed + d0.phase) * d0.radius
  y0 = circle.d0.y + sin(t * d0.speed + d0.phase) * d0.radius
  circle(x0, y0, 4)
  fill()
 
  circle(d0.x, d0.y, d0.radius)
  stroke()
  x1 = circle.d1.x + cos(t * d1.speed + d1.phase) * d1.radius
  y1 = circle.d1.y + sin(t * d1.speed + d1.phase) * d1.radius
  circle(x1, y1, 4)
  fill()
 
  t += 0.1
}

(译者注:注意原作者在伪代码中有个小错误,即下面 y0, y1 内也使用了 cos 来计算,我已将其改为 sin )

再一次强调一下,loop 是个假定的函数代表的是无限循环用于创建动画。我自己用代码实现了 loop 创建了一个帧动画,下面是我弄的 gif 图,但它也可以是一个实时动画:

曲线艺术编程 coding curves 第六章 平托图 (Pintographs)

它虽然不是那么丝滑,但不重要。我们有了两个不同大小、速度的圆。 代码本身并不复杂。我们先清空了屏幕,然后在两个圆的圆周位置上各自绘制一个圆。它用于连接连杆。这里应用基础的三角学:x = cos(angle) * radius, y = sin(angle) * radius, 角度是用 t * 速度 + 相位。 这样就得到了那两个点,我们用实心小圆代表。连接连杆并找到那根虚拟笔的位置

接下来事情变的更加数学化了。我们需要两个连接杆。每个连接杆都应该各自连接到一个旋转的点上。然后它们的另一端彼此相连。像下面草图画的那样:

曲线艺术编程 coding curves 第六章 平托图 (Pintographs)

两个圆盘。通过两个圆盘的半径,旋转和位置,这 p0 和 p1 也就知道了。这就是我们上面做的。 我们也可以直接定义连杆长度。它们现定义成等长, 它当然也可以不等长。 我们把它命名成 a0 和 a1.(我知道它们现在草图中看起来像 90 和 91 sorry!), 我们需要计算是的两个连杆连接点的位置。

p0 和 p1 之间的距离我们通过勾股定理很容易计算出来。我们把它命名为 d 。在图中用虚线表示。

现在我们拥有了一个三角形,每一边分别为 a0, a1 和 d。

这里有个三角法则叫“余弦定理”能帮我们。如果你知道三角形的三条边, a, b 和 c, 那么我们就可以计算得到三个角的角度。通常被写成下面这样:

c = sqrt(a*a + b*b - 2*a*b*cos(y))

y 是 c 边的对角。所以如果你知道两边的长度和它们的夹角,那么你就能算出它夹角的对边长度。尽管它非常有用,但我们这里暂时用不到。

我们可以重新整理公式,让未知道的变量在一边,另一边则是可计算的公式。

我们需要知道三个角中的其中一个角用于计算虚拟笔的位置。下面是我用余弦定理公式手动计算的代数结果公式。

曲线艺术编程 coding curves 第六章 平托图 (Pintographs)

在我们例子中,三边在余弦定理公式中对应关系如下:

a = a0
b = d
c = a1

应用公式后,我们就可以得到 角 p1-p0-pen 的夹角了.

我们也能用 atan2 得到 p0 到 p1 的角度。两者相关就得到了 p0 到 pen 的角度。

再次,展示下我画的草图

曲线艺术编程 coding curves 第六章 平托图 (Pintographs)

通过余弦定理得到 大角 p1 到 p0 到 pen 的夹角 我们把它命名为 p1_p0_pen. 通过 atan2 计算出的小的那个角命名为 p0toP1。相减后角的值,就指向虚拟笔的位置。我相信有很多种方式可以计算出这个角, 也许比我这种方式更好, 但我这种方式可以正常运行。你可以继续简化它,但我用详细的步骤用于说明,希望对你有帮助。

下面是代码部分:

width = 600
height = 600
canvas = (width, height)
t = 0
 
d0 = disk(150, 450, 100, 2, 0.5)
d1 = disk(450, 450, 60, 3, 0.0)
 
function loop() {
  clearScreen()
 
  circle(d0.x, d0.y, d0.radius)
  stroke()
  x0 = d0.x + cos(t * d0.speed + d0.phase) * d0.radius
  y0 = d0.y + sin(t * d0.speed + d0.phase) * d0.radius
  // (译者注:左侧大圆圆周上的小圆)
  circle(x0, y0, 4)
  fill()
  
  // (译者注:原作者此处 circle(d0.x, d0.y, d0.radius); 书写错误 ,应为 circle(d1.x, d1.y, d1.radius))
  circle(d1.x, d1.y, d1.radius)
  stroke()
  x1 = d1.x + cos(t * d1.speed + d1.phase) * d1.radius
  y1 = d1.y + sin(t * d1.speed + d1.phase) * d1.radius
  circle(x1, y1, 4)
  fill()
 
  // 连杆长度
  a0 = 350
  a1 = 350
 
  // p0 和 p1 距离
  dx = x1 - x0
  dy = y1 - y0
  d = sqrt(dx * dx + dy * dy)
 
  // 找到两个关键角相减
  p1_p0_pen = acos((a1 * a1 - a0 * a0 - d * d) / (-2 * a0 * d))
  p0toP1 = atan2(y1 - y0, x1 - x0)
  angle = p0toP1 - p1_p0_pen
 
  // 计算得到虚拟笔的位置
  //(译者注:左侧大圆圆周上的小圆位置和上面的angle 计算出虚拟笔的位置)
  pX = x0 + cos(angle) * a0
  pY = y0 + sin(angle) * a0
   
  // 绘制连杆
  moveTo(x0, y0)
  lineTo(pX, pY)
  lineTo(x1, y1)
  stroke()
 
  t += 0.1
}

按上面的代码正确编码后你应该可以渲染出如下的结果:

曲线艺术编程 coding curves 第六章 平托图 (Pintographs)

再次提醒,这只是不完整循环的 gif 图,仅用于演示如何运行。代码中每一步都有注释。希望对你有帮助。 注意我也改了 canvas 的宽高并且将圆盘位置调整到了底部腾出空间用于显示完整的连杆。

有一点需要注意,要确保连杆足够的长保证它们能彼此相连。在真实世界中,如果它们太短,可能会卡住或弄坏电动机。 在我们的模拟中,在反余弦函数计算 acos 可能会得到 NaN (not a number)错误,而你可能还摸不着头脑。我这是经验之谈。

绘制曲线

最后让我们看看画出个啥。在此,我把动画禁掉并且也不绘制圆和连杆 。我将追踪每次迭代虚拟笔的路径用于绘制一个长循环的具有利萨茹特征的曲线。

width = 800
height = 600
canvas = (width, height)
 
function render() {
  t = 0
   
  d0 = disk(250, 550, 141, 2.741, 0.5)
  d1 = disk(650, 550, 190, 0.793, 0.0)
 
  // the length of the arms
  a0 = 400
  a1 = 400
   
  for (i = 0; i < 50000; i++) {
    x0 = d0.x + cos(t * d0.speed + d0.phase) * d0.radius
    y0 = d0.y + sin(t * d0.speed + d0.phase) * d0.radius
 
    x1 = d1.x + cos(t * d1.speed + d1.phase) * d1.radius
    y1 = d1.y + sin(t * d1.speed + d1.phase) * d1.radius
 
    // get the distance between p0 and p1
    dx = x1 - x0
    dy = y1 - y0
    d = sqrt(dx * dx + dy * dy)
 
    // find the two key angles and subtract them
    p1_p0_pen = acos((a1 * a1 - a0 * a0 - d * d) / (-2 * a0 * d))
    p0toP1 = atan2(y1 - y0, x1 - x0)
    angle = p0toP1 - p1_p0_pen
 
    // find the pen point
    pX = x0 + cos(angle) * a0
    pY = y0 + sin(angle) * a0
   
    lineTo(pX, pY)
    t += 0.01
  }
  stroke()
}

我留了足够多的空间让你自己去优化代码,少年加油!尽管代码看起来乱糟糟的,但绘制结果它应该会像下图:

曲线艺术编程 coding curves 第六章 平托图 (Pintographs)

这里你可以尝试修改代码中的许多东西用于体验。这就是一个超简易的平托图,所以上面的图看起来大多都有点糙。但你可以依据这些原则创建各种更复杂的设备模拟。这个网站拥有许多 demo 相信可以启发你的思路:

https://michaldudak.github.io/pintograph/demo/

一个盘叠一个盘, 旋转的平托图,三个转盘的平托图,等等。

如果你想开始尝试,你只需要在 youtube 搜索 “harmonograph”, “pintograph” and “drawing machines” 等关键字,它会提供无限的点子给你----你可以用来编码或弄个真实的设备。在我看来最有趣的那一个例子是一个转台上自身慢慢旋转在一张纸上绘制出曲线。

总结

利萨茹曲线和相关的模拟装置讨论在这里就结束了。至少暂时就这样了。下一章我们将回归到比较基础的标准几何曲线。

本章 Javascript 源码 https://github.com/willian12345/coding-curves/blob/main/examples/ch06


博客园: http://cnblogs.com/willian/
github: https://github.com/willian12345/文章来源地址https://www.toymoban.com/news/detail-475632.html

到了这里,关于曲线艺术编程 coding curves 第六章 平托图 (Pintographs)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 曲线艺术编程 coding curves 第八章 贝赛尔曲线(Bézier Curves)

    原作:Keith Peters https://www.bit-101.com/blog/2022/11/coding-curves/ 译者:池中物王二狗(sheldon) blog: http://cnblogs.com/willian/ 源码:github: https://github.com/willian12345/coding-curves 曲线艺术编程系列第8章 贝赛尔曲线 让我们回到真正的曲线上来。贝赛尔曲线编程就非常有趣领人止不住的想探索一翻

    2024年02月08日
    浏览(56)
  • 曲线艺术编程 coding curves 第七章 抛物线(Parabolas)

    原作:Keith Peters https://www.bit-101.com/blog/2022/11/coding-curves/ 译者:池中物王二狗(sheldon) blog: http://cnblogs.com/willian/ 源码:github: https://github.com/willian12345/coding-curves 曲线艺术编程系列第7章 我承认这一章脑暴时,再三考虑过是否要将抛物线包含进来。此篇覆盖的抛物线比起之前三章

    2024年02月08日
    浏览(41)
  • 曲线艺术编程 coding curves 第五章 谐波图形(谐振图形) HARMONOGRAPHS

    原作:Keith Peters https://www.bit-101.com/blog/2022/11/coding-curves/ 译者:池中物王二狗(sheldon) blog: http://cnblogs.com/willian/ 源码:github: https://github.com/willian12345/coding-curves 曲线艺术编程系列第 5 章 这一篇幅建立在对第四章利萨茹曲线的讨论之上。事实上谐波图形并不是一类曲线,它是一

    2024年02月08日
    浏览(36)
  • 曲线艺术编程 coding curves 第三章 弧,圆,椭圆(ARCS, CIRCLES, ELLIPSES)

    原作:Keith Peters https://www.bit-101.com/blog/2022/11/coding-curves/ 译者:池中物王二狗(sheldon) blog: http://cnblogs.com/willian/ 源码:github: https://github.com/willian12345/coding-curves 曲线艺术编程系列第三章 这一篇中我们将关注如何绘制圆弧,圆和椭圆。(结束前再聊聊正切相关的) 很可能你使用

    2024年02月07日
    浏览(45)
  • Qt第六章 多窗口编程

    QMessageBox继承自QDialog ,是一个Qt内置的用来展示 信息或询问用户一个问题的模态对话框。 预设了四种类型: 像那些已经写好的窗口,这些现成的东西都会有一些特性,就是他们的对象都不需要new或者说他们就不需要拿到对象,他们为了方便我们使用会用一个静态成员函数就

    2024年02月07日
    浏览(39)
  • 《TCP IP网络编程》第六章

    UDP 套接字的特点:         通过寄信来说明 UDP 的工作原理,这是讲解 UDP 时使用的传统示例,它与 UDP 的特点完全相同。寄信前应先在信封上填好寄信人和收信人的地址,之后贴上邮票放进邮筒即可。当 然,信件的特点使我们无法确认信件是否被收到。邮寄过程中也可能

    2024年02月16日
    浏览(51)
  • java JUC并发编程 第六章 CAS

    第一章 java JUC并发编程 Future: link 第二章 java JUC并发编程 多线程锁: link 第三章 java JUC并发编程 中断机制: link 第四章 java JUC并发编程 java内存模型JMM: link 第五章 java JUC并发编程 volatile与JMM: link 第六章 java JUC并发编程 CAS: link 第七章 java JUC并发编程 原子操作类增强: link 第八章

    2024年02月10日
    浏览(47)
  • 《Python程序设计》 第六章 函数+编程题解

    目录 6-1 使用函数求特殊a串数列和 6-2 使用函数求素数和 6-3 使用函数统计指定数字的个数 6-4 使用函数输出指定范围内Fibonacci数的个数  6-5 使用函数求余弦函数的近似值 6-6 缩写词 7-1 输入列表,求列表元素和(eval输入应用) 7-2 一帮一 7-3 验证“哥德巴赫猜想” 7-4 列表或元组

    2024年02月07日
    浏览(66)
  • Qt编程基础 | 第六章-窗体 | 6.3、QTableWidget

    QTableWidget是QT中的表格组件类,一般用来展示多行多列的数据,是QT中使用较多的控件之一。QTableWidgetItem用来表示表格中的一个单元格,整个表格都需要用逐个单元格构建起来。 2.1、设置表格的行数与列数 2.2、添加单元格 2.3、表头设置 2.4、设置行表头、列表头是否显示 2.

    2024年02月13日
    浏览(44)
  • C Primer Plus第六章编程练习答案

    学完C语言之后,我就去阅读《C Primer Plus》这本经典的C语言书籍,对每一章的编程练习题都做了相关的解答,仅仅代表着我个人的解答思路,如有错误,请各位大佬帮忙点出! 1.编写一个程序,创建一个包含26个元素的数组,并在其中储存26个小 写字母。然后打印数组的所有

    2024年02月06日
    浏览(44)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包