- Java锁的逻辑(结合对象头和ObjectMonitor)
- 还在用饼状图?来瞧瞧这些炫酷的百分比可视化新图形(附代码实现)⛵
- 自动注册实体类到EntityFrameworkCore上下文,并适配ABP及ABPVNext
- 基于Sklearn机器学习代码实战
原作: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 。
曲线艺术编程系列 第四章 。
确保您已知晓了最初一章中我们对示例代码的约定.
利萨茹曲线一直以来是我最喜欢的技术之一。除了循环的形状,实际上它可比看起来有用.
在这一篇中我们将覆盖它的基础知识,除此之外像往常一样,我们另外还得看看它在其它方面的应用.
利萨茹曲线又名利萨茹图形或鲍迪奇曲线。两个名字都来自于 19 世纪研究和撰写它们的人名.
这些曲线图形由上下左右来回摆动循环的长曲线形成。在它们在纯粹的形状时(译者注:没有复杂多余线条时),让我们想起常常在老式科幻电影中显示在示波器上发光的图形.
此番,在一开始我搜索利萨茹曲线相关题材时就找到了一个有用的参数方程.
x = A * sin(a * t + d)
y = B * sin(b * t)
有一个正弦波在 x 轴,另一个正弦波在 y 轴。 它们不会在某个方向上趋向无限,它在周期内自循环.
公式中变量挺多的。让我们分别看看.
A 和 B 最后影响的是曲线在 x 轴宽和 y 轴高。确切的讲,只是宽高的一半,因为会在它各自方向上延展.
t 是一个范围 在 0 到 2 * PI 的范围参数变量。尽管在真正执行时它在各自方向上会超出范围,但很快它就会返回回来。在 x 方程式中 t 乘以 a, y 方程式中 t 乘以 b ,然后在各自轴结果传入正弦函数。另外,在 x 方程式中参数 d 或者说 delta 变量用于把它移出相位.
此方程可能看起来像之前章节中我们接触的圆方程。如果我们将 A 和 B 设为相等并且把它当作 r ,并且将 a 和 b 设为 1,再去掉 d ,再用余弦代替 x 方程的 正弦函数,我们就得到了:
x = r * cos(t)
y = r * sin(t)
这就是原点在 0,0 的圆方程了。因为余弦就是正弦 +90 度,所以我们也可以说:
x = r * sin(t + d)
y = r * sin(t)
... 这个 d 就是 90 度 ,或者 PI / 2 弧度.
A 和 B 分开的情况你在椭圆方程里已经见过了, 在那里 A 我们叫作 '半径 x', B 就是 “半径 y” 。
x = A * sin(t + d)
y = B * sin(t)
所以当参数像上面那样同步变化,我们得到的是圆或椭圆,但当我们改动一些参数后,我们将得到了更有趣的曲线.
好了,说的够多了,开始编码吧。我们直接跳到创建一个利萨如函数。我会简化一下.
function liss(cx, cy, A, B, a, b, d) {
res = 0.01
for (t = 0; t < 2 * PI; t += res) {
x = cx + sin(a * t + d) * A
y = cy + sin(b * t) * B
lineTo(x, y)
}
closePath()
}
此处,分辨率变量 res 值不像之前在圆和椭圆函数内那样。在这里我给了一个很小的值,尽管它意味着画更多简单的小曲线。这样设定后从 0 到 2 * PI (6.28...), 从 0.01 开始增长将会得到 528 条线段,这对大多数例子来说足够用了(译者注:线段越多意味着越平滑)。如果曲线变的不平滑了,你就改这个值让线段变的更多。但我不打算深入测算到一个合适的值.
现在我们能用它画出来像下面这样调用:
width = 600
height = 600
canvas(600, 600)
liss(300, 300, 250, 250, 1, 1, PI / 2)
stroke()
这个图就像我上面说的那样,我把 A 和 B 设为相等的值,a 和 b 设为 1 并且 d 设为 PI / 2 。这样实际得到的结果就是一个圆形... 。
... 看,确实是圆.
让我们先将 d 设为 0 然后 a 和 b 稍后小变化一下子。 这里,将 a 和 b 分别设置为 2 和 1(再次 d 设为 0) 。
liss(300, 300, 250, 250, 2, 1, 0)
设为 2 和 3 时:
liss(300, 300, 250, 250, 2, 3, 0)
让我们调的更大一点,11 和 8 。
liss(300, 300, 250, 250, 11, 8, 0)
以上的这几个例子都中 d 都是 0, 波形都在自己轴的相位。现在我们保持 11 和 8 不变,将 d 变成 0.5, 移出它们的相位.
liss(300, 300, 250, 250, 11, 8, 0.5)
这里的动画是 a 为 6,b 为 7, d 持续变化时产生的图形变化 。
如果你希望你创建的曲线首尾丝滑的连接,那么没有什么 比 a 和 b 不是整数更糟的了(译者注:想丝滑需要 a 和 b 为整数)。 如果你将 a 设为 6.4,b 设为 7.3 。
liss(300, 300, 250, 250, 6.4, 7.3, 0)
如果你想看清楚点发生了啥,那么将 closePath 从函数内注释掉看看结果:
现在你可以看到曲线开始与结束点在随机位置, 而不是像 a 与 b 为整数时丝滑的连接起来.
当然,当你在这里使用小数时,你可以将变量 t 的范围从 0 到 2 * PI 继续放大到可以填满整个空间。 这里是我将 t 范围扩展到 20 * PI 的效果:
如果 a 和 b 你使用了有理数路径将最终又连接起来。 但可能会花点时间(译者注:如果是在动画中)。这个图中看起来就基本很接近了.
我们当然也能通过改变 A 和 B 这两个变量来获取宽的图形:
A = 250, B = 100 。
or tall figures
或高的 。
A = 100, B = 250 。
这就是绘制利萨茹图形最直接的方法。 可以查查维基百科与此相关的资料,学习一下这类曲线的多种属性。 我考虑在这里创建一个可交互的 demo, 但最后发现网上已经有很多了。文章最后我放了一些链接 。
取而代之的是,我们可以看看另外的应用方向.
此处不会像上面做的曲线动画一样,不讨论曲线自身的动画,但会利用利萨茹曲线的结果应用在某个对象上.
但,首先我们先聊一聊最基础的动画 。
通常你想在屏幕上对一个对象进行动画但又不想它超出屏幕, 让它上下左右的动,或者对它进行扭曲,变大,缩小。 你可能已经学习过一些 2D 图形变形属性,平移,旋转,缩放。 你可以用正弦或余弦函数计算结果值应用于这些变形属性,随着时间的推移改变那些函数方法的输入值就可以.
我们需要扩展一下我们的伪代码,它包含一个 loop 循环函数用于时刻进行不同绘制,它运行起来就是动画了。Processing (译者注:一个著名的图形库) 已经有内建的功能,其它图形系统也有类似的功能。但是你可能需要自己编写一个函数来实现这些功能。如果你用的是 HTML 和 javascript 的,那么我们可以使用 requestAnimationFrame 函数来实现.
我们假定它也拥有一个 clearCanvas 方法。我们可以把上一篇中编写的 circle 函数用到此处,或者使用你编码平台内置的绘图 api 。 我们像下面这样开始:
width = 400
height = 400
t = 0
canvas(width, height)
function loop() {
clearScreen()
circle(width / 2 + sin(t) * 100, height / 2, 20)
fill()
t += 0.1
}
这里将正弦中的 t 乘以 100 以获得圆在 x 轴上的偏移。当 t 持续增长时,这个圆会来回运动。你也可以简单的对 y 轴应用同样的效果。或者应用在半径上:
width = 400
height = 400
t = 0
canvas(width, height)
function loop() {
clearScreen()
circle(width / 2, height / 2, 50 + sin(t) * 20)
fill()
t += 0.1
}
此处,我们用 50 作为基础半径,加上使用 t 的正弦值乘以 20。由于 正弦值从 -1 到 +1 ,半径会加上 -20 到 +20 , 结果就是 30 至 70 之间摆动.
我们同样也可以将此应用在旋转属性上,但需要换一下图形,以便于我们可以观察到它的旋转。我把这个留给你自己实现吧.
回到绕圆运动。我们希望它绕整个 canvas 做圆周运行。我们一样可以使用正弦配合余弦完成圆周运动:
width = 400
height = 400
t = 0
canvas(width, height)
function loop() {
clearScreen()
circle(width / 2 + cos(t) * 100, height / 2 + sin(t) * 100, 20)
fill()
t += 0.1
}
假设我们希望它运动的更加自然该如何实现?我们可以为它添加一些随机运动,然后你会发现一个问题,如何保证它只在屏幕内运动。不难,我们可以使用利萨茹的公式来实现这一点,像下面这样:
width = 400
height = 400
t = 0
a = 13
b = 11
canvas(width, height)
function loop() {
clearScreen()
circle(width / 2 + sin(a * t) * 100, height / 2 + sin(b * t) * 100, 20)
fill()
t += 0.02
}
虽然这是一个不太完美的循环运动 gif 动画,但精神你肯定已经领会到了。这个圆看起来就像是随机绕着屏幕运动,但它实际是按利萨茹曲线路径运动。在我看来它就像是一只苍蝇在来回飞。事实上如果你多添加一些应用不同的参数的圆,那么它们会看起来更像一群苍蝇在飞。没有公分母的 a 和 b 数值设的越高,它在路径的运动看起来会更加随机.
下面这些图并非“标准官方”的图形,你可以在任何地方找到相关文档(可能我以前在某个地方提到过),但我始终觉得相互交流不同的创意是非常好的。你常常可以创造出一些独一无二的东西。所以我就放一些我自创的图在这里吧.
一些年前我曾经使用过利萨如曲线并尝试在不同的方式渲染它们。不仅仅是渲染它自己的路径,我决定用曲线上的每个相近点连接成线条。结果非常酷炫, 我将它们称为“利萨茹网络”。这里是一些例子:
你可以在这里找到更多 http://www.artfromcode.com/?p=657 。
我觉得它们看起来超酷。这些技术包含在了 Generative Design 这本书中 (信我) 。
随着我创意持续的进步, 我希望让它们更加的自然。 而不是仅仅给 a 和 b 添加乘数,我开始让这些参数变的随机一点。这会生成真正惊艳的图,我把它们称作“随机利萨茹网络” 。
它成为了我最爱欢迎作品这一。几年后我甚至被委托用此项技术设计一个系列印在红酒瓶上.
(译者注:红酒网站打不开...) 。
我就不再亮代码了。希望更多是对你的启发 -- 如何利用利萨茹曲线这一概念让颠覆事物让它变的更有趣.
下一章我们将聚焦在一些相关的系统上,它们同样使用非常有趣的方式创建曲线.
本章 Javascript 源码 https://github.com/willian12345/coding-curves/blob/main/examples/ch04/ 。
博客园: http://cnblogs.com/willian/ github: https://github.com/willian12345/ 。
最后此篇关于曲线艺术编程codingcurves第四章利萨茹曲线(LissajousCurves)的文章就讲到这里了,如果你想了解更多关于曲线艺术编程codingcurves第四章利萨茹曲线(LissajousCurves)的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。
我正在尝试打印 timeval 类型的值。实际上我可以打印它,但我收到以下警告: 该行有多个标记 格式“%ld”需要“long int”类型,但参数 2 的类型为“struct timeval” 程序
我正在编写自己的 unix 终端,但在执行命令时遇到问题: 首先,我获取用户输入并将其存储到缓冲区中,然后我将单词分开并将它们存储到我的 argv[] 数组中。IE命令是“firefox”以启动存储在
我是 CUDA 的新手。我有一个关于一个简单程序的问题,希望有人能注意到我的错误。 __global__ void ADD(float* A, float* B, float* C) { con
我有一个关于 C 语言 CGI 编程的一般性问题。 我使用嵌入式 Web 服务器来处理 Web 界面。为此,我在服务器中存储了一个 HTML 文件。在此 HTML 文件中包含 JavaScript 和
**摘要:**在代码的世界中,是存在很多艺术般的写法,这可能也是部分程序员追求编程这项事业的内在动力。 本文分享自华为云社区《【云驻共创】用4种代码中的艺术试图唤回你对编程的兴趣》,作者: break
我有一个函数,它的任务是在父对象中创建一个变量。我想要的是让函数在调用它的级别创建变量。 createVariable testFunc() [1] "test" > testFunc2() [1]
以下代码用于将多个连续的空格替换为1个空格。虽然我设法做到了,但我对花括号的使用感到困惑。 这个实际上运行良好: #include #include int main() { int ch, la
我正在尝试将文件写入磁盘,然后自动重新编译。不幸的是,某事似乎不起作用,我收到一条我还不明白的错误消息(我是 C 初学者 :-)。如果我手动编译生成的 hello.c,一切正常吗?! #include
如何将指针值传递给结构数组; 例如,在 txt 上我有这个: John Doe;xxxx@hotmail.com;214425532; 我的代码: typedef struct Person{
我尝试编写一些代码来检索 objectID,结果是 2B-06-01-04-01-82-31-01-03-01-01 . 这个值不正确吗? // Send a SysObjectId SNMP req
您好,提前感谢您的帮助, (请注意评论部分以获得更多见解:即,以下示例中的成本列已添加到此问题中;西蒙提供了一个很好的答案,但成本列本身并未出现在他的数据响应中,尽管他提供的功能与成本列一起使用) 我
我想知道是否有人能够提出一些解决非线性优化问题的软件包的方法,而非线性优化问题可以为优化解决方案提供整数变量?问题是使具有相等约束的函数最小化,该函数受某些上下边界约束的约束。 我已经在R中使用了'n
我是 R 编程的初学者,正在尝试向具有 50 列的矩阵添加一个额外的列。这个新列将是该行中前 10 个值的平均值。 randomMatrix <- generateMatrix(1,5000,100,
我在《K&R II C 编程 ANSI C》一书中读到,“>>”和“0; nwords--) sum += *buf++; sum = (sum >>
当下拉列表的选择发生变化时,我想: 1) 通过 div 在整个网站上显示一些 GUI 阻止覆盖 2)然后处理一些代码 3) 然后隐藏叠加层。 问题是,当我在事件监听器函数中编写此逻辑时,将执行 onC
我正在使用 Clojure 和 RESTEasy 设计 JAX-RS REST 服务器. 据我了解,用 Lisp 系列语言编写的应用程序比用“传统”命令式语言编写的应用程序更多地构建为“特定于领域的语
我目前正在研究一种替代出勤监控系统作为一项举措。目前,我设计的用户表单如下所示: Time Stamp Userform 它的工作原理如下: 员工将选择他/她将使用的时间戳类型:开始时间、超时、第一次
我是一名学生,试图自学编程,从在线资源和像您这样的人那里获得帮助。我在网上找到了一个练习来创建一个小程序来执行此操作: 编写一个程序,读取数字 a 和 b(长整型)并列出 a 和 b 之间有多少个数字
我正在尝试编写一个 shell 程序,给定一个参数,打印程序的名称和参数中的每个奇数词(即,不是偶数词)。但是,我没有得到预期的结果。在跟踪我的程序时,我注意到,尽管奇数词(例如,第 5 个词,5 %
只是想知道是否有任何 Java API 可以让您控制台式机/笔记本电脑外壳上的 LED? 或者,如果不可能,是否有可能? 最佳答案 如果你说的是前面的 LED 指示电源状态和 HDD 繁忙状态,恐怕没
我是一名优秀的程序员,十分优秀!