这是更新控制点时 NURBS-python 中的错误吗?
Is this a bug in NURBS-python when updating the control points?
我使用了 NURBS-python 并发现了一个有趣的问题,不确定这是故意这样做的还是只是一个错误。我想用2个代码来介绍一下。
第一个应该和第二个输出一样,但不是。第一个成功更新了NURBS曲线的控制点,绘制了一条新曲线,
改变控制点列表的方式影响结果。
import math
from geomdl import BSpline
from geomdl import NURBS
from geomdl import fitting
from geomdl import convert
from geomdl.visualization import VisMPL
P1=[[0, 0], [0, 1], [1, 1], [1, 0], [1, -1], [0, -1], [0, 0]]
Degree=3
CPN=5
P2=[[0, 0], [0, 1], [2, 1], [2, 0], [2, -1], [0, -1], [0, 0]]
CP=[[0, 0], [1, 2], [2, 0], [1, -2], [0, 0]]
c1=NURBS.Curve()
c1.degree=Degree
c1.ctrlpts=P1
c1.weights=[1, 1, 1, 1, 1, 1, 1]
c1.knotvector=[0, 0, 0, 0, 0.25, 0.5, 0.75, 1, 1, 1, 1]
c1.vis=VisMPL.VisCurve2D()
c1.render()
c1.ctrlpts=P2
c1.vis=VisMPL.VisCurve2D()
c1.render()
c2=convert.bspline_to_nurbs(fitting.approximate_curve(P1, Degree, ctrlpts_size=CPN))
c2.vis=VisMPL.VisCurve2D()
c2.render()
c2.ctrlpts=CP
c2.vis=VisMPL.VisCurve2D()
c2.render()
虽然第二个只是更新控制点,但曲线本身根本没有改变。
import math
from geomdl import BSpline
from geomdl import NURBS
from geomdl import fitting
from geomdl import convert
from geomdl.visualization import VisMPL
P1=[[0, 0], [0, 1], [1, 1], [1, 0], [1, -1], [0, -1], [0, 0]]
Degree=3
CPN=5
P2=[[0, 0], [0, 1], [2, 1], [2, 0], [2, -1], [0, -1], [0, 0]]
CP=[[0, 0], [1, 2], [2, 0], [1, -2], [0, 0]]
c1=NURBS.Curve()
c1.degree=Degree
c1.ctrlpts=P1
c1.weights=[1, 1, 1, 1, 1, 1, 1]
c1.knotvector=[0, 0, 0, 0, 0.25, 0.5, 0.75, 1, 1, 1, 1]
c1.vis=VisMPL.VisCurve2D()
c1.render()
for i in range(len(P2)):
c1.ctrlpts[i]=P2[i]
c1.vis=VisMPL.VisCurve2D()
c1.render()
c2=convert.bspline_to_nurbs(fitting.approximate_curve(P1, Degree, ctrlpts_size=CPN))
c2.vis=VisMPL.VisCurve2D()
c2.render()
for i in range(len(CP)):
c2.ctrlpts[i]=CP[i]
c2.vis=VisMPL.VisCurve2D()
c2.render()
请帮忙,谢谢
Curve.ctrlpts
是一个 property。当您访问 getter 时,它会 returns 控制点列表。访问 setter 可以做更多的事情,主要是一致性检查和必要的清理。
调用cpts = c1.ctrlpts
时,调用属性的__get__
方法,返回Curve
实例中存储控制点的列表对象的引用并分配给 cpts
变量:
>>> cpts = c1.ctrlpts
>>> type(cpts)
<class 'list'>
当您循环遍历列表 cpts
时,您实际上循环遍历了它在 Curve
class 实例中的引用。由于您直接与列表对象交互,因此您不会访问 ctrlpts
setter,它实际上通过调用 Curve.reset()
方法进行清理。
不幸的是,无法覆盖 built-in classes 的方法(在 API 级别上定义的 classes)。
>>> list.__getitem__ = my_getter_method
TypeError: can't set attributes of built-in/extension type 'list'
因此,当底层 list
对象发生变化时触发 Curve.reset()
方法变得有点复杂(但并非不可能)。
最好和最安全的设置控制点的方法是使用 属性:
的 setter 方法
my_ctrlpts = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
c1.ctrlpts = my_ctrlpts
如果要使用for循环,需要手动调用reset方法:
for i in range(len(P2)):
c1.ctrlpts[i]=P2[i]
c1.reset(evalpts=True)
注意:我是 NURBS-Python (geomdl)
的作者
我使用了 NURBS-python 并发现了一个有趣的问题,不确定这是故意这样做的还是只是一个错误。我想用2个代码来介绍一下。
第一个应该和第二个输出一样,但不是。第一个成功更新了NURBS曲线的控制点,绘制了一条新曲线,
改变控制点列表的方式影响结果。
import math
from geomdl import BSpline
from geomdl import NURBS
from geomdl import fitting
from geomdl import convert
from geomdl.visualization import VisMPL
P1=[[0, 0], [0, 1], [1, 1], [1, 0], [1, -1], [0, -1], [0, 0]]
Degree=3
CPN=5
P2=[[0, 0], [0, 1], [2, 1], [2, 0], [2, -1], [0, -1], [0, 0]]
CP=[[0, 0], [1, 2], [2, 0], [1, -2], [0, 0]]
c1=NURBS.Curve()
c1.degree=Degree
c1.ctrlpts=P1
c1.weights=[1, 1, 1, 1, 1, 1, 1]
c1.knotvector=[0, 0, 0, 0, 0.25, 0.5, 0.75, 1, 1, 1, 1]
c1.vis=VisMPL.VisCurve2D()
c1.render()
c1.ctrlpts=P2
c1.vis=VisMPL.VisCurve2D()
c1.render()
c2=convert.bspline_to_nurbs(fitting.approximate_curve(P1, Degree, ctrlpts_size=CPN))
c2.vis=VisMPL.VisCurve2D()
c2.render()
c2.ctrlpts=CP
c2.vis=VisMPL.VisCurve2D()
c2.render()
虽然第二个只是更新控制点,但曲线本身根本没有改变。
import math
from geomdl import BSpline
from geomdl import NURBS
from geomdl import fitting
from geomdl import convert
from geomdl.visualization import VisMPL
P1=[[0, 0], [0, 1], [1, 1], [1, 0], [1, -1], [0, -1], [0, 0]]
Degree=3
CPN=5
P2=[[0, 0], [0, 1], [2, 1], [2, 0], [2, -1], [0, -1], [0, 0]]
CP=[[0, 0], [1, 2], [2, 0], [1, -2], [0, 0]]
c1=NURBS.Curve()
c1.degree=Degree
c1.ctrlpts=P1
c1.weights=[1, 1, 1, 1, 1, 1, 1]
c1.knotvector=[0, 0, 0, 0, 0.25, 0.5, 0.75, 1, 1, 1, 1]
c1.vis=VisMPL.VisCurve2D()
c1.render()
for i in range(len(P2)):
c1.ctrlpts[i]=P2[i]
c1.vis=VisMPL.VisCurve2D()
c1.render()
c2=convert.bspline_to_nurbs(fitting.approximate_curve(P1, Degree, ctrlpts_size=CPN))
c2.vis=VisMPL.VisCurve2D()
c2.render()
for i in range(len(CP)):
c2.ctrlpts[i]=CP[i]
c2.vis=VisMPL.VisCurve2D()
c2.render()
请帮忙,谢谢
Curve.ctrlpts
是一个 property。当您访问 getter 时,它会 returns 控制点列表。访问 setter 可以做更多的事情,主要是一致性检查和必要的清理。
调用cpts = c1.ctrlpts
时,调用属性的__get__
方法,返回Curve
实例中存储控制点的列表对象的引用并分配给 cpts
变量:
>>> cpts = c1.ctrlpts
>>> type(cpts)
<class 'list'>
当您循环遍历列表 cpts
时,您实际上循环遍历了它在 Curve
class 实例中的引用。由于您直接与列表对象交互,因此您不会访问 ctrlpts
setter,它实际上通过调用 Curve.reset()
方法进行清理。
不幸的是,无法覆盖 built-in classes 的方法(在 API 级别上定义的 classes)。
>>> list.__getitem__ = my_getter_method
TypeError: can't set attributes of built-in/extension type 'list'
因此,当底层 list
对象发生变化时触发 Curve.reset()
方法变得有点复杂(但并非不可能)。
最好和最安全的设置控制点的方法是使用 属性:
的 setter 方法my_ctrlpts = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
c1.ctrlpts = my_ctrlpts
如果要使用for循环,需要手动调用reset方法:
for i in range(len(P2)):
c1.ctrlpts[i]=P2[i]
c1.reset(evalpts=True)
注意:我是 NURBS-Python (geomdl)
的作者