gpt4 book ai didi

java - 计算立方贝塞尔曲线的控制点

转载 作者:行者123 更新时间:2023-11-29 09:54:42 25 4
gpt4 key购买 nike

我正在编写一个用于在Android Tablet上显示音乐的应用程序。

我碰到需要绘制领带和混音的那一刻-将两个音符连接在一起的曲线。

为此,我想使用三次贝塞尔曲线-但不知道如何确定两个控制点的位置。

我显然知道起点(A)和终点(B)(2D),以及我要曲线经过的距线A-B的距离。我这样说是因为曲线不一定在水平面上。

谁能帮助我确定所需的控制点,以使生成的曲线通过一个给定点-即距平面的距离和沿A-B平面的偏移量?

请注意,我不是数学专家,并且希望编程类型公式而不是数学公式。

这是一个具体的例子:



我知道每条线的起点和终点,以及我希望曲线经过的点。

但是,在最近两天用google搜索之后,我无法找到正确的公式来确定再现这些曲线所必需的两个控制点位置。

最佳答案

不幸的是,不依靠数学就没有办法做到这一点,因为从您的图像中,我们需要绘制的曲线类型取决于它所附加的内容。分析您的给定图像会显示两条曲线不共享“构造”属性:



红线是开始/结束基线,其最大平移以适应曲线,蓝线是从开始到第一个控件的方向,从第二个控件到终点,绿线大致表示曲线的数学中点(t = 0.5),黑线显示曲线的最大垂直延伸。

为了形成这些曲线,我们将在标准曲线上发布线性代数,并查看从何处获得我们。

右边的曲线实际上相对容易构建,因为它是非常对称的曲线,我们可以通过缩放标准半圆贝塞尔曲线来制作:

{ (0,0), (0,0.552), (1,0.552), (1,0) }


这会使曲线笔直地“向外”移动,因此我们将其扭曲,以使曲线以微小角度开始和结束:

{ (0,0), (0.2,0.552), (0.8,0.552), (1,0) }


那是在一条直线上,随着一个半圆的高度而上升,所以我们需要将其缩小到四分之一高度,并可能在y坐标前面粘贴一些减号。

{ (0,0), (0.2, +/- 0.138), (0.8, +/- 0.138), (1,0) }


并根据起点p1和终点p4对其进行缩放以匹配所需的线长,

D = distance(p1, p4)
{ (0,0), (0.2 * D, 0.138 * D), (0.8 * D, 0.138 * D), (D,0) }


然后我们旋转坐标,使它们位于正确的角度线上,使用您的线与水平线之间的角度,并将该角度粘贴在旋转矩阵中:

phi = atan2(p4.y - p1.y, p4.x - p1.x)

{
(0, 0),
(0.2 * D * cos(phi) - 0.138 * D * sin(phi), 0.2 * D * sin(phi) + 0.138 * D * cos(phi)),
(D * cos(phi) - 0.138 * D * sin(phi), D * sin(phi) + 0.138 * D * sin(phi)),
(D * cos(phi), D * sin(phi)
}


这看起来像“数学”,但事实并非如此。如果您已经有了phi,则cos(phi)和sin(phi)只是两个数字,这里不涉及数学,只是愚蠢的算术运算。

然后,最后一步是转换所有坐标,以使它们位于页面上的正确位置:

{
(p1.x + 0, p1.y + 0),
(p1.x + 0.2 * D * cos(phi) - 0.138 * D * sin(phi), p1.y + 0.2 * D * sin(phi) + 0.138 * D * cos(phi)),
(p1.x + D * cos(phi) - 0.138 * D * sin(phi), p1.y + D * sin(phi) + 0.138 * D * sin(phi)),
(p1.x + D * cos(phi), p1.y + D * sin(phi)
}


做完了您的第二条曲线很容易绘制。

左侧的曲线工作量稍大,但仅略有增加。我们可能以直觉的方式开始,形成与以前完全相同的曲线类型,然后在旋转之前停止。我们可以观察到,如果我们将您的图像上的曲线平放在水平线上,则实际上是规则的缩放半圆,但是剪切了右侧。因此,让我们这样做:

轮换之前:

{ (0,0), (0.2 * D, 0.138 * D), (0.8 * D, 0.138 * D), (D,0) }


水平剪切

float sx = <strength of the shear>
{ (0,0), (0.2 * D + 0.138 * D * sx, 0.138 * D), (0.8 * D + 0.138 * D * sx, 0.138 * D), (D,0) }


旋转:

phi = atan2(p4.y - p1.y, p4.x - p1.x)

{
(0, 0),
((0.2 * D + 0.138 * D * sx) * cos(phi) - 0.138 * D * sin(phi), (0.2 * D + 0.138 * D * sx) * sin(phi) + 0.138 * D * cos(phi)),
((D + 0.138 * D * sx) * cos(phi) - 0.138 * D * sin(phi), (D + 0.138 * D * sx) * sin(phi) + 0.138 * D * cos(phi)),
(D * cos(phi), D * sin(phi)
}


然后最后一个翻译步骤是相同的​​。再次,大多数情况下只是插入数字,尽管这次您将不得不使用剪切值来查看哪个看起来最好。

免费参数

我们可以通过更改缩放原始半圆的大小来控制曲线的“扭曲”程度。 0.25因子相对紧,0.33相对气泡。我们还可以控制像左领带一样的曲线的剪切强度。剪切力1微妙,剪切力1.75急剧突变。

为什么这项工作

尽管贝塞尔曲线名称中有单词curve,但它们是...线的线性插值的线性插值。将线性变换应用于构建曲线的坐标可保留曲线的属性,因此,我们无需尝试使用完整曲线,而只需弄乱四个坐标并相信曲线会正确。

因此,我们获取一条已知坐标的曲线的四个坐标,然后应用我们需要的所有变换来获得所需的曲线:

(x,y) . scale . (shearx?) . rotation, + (tx,ty)


这是:

|x| . | D 0 | . | 1 shearx | . |cos(phi) -sin(phi)| + |tx|
|y| | 0 D | | 0 1 | |sin(phi) cos(phi)| |ty|


而且矩阵运算可以分解为一个矩阵(这就是为什么计算机如此擅长2D / 3D东西的原因-都是矩阵,因此非常复杂的运算仍然只是应用于一百万个坐标的单个矩阵)。

实际上,如果我们将坐标视为3d坐标,并且z值始终为1,我们甚至可以将其作为矩阵运算来进行转换。但这不再与您的问题真正相关。

一个技巧

可以在 http://jsfiddle.net/CLbUF/1处进行逐步实现左领带的操作,但是并不能将所有操作都折叠为一个操作。您需要自己做。

关于java - 计算立方贝塞尔曲线的控制点,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18492695/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com