曲线艺术编程 coding curves 第七章 抛物线(Parabolas)

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

抛物线 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章

我承认这一章脑暴时,再三考虑过是否要将抛物线包含进来。此篇覆盖的抛物线比起之前三章我们弄出来的复杂曲线相比非常的简单且基础的。但当我真的开始后才发现它也非常的酷,并且拥有很多有趣的特性。事实上,我一开始还打算将双曲线也包含在这一章, 但当我深入抛物线后,决定双曲线还是另找其它时间讲吧。

先确认一下我们讲的抛物线是像下面这样的:

曲线艺术编程 coding curves 第七章 抛物线(Parabolas)

学习抛物线之前你首先得知道它是圆锥截面的一种。由于我们仅在这里介绍二维曲线,它的三维形式有点不相关。你可以自行在维基百科上查询相关信息:

https://en.wikipedia.org/wiki/Parabola

自从我们讲了圆和椭圆,本章与下一章我将填坑所有相关的圆锥曲线。虽然这从未是目标,但我向来是搂草打兔子,能讲的就都讲了吧。

上面的第一张图,注意抛物线是 y 轴对称的,顶点(最高或最低点,取决于抛物线的开口方向)就是最接近 x 轴的点。

像大多数几何图形一样,有很多种公式可以描述它们。下面是一个相当简单易用的一个:

y = a * x * x

在这个式子中,a 参数是控制抛物线开口宽度的 - 无论开口是向上还是向下。相当简单。 先画个看看,但首先做些准备工作写一些通用函数。

准备工作

就如最上面那张图,我们希望原始位置位于 canvas 中心点以便完整显示抛物线。所以我们需要将 canvas 原点平移到那里。

当然,这也是很好的机会用于对比你使用的语言平台绘图 api 与 普通笛卡尔坐标系是否上下颠倒。换句话说, y 轴的值越大越向下,反之越向上。也就是说 y 坐标翻转过来就是普通笛卡尔。

最后,要是坐标轴能看到就更好了。我们可以简单的写个函数将轴画出来。

为了平移到 canvas 中心。你可能需要使用像下面这样的方法:

translate(width / 2, height / 2)

我假定你的绘图 api 内建了 translate 方法。好像老是解释这一点显的我有点啰嗦, 所以我假定你的绘图 api 常用方法都有内建支持了。

function center() {
  translate(width / 2, height / 2)
}

就像之前一样,这里用的是伪代码,无论你想在何种目标对象上绘制,都可以像这样调用这些方法。Processing 就是像这样写的 (译都注:Processing 图形库 processing.org) ,但其它系统中这些方法很有可能是在 canvas 对象下。它更可能像下面这样调用:

canvas.translate(canvas.width / 2, canvas.height / 2)

我肯定可以搞得定。

为了翻转 y 轴,你可以这样调用 scale:

scale(1, -1)

这能让 x 轴不变 y 轴翻转。好了,好了,在这个系列文章中有时候翻转有时候又不翻转。此系列文指在实践练习绘图课程,而非严密的数学教程。所以你应该知道啥时候翻转 canvas 啥时候不翻转了吧。

最后, 还要有一个函数用于绘制坐标轴。像下面这样:

function drawAxes() {
  lineWidth = 0.25
  moveTo(-width, 0)
  lineTo(width, 0)
  moveTo(0, -height)
  lineTo(0, height)
  stroke()
  lineWidth = 1
} 

此函数实现了横竖两条线且超过了 canvas 的边界,但问题不大。 线的宽度同样设置的很细,这仅仅是用来辅助的线条, 绘制完成后线宽重新设为 1。 在你的实际代码中有可能需要调用类似 pushing 和 popping 或 saving 和 restoring 这样的 api 用于canvas 的上下文状态管理, 以便于恢复到调用此函数之前的状态,因为它可能调用前的上下文状态线宽不是 1。

Ok, 现在可以设置 canvas 了:

width = 800
height = 800
canvas(width, height)
 
center()
scale(1, -1)
drawAxes()

下图就是这一番操作后的结果,这是一个好的开始:

曲线艺术编程 coding curves 第七章 抛物线(Parabolas)

你可能想将以上的代码整合到 setup 函数内。这取决于你自己。

绘制抛物线

在上面代码的基础上,我们可以用一个循环将 x 从左至右贯穿 canvas。我们将 a 设为很小的一个值比如 0.003 因为我们操作的是几百像素值。我选这个值是因为它让绘出的结果图在我们可视的 canvas 范围内

a = 0.003
for (x = -width / 2; x <= width / 2; x++) {
  y = a * x * x
  lineTo(x, y)
}
stroke()

这就是我们绘制的结果了:

曲线艺术编程 coding curves 第七章 抛物线(Parabolas)

如果将 a 值大,比如 0.3 , 我们会得到非常窄的抛物线:

曲线艺术编程 coding curves 第七章 抛物线(Parabolas)

如果变的更小,如 0.0003 , 我们会得到一个非常宽的抛物线:

曲线艺术编程 coding curves 第七章 抛物线(Parabolas)

技术上讲,你不应该将 a 值设为 0。如果你这么干了,那么你会得到一条直线。如果 a 变为负值,抛物线开口将会反向。这是 -0.003 :

曲线艺术编程 coding curves 第七章 抛物线(Parabolas)

这就是抛物线的全部了。

Oh, 等等。还有一些事情需要交待!

焦点与准线

抛物线还有一个熟知的知识点叫焦点。焦点的定义如下:

x = 0
y = 1 / (4 * a)

让我们把这个点画出来:

a = 0.003
for (x = -width / 2; x <= width / 2; x++) {
  y = a * x * x
  lineTo(x, y)
}
stroke()
 
// draw focus
focusX = 0
focusY = 1/(4 * a)
circle(focusX, focusY, 4)
fill()

曲线艺术编程 coding curves 第七章 抛物线(Parabolas)

还有另一个属性是准线。这是一条水平线用于表示 y 值:

y = -1 / (4 * a)

我们可以把它画出来:

a = 0.003
for (x = -width / 2; x <= width / 2; x++) {
  y = a * x * x
  lineTo(x, y)
}
stroke()
 
// 绘制焦点
focusX = 0
focusY = 1/(4 * a)
circle(focusX, focusY, 4)
fill()
 
// 绘制准线
directrixY = -1/(4 * a)
moveTo(-width / 2, directrixY)
lineTo(width / 2, directrixY)
stroke()

曲线艺术编程 coding curves 第七章 抛物线(Parabolas)

很明显,顶点距离焦点与准线的距离相等。因为 y 值的公式相等只是符号相反。

但这里有个有趣的事实 - 等距适用于抛物线上的任意一点(译者注:抛物线上的任意一到到焦点和焦点垂直到准线的距离相等)!我们能根据上面的代码展示出来...

lineWidth = 0.5
for (x = -width / 2; x <= width/2; x += 40) {
    // find a point on the parabola
    // 在抛物线上找到那个点
    y = a * x * x
    circle(x, y, 4)
    // draw a vertical line from the directrix to that point
    // then from the that point to the focus
    // 画一条线垂直于准线于那个点
    // 再将那个点连接至焦点
    moveTo(x, directrixY)
    lineTo(x, y)
    lineTo(0, focusY)
}

我们简单的从抛物线上采样了一些点。画出点,然后再从准线上画一条垂线到这个点,然后再连接到焦点。从点出发的两条线长度相等。可能没啥直接的实际用途,但它看起来还是巧妙的!

曲线艺术编程 coding curves 第七章 抛物线(Parabolas)

切线

另一个你能做的事情是找到抛物线上的任意点的切线。这个代表曲线在那个点上的斜率。切线点 x0, y0 公式:

y = 2 * a * x0 * x - a * x0 * x0

这里也许有一点点乱,因为我们即有 x 又有 x0, 再次提示 x0 是抛物线上的某个点,而 x 是定义切线点中的一个点。公式给出了x 对应的 y 。 让我们开始对曲线上的单个点进行编码吧。先画一个抛物线, 然后选择一个 x0, y0 点然后用公式找到另两个点用于绘制出切线。

// 抛物线
a = 0.003
for (x = -width / 2; x <= width / 2; x++) {
  y = a * x * x
  lineTo(x, y)
}
stroke()
 
// 找任意一个抛物线上的点
x = -80
y = a * x * x
circle(x, y, 4)
fill()
 
// 找一个远离 canvas 左边的点
x1 = -width / 2
y1 = 2 * a * x0 * x1 - a * x0 * x0
 

// 找一个远离 canvas 右边的点
x2 = width / 2
y2 = 2 * a * x0 * x2 - a * x0 * x0
 
// 画线
moveTo(x1, y1)
lineTo(x2, y2)
stroke()

我就就得到了如下的点与线:

曲线艺术编程 coding curves 第七章 抛物线(Parabolas)

现在我们可以像上面那样画出多条抛物线上面的切线。

lineWidth = 0.5
for (x0 = -width / 2; x0 <= width/2; x0 += 40) {
    // find a point on the parabola
    y0 = a * x0 * x0
    circle(x0, y0, 4)
    fill()
 
    // find a point on the far left of the canvas
    x1 = -width / 2
    y1 = 2 * a * x0 * x1 - a * x0 * x0
 
    // and one on the far right
    x2 = width / 2
    y2 = 2 * a * x0 * x2 - a * x0 * x0
 
    // and draw a line
    moveTo(x1, y1)
    lineTo(x2, y2)
    stroke()
}

代码很相似只是把它放到了循环内,然后结果是:

曲线艺术编程 coding curves 第七章 抛物线(Parabolas)

你可以将原始的抛物线条去掉并将间隔缩紧,然后你就可以得到一些伪线条艺术了

抛物面反射镜

另一个抛物线特性是射线打到抛物线后最后都会聚集到单一的一个点上。利用这个原理它一般被应用于天线和射电望远镜,将收到的信号聚集于接受器,各种各样的太阳能设备会将太阳光汇集于一点(这个点会异常的烫)。毫无疑问,这个汇集点就是抛物面的焦点。

曲线艺术编程 coding curves 第七章 抛物线(Parabolas)

https://en.wikipedia.org/wiki/Parabolic_antenna#/media/File:Erdfunkstelle_Raisting_2.jpg

事实上,我记得在我小时候,我的继父有一个小的太阳能打火机,像这样:

曲线艺术编程 coding curves 第七章 抛物线(Parabolas)

虽然比你日常使用的东西要新奇,但它确实能正常点火工作。

如果你懂了相关的数学,你可以找到射线射到抛物线上的点,找到这个点对应的切线。然后找到这个点的法线(垂直于切线的向量)并反射射入法线点的射线。如果你都做对了,你就会发现反射的射线都汇集到了焦点。我就不和你一起练习了,让我们绘制一些射线看看正不正常。我们仅仅画了一些从 canvas 顶部垂直向下交于抛物线的直线,然后再将其连接到焦点。

a = 0.003
 
// 在这个位置假装画了个抛物线 
// 绘制焦点
focusX = 0
focusY = 1/(4 * a)
circle(focusX, focusY, 4)
fill()
 
lineWidth = 0.5
for (x = -width / 2; x <= width/2; x += 40) {
    // 找到一个抛物线上的点
    y = a * x * x
     
    moveTo(x, -height / 2)
    lineTo(x, y)
    lineTo(focusX, focusY)
    stroke()
}

曲线艺术编程 coding curves 第七章 抛物线(Parabolas)

你可以试着找一条任意的线垂直到抛物线然后连接到焦点。你会发现它从曲线上按它正确的角度反射了。再次我就套用公式直接画出来了,如果可以的话你可以从物理角度上算算应该会得到一样的结果。

注意:这只能在正确配置垂直于 y 轴的射线时才会正常运行。如果射线从其它角度射入那么它就不会聚集于抛物面的焦点了。这就是为啥太阳能点烟器必须要摆到正常的角度才能获取足够的热度用于点烟, 卫星接受器也一样要调整到正常角度信号才能足够好。

另一个公式

当然,抛物线不会总是居中 y 轴对称且顶点靠近 x 轴的这一种形态。以上我们接触的抛物线样子是因为我们使用的是最简单的公式。下面是另一种:

	
y = a * x * x + b * x + c

我们在此处添加了一些额外的参数。最后添加的 c 很明显是用于直接影响曲线顶点在 y 轴的位置。参数 b 就有一点点复杂了,让我们编码运行看看它到底是干什么用的。先把它写成一个抛物线函数:

function parabola(a, b, c, x0, x1) {
    for (x = x0; x <= x1; x++) {
        y = a*x*x + b*x + c
        lineTo(x, y)
    }
}

你也许想对它进行改进,但在此处能用就行。我们只是从 x0 循环至 x1, 找到每个 x 上的 y 点,然后全连接起来。

parabola(0.01, 0, 0, -width/2, width/2)

结果就是之前我们已经实现过的一条抛物线:

曲线艺术编程 coding curves 第七章 抛物线(Parabolas)

下面两个是给 c 分别赋于 -200 与 +200 的结果。

parabola(0.01, 0, -200, -width/2, width/2)
parabola(0.01, 0, 200, -width/2, width/2)

曲线艺术编程 coding curves 第七章 抛物线(Parabolas)

没啥大惊喜,现在把 c 改回 0, 然后把 b 变成正数。

parabola(0.01, 3, 0, -width/2, width/2)

曲线艺术编程 coding curves 第七章 抛物线(Parabolas)

b 为负数:

parabola(0.01, -3, 0, -width/2, width/2)

曲线艺术编程 coding curves 第七章 抛物线(Parabolas)

a 为正数,b 用于控制抛物线位置左、右移动。那如果将 a 变成 负数会如何?

parabola(-0.01, -3, 0, -width/2, width/2)
parabola(-0.01, 3, 0, -width/2, width/2)

曲线艺术编程 coding curves 第七章 抛物线(Parabolas)

毫无意外。它们向上移动了。

注意,到目前为止我们所用到的公式,我们将 x 与 y 交换将得到抛物线开口向左或向右的形状。

曲线艺术编程 coding curves 第七章 抛物线(Parabolas)

在个例子的简单公式:

x = a * y * y

豪华进阶版:

x = a * y * y + b * y + c

总结

好了, 这就是全部我要讲的抛物线内容。我不知道你的编程过程中是否有绘制抛物线的需求,如果有,那么你现在已经整装待发了!

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


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

到了这里,关于曲线艺术编程 coding curves 第七章 抛物线(Parabolas)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索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 第六章 平托图 (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), 事实上我真的自己弄了一个。

    2024年02月08日
    浏览(43)
  • 曲线艺术编程 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日
    浏览(37)
  • 曲线艺术编程 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日
    浏览(47)
  • 第七章 面向对象编程(基础)

    (1)类是抽象的,概念的,代表一类事物,比如人类、猫类... 即它是数据类型。 (2)对象是具体的,实际的,代表一个具体事物,即实例。 (3)类是对象的模板,对象是类的一个个体,对应一个实例。 属性是类的一个组成部分,一般是基本数据类型,也可是引用类型(对

    2024年02月06日
    浏览(86)
  • Flink第七章:状态编程

    Flink第一章:环境搭建 Flink第二章:基本操作. Flink第三章:基本操作(二) Flink第四章:水位线和窗口 Flink第五章:处理函数 Flink第六章:多流操作 Flink第七章:状态编程 这次我们来学习Flink中的状态学习部分,创建以下scala文件 这个文件里有几个常用的状态创建 按键分区中值状态编程案

    2024年02月06日
    浏览(68)
  • 第七章——函数(C++的编程模块)

    复习函数的基本知识 要使用C++函数,必须完成如下工作: 提供函数定义 提供函数原型 调用函数  库函数是已经定义和编译好的函数,同时可以使用标准库头文件提供其原型,因此只需要正确地调用这种函数即可。但是创建自己的函数时,必须自行处理上面提到的3个方面。

    2024年02月13日
    浏览(45)
  • C++ primer plus第七章编程练习答案

    1.编写一个程序,不断要求用户输入两个数,直到其中的一个为 0。对于每两个数,程序将使用一个南数来计算它们的调和平均数,并将结果返回给 main(),而后者将报告结果。调和平均数指的是倒数平均值的倒数,计算公式如下: 调和平均数=2.0*xy/(x + y) 2.编写一个程序,要求用

    2024年02月10日
    浏览(39)
  • TCP/IP 网络编程 第七章:优雅地断开套接字连接

    在前面的章节中,我们都是通过close或者closesocket来断开套接字连接的,但是调用这两个函数导致我们套接字完全断开,套接字将无法接受数据,并且也只能传输完最后余留在缓冲区的数据内容。此时\\\"只关闭一部分数据交换中使用的流\\\"的方法应运而生。 针对优雅断开的shutd

    2024年02月17日
    浏览(56)
  • 中文编程入门(Lua5.4.6中文版)第七章 Lua 字符串与模式

    在网游的符文之地中,我们可以通过神秘的“字符串法术”来处理和操作一系列字符。以下是如何在Lua的魔法卷轴上施展这种法术: 字符串的表示与召唤:  在Lua的魔法治则中,你可以运用三种方式召唤出一串字符(即字符串): 单引号(\\\')内的字符序列。 双引号(\\\")内的字符

    2024年03月19日
    浏览(42)

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

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

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

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

二维码1

领取红包

二维码2

领红包