【问题标题】:Draw curved line between two points在两点之间画曲线
【发布时间】:2014-09-14 16:35:34
【问题描述】:

我什至不记得什么时候我一直在寻找一种在两点之间绘制曲线的方法。

我尝试了很多方法,例如QuadCurves2D、Bezier Curve 等...,但我找不到控制点。

这里的想法是在两个点之间分别绘制一条曲线,它们在哪里或它们之间的角度是多少(用户可以通过单击 alt 并将其拖动到屏幕上来更改点的位置)

这就是我到目前为止所得到的......

正如你在上面看到的,曲线是绝对错误的。

我的期望是这样的:

【问题讨论】:

  • 两个点只定义一条线。如果你想要一个平滑的曲线,你需要两个以上的点来定义它。
  • @duskwuff 我明白了。但我想要理解的正是你所说的。我想在这两点之间找到一个控制点,这样我就可以得到一条曲线。
  • 你需要选择控制点!考虑一下你在 0 和 5 之间的两条线——你的程序应该如何决定绘制这两条线中的哪一条?

标签: java draw curve bezier


【解决方案1】:

第一步:轴对齐两个点,使其中一个位于 (0,0) 上,另一个位于 ([...],0) 上。假设我们有两点,

P1 = {a,b)
P2 = {c,d}

我们翻译它们,使 p1 位于 0,0:

P1 = {0,0}
P2 = {c-a,d-b}

然后我们将 p2 旋转大约 (0,0) 使其最终位于 x 轴上:

a = -atan2(dy,dx) = -atan2(d-b, c-a)
P2ʹ = {
  p2.x * cos(a) - p2.y * sin(a),
  p2.x * sin(a) + p2.y * cos(a)
}

注意 atan2 调用前面的 - 因为我们不想知道“从轴到点”的角度,而是从点到 x 轴。我们现在有两个轴对齐的点(我们将新 P2 的旋转 x 坐标称为“v”):

P1  = { 0 , 0 }
P2ʹ = { v , 0 }

我们现在可以在曲线构造方面做任何我们想做的事情。虽然通常很丑陋,但我们可以构造一个二次曲线,其控制点位于(v/2, ...) 并具有高度“根据您想要的曲率有多强,您想要的任何高度。这将为我们提供一个相对于变换的坐标 -不变的坐标,所以我们只是反向应用旋转/平移:

C  = (v/2,h), then rotate by -a, then translate by (a,b)

(请注意 - 再次签名)。我们已经知道 P1 和 P2 在哪里,所以我们不需要在那里进行任何计算。贝塞尔曲线由它们的“船体点”定义,并且在线性变换方面表现良好,因此所有这些平移/旋转业务对绘制曲线的算法没有影响。只需将这六个值插入二次绘制函数即可。由 C 控制的从 P1 到 P2 的曲线。

当然你可能想要一个三次曲线,因为二次曲线非常难看,所以我们可以定义一个 C1 和 C2,而不是定义一个 C:

C1 = (v/3, 0)
C2 = (2*v/3, 0)

然后将它们升高/降低相同的量;然后我们对它们进行反旋转和反平移并将我们现在拥有的 P1、C1、C2、P2 插入到三次贝塞尔绘图函数中:完成。漂亮的曲线。

【讨论】:

  • 感谢您精心构建的答案,迈克。我将执行您的建议,我很快就会回来检查您的答案是否正确。
  • @GabrielCâmara 看起来你从来没有这样做过。
  • @Tara 我没有太多时间,所以我不得不放弃这个项目。太糟糕了,回到过去真是太棒了。
  • 只要有帖子回答了问题,即使您不再处理它,请记住接受它,以便将来的访问者从网络搜索中找到它。 “未回答”的问题不会浮出水面。
  • 你是对的@Tara 和 Mike,但由于我无法真正尝试上述解决方案,我觉得我会误导那些正在寻找答案的人。如果我没有尝试过我的旧代码,我怎么可能将其标记为正确答案?那是我的想法。无论如何,我会标记为正确的,因为你的论点对我来说似乎是正确的。抱歉,我花了这么长时间才接受这个答案,感谢您抽出宝贵时间,迈克