图形学_Bezier曲线
Bezier曲线由n个控制点生成,举个例子:当n=2时,点$P_0$、$P_1$之间遵从计算:
$P_0=(1-t)P_0+tP_1$
而推广为n维时,有:
$P^n_0=(1-t)P^{n-1}_0+tP^{n-1}_1$
递推公式有:
$P^k_i=(1-t)P^{k-1}_i+tP^{k-1}_{i+1}$
要递推生成Bezier的理论知识如上。使用py动态(…课程要求)生成曲线需要掌握matplotlib库的键鼠响应事件。
#fig.canvas.mpl_connect() 事件绑定规范用法
import matplotlib.pyplot as plt def on_key_press(event):
print(event.key) fig, ax = plt.subplots()
fig.canvas.mpl_connect('key_press_event', on_key_press)
plt.show()
下面是实现过程:
定义一个Bezier类,初始化函数中保存事件状态与响应,这里就用到了事件绑定:
def __init__(self, line):
self.line = line
self.index_02 = None # 保存拖动索引
self.press = None # 按下
self.pick = None # 选中
self.motion = None #拖动
self.xs = list() # x坐标
self.ys = list() # y坐标
self.cidpress = line.figure.canvas.mpl_connect('button_press_event', self.on_press) # 鼠标按下事件
self.cidrelease = line.figure.canvas.mpl_connect('button_release_event', self.on_release) # 鼠标放开事件
self.cidmotion = line.figure.canvas.mpl_connect('motion_notify_event', self.on_motion) # 鼠标拖动事件
self.cidpick = line.figure.canvas.mpl_connect('pick_event', self.on_picker) # 鼠标选中事件
这里xs、ys为控制点的横、纵坐标列表。
将self.press设定为1,即表示鼠标按下被调用;
def on_press(self, event): # 鼠标按下调用
if event.inaxes != self.line.axes: return
self.press = 1
选中调用同理;
def on_picker(self, event): # 选中调用
self.pick = 1
鼠标拖动事件的行为就稍微有,复杂了:
def on_motion(self, event): # 鼠标拖动调用
if event.inaxes != self.line.axes: return
if self.press is None: return
if self.pick is None: return
if self.motion is None: # 按下并选中
self.motion = 1
x = self.xs
xdata = event.xdata
ydata = event.ydata
index_01 = 0
for i in x:
if abs(i - xdata) < 0.02: # 0.02 为点的半径
if abs(self.ys[index_01] - ydata) < 0.02: break
index_01 = index_01 + 1
self.index_02 = index_01
if self.index_02 is None: return
self.xs[self.index_02] = event.xdata # 鼠标的坐标覆盖选中的点的坐标
self.ys[self.index_02] = event.ydata
self.draw_01()
一个点的按下与选中值都为1时,才可能被拖动;将self.motion设定为1后,在控制点列表中寻找被拖动的点的位置,然后更新该点的坐标。最后调用draw_01,重新构图。
draw_01如下:
def draw_01(self): # 绘图函数
self.line.clear() # 不清除的话会保留原有的图
self.line.axis([0, 1, 0, 1]) # x和y范围0到1
self.bezier(self.xs, self.ys) # Bezier曲线
self.line.scatter(self.xs, self.ys, color='b', s=200, marker="o", picker=5) # 画点
self.line.plot(self.xs, self.ys, color='r') # 画线
self.line.figure.canvas.draw() # 重构子图
draw先清除了原本的图(不然生成的图会在原图上,生成多条曲线),使用更新过的xs、ys调用Bezier函数生成新的曲线;使用scatter作点;最后重构子图。
Bezier函数如下:
def bezier(self, *args): # Bezier曲线公式转换,获取x和y
n = len(args[0]) # 点的个数
xarray, yarray = [], []
x, y = [], []
index = 0
for t in np.linspace(0, 1):
for i in range(1, n):
for j in range(0, n - i):
if i == 1:
xarray.insert(j, args[0][j] * (1 - t) + args[0][j + 1] * t)
yarray.insert(j, args[1][j] * (1 - t) + args[1][j + 1] * t)
continue
# i != 1时,通过上一次迭代的结果计算
xarray[j] = xarray[j] * (1 - t) + xarray[j + 1] * t
yarray[j] = yarray[j] * (1 - t) + yarray[j + 1] * t
if n == 1:
x.insert(index, args[0][0])
y.insert(index, args[1][0])
else:
x.insert(index, xarray[0])
y.insert(index, yarray[0])
xarray = []
yarray = []
index = index + 1
self.line.plot(x, y)
这里算法的j的范围让我疑惑了一下,一开始写的是和i一样,…然后报错了;个人理解是一个点不会被自己影响过的点影响;将生成的点加入x、y数组后,放入plot中。
最后是响应鼠标松开事件的函数:
def on_release(self, event): # 鼠标放开调用
if event.inaxes != self.line.axes: return
if self.pick == None: # 如果不是选中点,那就添加点
self.xs.append(event.xdata)
self.ys.append(event.ydata)
if self.pick == 1 and self.motion != 1: # 如果是选中点,但不是拖动点,那就删去点
x = self.xs
xdata = event.xdata
ydata = event.ydata
index_01 = 0
for i in x:
if abs(i - xdata) < 0.02:
if abs(self.ys[index_01] - ydata) < 0.02: break
index_01 = index_01 + 1
self.xs.pop(index_01)
self.ys.pop(index_01)
self.draw_01()
self.pick = None # 所有状态恢复,鼠标按下到释放为一个周期
self.motion = None
self.press = None
self.index_02 = None
这里再次点击点被设定为将点从控制点列表中删去。函数的最后,各状态被重置。
主函数:
fig = plt.figure(2, figsize=(12, 6)) # 创建第2个绘图对象,1200*600像素
ax = fig.add_subplot(111) # 一行一列第一个子图
ax.set_title("Missouter's bezier")
myBezier = MyBezier(ax)
plt.xlabel('X')
plt.ylabel('Y')
plt.show()
这个程序在pycharm里不好运行的样子,cmd运行指令python demo.py。
参考博客:
https://blog.csdn.net/guofei9987/article/details/78106492
https://www.jianshu.com/p/116be2cfa708
https://blog.csdn.net/Hachi_Lin/article/details/89052318
图形学_Bezier曲线的更多相关文章
- 计算机图形学:贝塞尔曲线(Bezier Curve)
计算机图形学:贝塞尔曲线(Bezier Curve) 贝塞尔能由贝塞尔样条组合而成,也可产生更高维的贝塞尔曲面.
- 【Notes_8】现代图形学入门——几何(基本表示方法、曲线与曲面)
几何 几何表示 隐式表示 不给出点的坐标,给数学表达式 优点 可以很容易找到点与几何之间的关系 缺点 找某特定的点很难 更多的隐式表示方法 Constructive Solid Geometry .D ...
- 【UE4】GAMES101 图形学作业4:贝塞尔曲线
总览 Bézier 曲线是一种用于计算机图形学的参数曲线. 在本次作业中,你需要实现de Casteljau 算法来绘制由4 个控制点表示的Bézier 曲线(当你正确实现该算法时,你可以支持绘制由更 ...
- 计算机图形学(二)输出图元_6_OpenGL曲线函数_2_中点画圆算法
中点画圆算法 如同光栅画线算法,我们在每一个步中以单位间隔取样并确定离指定圆近期的像素位置.对于给定半径r和屏幕中心(xc,yc),能够先使用算法计算圆心在坐标原点(0, 0)的圆的像素 ...
- iOS 2D绘图 (Quartz2D)之路径(点,直线,虚线,曲线,圆弧,椭圆,矩形)
博客原地址:http://blog.csdn.net/hello_hwc?viewmode=list 让我们继续跟着大神的脚步前进吧.这一次 我们学习一些Quartz 2D 最基本的一些用法. 前言: ...
- 运动曲线提升CSS动画效果
原文链接 译文\译者鞠大宝 先有UI动画,然后才会有好的UI动画.好的动画会让人惊叹“哇哦!”——因为页面看上去很流畅.很漂亮,最重要的是,自然,一点都不会让人觉得不和谐或者僵硬死板.如果你经常逛Dr ...
- Unity3d游戏中自定义贝塞尔曲线编辑器[转]
关于贝塞尔曲线曲线我们再前面的文章提到过<Unity 教程之-在Unity3d中使用贝塞尔曲线>,那么本篇文章我们来深入学习下,并自定义实现贝塞尔曲线编辑器,贝塞尔曲线是最基本的曲线,一般 ...
- Mathematics for Computer Graphics数学在计算机图形学中的应用 [转]
最近严重感觉到数学知识的不足! http://bbs.gameres.com/showthread.asp?threadid=10509 [译]Mathematics for Computer Gra ...
- iOS 2D绘图详解(Quartz 2D)之路径(点,直线,虚线,曲线,圆弧,椭圆,矩形)
前言:一个路径可以包含由一个或者多个shape以及子路径subpath,quartz提供了很多方便的shape可以直接调用.例如:point,line,Arc(圆弧),Curves(曲线),Ellip ...
随机推荐
- 2020不平凡的90天,Python分析三个月微博热搜数据带你回顾
前言 文的文字及图片来源于网络,仅供学习.交流使用,不具有任何商业用途,版权归原作者所有,如有问题请及时联系我们以作处理. 作者:刘早起早起 PS:如有需要Python学习资料的小伙伴可以加点击下方链 ...
- Python程序设计实验报告一:熟悉IDLE和在线编程平台
安徽工程大学 Python程序设计 实验报告 班级 物流191 姓名 崔攀 学号3190505136 成绩_____ 日期 2020.3.8 指导老师 ...
- LCS(记录路径)+LIS+LCIS
https://blog.csdn.net/someone_and_anyone/article/details/81044153 当串1 和 串2 的位置i和位置j匹配成功时, dp[i][j]=d ...
- [linux][mysql] MySQL中information_schema是什么
来源:MySQL中information_schema是什么 information_schema数据库是MySQL自带的,information_schema提供了访问数据库元数据的方式.这就是?元 ...
- 实例讲解Springboot以Template方式整合Redis及序列化问题
1 简介 之前讲过如何通过Docker安装Redis,也讲了Springboot以Repository方式整合Redis,建议阅读后再看本文效果更佳: (1) Docker安装Redis并介绍漂亮的可 ...
- Java IO 流 -- 随机读取和写入流 RandomAccessFile (文件分割和合并)
RandomAccessFile 相对其它流多了一个seek() 方法指定指针的偏移量. 1.指定起始位置读取剩余内容 public static void test01() throws IOExc ...
- deepin15.11小毛病解决
目录 边缘花屏问题 QQ`Tim头像问题 ssh卡死问题 看直播卡 边缘花屏问题 sudo apt install systemsettings 打开kde系统设置 打开显示与设置,修改如图下,基本上 ...
- 关于小程序中textarea内的字体浮动问题
因为map.canvas.video.textarea 是由客户端创建的原生组件,原生组件的层级是最高的,所以页面中的其他组件无论设置 z-index 为多少,都无法盖在原生组件上. 原生组件暂时还无 ...
- 总结:js世界中的特殊符号
常用符号:+ ++ - -- || / /' && 等 这些基本上每天都能用到,但是 js 世界中有些特殊符号是不常用的,我也是偶然在阅读大神代码的时候发现的,一番查找之后得出了以下结 ...
- LeetCode7-ReverseInteger
LeetCode7-ReverseInteger LeetCodeeasyOverflow 题目 题目所在链接为 LeetCode-7:ReverseInteger 题目描述 给出一个32位的有符号整 ...