我有一堆座標,它們是2D平面上夾緊的均勻三次B樣條的控制點。我想用Cairo調用(使用Python,使用Cairo的Python綁定)來繪製這條曲線,但據我所知,Cairo只支持Bézier曲線。我也知道兩個控制點之間的B樣條的線段可以用Bézier曲線繪製,但我無法在任何地方找到確切的公式。給定控制點的座標,我怎樣才能推導出相應的貝塞爾曲線的控制點?有沒有任何有效的算法?使用Cairo繪製夾緊的均勻三次B樣條
2
A
回答
5
好吧,所以我用Google搜索了很多,我想我想出了一個適合我的目的的合理解決方案。我在這裏發佈 - 也許這對其他人也有用。
首先,讓我們從一個簡單的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
對象的集合更多:
class CubicBSpline(object):
__slots__ = ("points",)
def __init__(self, points):
self.points = [Point(*coords) for coords in points]
現在,假設我們有一個打開均勻的立方B樣條而不是夾緊的樣條。一個三次B樣條的四個連續控制點定義了一個單獨的Bézier分段,所以控制點0到3定義了第一個Bézier分段,控制點1到4定義了第二個分段,依此類推。 Bézier樣條的控制點可以通過以適當方式在B樣條的控制點之間線性插值來確定。設A,B,C和D是B樣條的四個控制點。計算以下輔助點:
- 找到以2:1的比例劃分A-B線的點,讓它成爲A'。
- 找到以1:2的比例劃分C-D線的點,讓它成爲D'。
- 鴻溝BC線分成三個相等的部分,讓這兩個點是F和G
- 查找A之間的中間點」和F,這將是E.
- 查找G和d之間的中間點',這將是H.
從E到H的控制點F和G的Bézier曲線相當於點A,B,C和D之間的開放B樣條。請參閱第1-5節this excellent document。順便說一下,上述方法被稱爲Böhm算法,如果以一種適用於非均勻或非三次B樣條的適當數學方法進行表達,它會複雜得多。
對於B樣條的4個連續點的每組,我們必須重複上述過程,因此最終我們將需要幾乎任何連續控制點對之間的1:2和2:1分割點。這就是下面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)
2
相關問題
- 1. 繪製均勻的二次曲線
- 2. 用平面外推法夾緊三次樣條
- 3. 查找三次B樣條的長度
- 4. Matplotlib在三維表面繪製不均勻的數據
- 5. Addnig文本限制三次樣條繪製
- 6. 繪製非均勻間隔軸
- 7. 標準均勻分佈到離散均勻[a,b]
- 8. 如何使用貝塞爾曲線繪製B樣條?
- 9. 繪製漸變各地關閉三次樣條
- 10. 使用cairo繪製點時剪切
- 11. 使用三次樣條插值
- 12. 使用不均勻分箱繪製分箱數據
- 13. matlab中的三次樣條
- 14. 三次樣條的實施
- 15. 半球均勻採樣
- 16. 三次樣條程序
- 17. C++三次樣條軌跡
- 18. 將N元B樣條變成二次或B樣條的序列
- 19. 使用openGL繪製樣條線
- 20. 三次樣條插值:如何計算二次樣條S2
- 21. 非凸均勻網格三角剖分
- 22. 3D模型的均勻採樣
- 23. 如何在OpenGL中繪製有界b樣條曲面?
- 24. 在x軸上使用不均勻的間隔平滑繪圖
- 25. 日期格式不均勻的線圖繪製和更改
- 26. 在Python上繪製基本的均勻分佈
- 27. 在MATLAB中繪製均勻間隔的函數高度線
- 28. 在matlab中繪製具有不均勻軸的矢量
- 29. ggplot2中的條寬不均勻R
- 30. 不均勻的顏色條,R ggplot2 scale_color_gradient
@ΤΖΩΤΖΙΟΥ+1謝謝,這是有益的幫我在正確的方向開始。請參閱上面的答案,以獲得完整的解決方案以及我找到的算法的簡化說明。 – 2010-03-29 16:54:37