2024-09-26 18:16:03 发布
网友
我有一组坐标,它们是二维平面上固定的均匀三次B样条曲线的控制点。我想用Cairo调用绘制这个曲线(在Python中,使用Cairo的Python绑定),但据我所知,Cairo只支持Bézier曲线。我也知道两个控制点之间的B样条曲线的线段可以用Bézier曲线来绘制,但是我在任何地方都找不到精确的公式。给定了控制点的坐标,如何导出相应的Bézier曲线的控制点?有没有什么有效的算法?在
好吧,所以我用谷歌搜索了很多东西,我想我找到了一个合理的解决方案,适合我的目的。我把它贴在这里-也许对其他人也有用。在
首先,让我们从一个简单的Point类开始:
Point
from collections import namedtuple class Point(namedtuple("Point", "x y")): __slots__ = () def interpolate(self, other, ratio = 0.5): return Point(x = self.x * (1.0-ratio) + other.x * float(ratio), \ y = self.y * (1.0-ratio) + other.y * float(ratio))
三次B样条曲线只不过是Point对象的集合:
现在,假设我们有一个开放的均匀三次B样条,而不是一个钳制的。三次B样条曲线的四个连续控制点定义一个Bézier段,因此控制点0到3定义第一个Bézier段,控制点1到4定义第二个Bézier段,依此类推。Bézier样条的控制点可以通过在B样条控制点之间进行适当的线性插值来确定。设A、B、C、D为B样条曲线的四个控制点。计算以下辅助点:
控制点F和G从E到H的Bézier曲线等价于点A、B、C和D之间的开B样条曲线。顺便说一句,上述方法被称为Böhm算法,如果用适当的数学方法来描述非均匀或非三次B样条函数,则要复杂得多。在
我们必须对B样条曲线的每一组4个连续点重复上述步骤,因此最后我们将需要几乎所有连续控制点对之间的1:2和2:1分割点。以下BSplineDrawer类在绘制曲线之前所做的工作:
BSplineDrawer
class BSplineDrawer(object): def __init__(self, context): self.ctx = context def draw(self, bspline): pairs = zip(bspline.points[:-1], bspline.points[1:]) one_thirds = [p1.interpolate(p2, 1/3.) for p1, p2 in pairs] two_thirds = [p2.interpolate(p1, 1/3.) for p1, p2 in pairs] coords = [None] * 6 for i in xrange(len(bspline.points) - 3): start = two_thirds[i].interpolate(one_thirds[i+1]) coords[0:2] = one_thirds[i+1] coords[2:4] = two_thirds[i+1] coords[4:6] = two_thirds[i+1].interpolate(one_thirds[i+2]) self.context.move_to(*start) self.context.curve_to(*coords) self.context.stroke()
最后,如果我们想绘制固定的B样条曲线而不是开放的B样条曲线,我们只需将夹紧的B样条曲线的两个端点重复三次:
class CubicBSpline(object): [...] def clamped(self): new_points = [self.points[0]] * 3 + self.points + [self.points[-1]] * 3 return CubicBSpline(new_points)
最后,代码应该如何使用:
import cairo surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, 600, 400) ctx = cairo.Context(surface) points = [(100,100), (200,100), (200,200), (100,200), (100,400), (300,400)] spline = CubicBSpline(points).clamped() ctx.set_source_rgb(0., 0., 1.) ctx.set_line_width(5) BSplineDrawer(ctx).draw(spline)
Converting B-spline curve to Bezier spline curve有帮助吗?在
好吧,所以我用谷歌搜索了很多东西,我想我找到了一个合理的解决方案,适合我的目的。我把它贴在这里-也许对其他人也有用。在
首先,让我们从一个简单的
Point
类开始:三次B样条曲线只不过是
^{pr2}$Point
对象的集合:现在,假设我们有一个开放的均匀三次B样条,而不是一个钳制的。三次B样条曲线的四个连续控制点定义一个Bézier段,因此控制点0到3定义第一个Bézier段,控制点1到4定义第二个Bézier段,依此类推。Bézier样条的控制点可以通过在B样条控制点之间进行适当的线性插值来确定。设A、B、C、D为B样条曲线的四个控制点。计算以下辅助点:
控制点F和G从E到H的Bézier曲线等价于点A、B、C和D之间的开B样条曲线。顺便说一句,上述方法被称为Böhm算法,如果用适当的数学方法来描述非均匀或非三次B样条函数,则要复杂得多。在
我们必须对B样条曲线的每一组4个连续点重复上述步骤,因此最后我们将需要几乎所有连续控制点对之间的1:2和2:1分割点。以下
BSplineDrawer
类在绘制曲线之前所做的工作:最后,如果我们想绘制固定的B样条曲线而不是开放的B样条曲线,我们只需将夹紧的B样条曲线的两个端点重复三次:
最后,代码应该如何使用:
Converting B-spline curve to Bezier spline curve有帮助吗?在
相关问题 更多 >
编程相关推荐