鼠标操作贝塞尔曲线
来源:互联网 发布:南京行知实验中学分校 编辑:程序博客网 时间:2024/05/17 21:34
1 贝塞尔曲线
贝塞尔曲线(The Bézier Curves),是一种在计算机图形学中相当重要的参数曲线(三维空间中称为贝塞尔曲面). 贝塞尔曲线由法国工程师皮埃尔·贝塞尔(Pierre Bézier)于1962年发表,他运用贝塞尔曲线来为汽车的主体进行设计.
接下来将从一次贝塞尔曲线开始(以下简称一次曲线. 类似的,
1.1 一次贝塞尔曲线
给定两点
其中,
当参数
一次贝塞尔曲线函数中,参数
1.2 二次贝塞尔曲线
二次曲线的路径由给定点
其中,
为了生成二次曲线,可以借助于中间点
- 由
P0 至P1 的连续点Q0 ,描述一条一次曲线 - 由
P1 至P2 的连续点Q1 ,描述一条一次曲线 - 由
Q0 至Q1 的连续点B(t) ,描述一条二次曲线
以
当参数
1.3 三次贝塞尔曲线
为构造高次曲线,需要借助更多的中间点. 对于三次曲线,可由一次曲线描述的中间点
设
曲线的参数形式为:
其中,
以
当参数
1.4 高次曲线
如果用
2 实现
2.1 计算机绘图
要“画”出贝塞尔曲线,一般使用逐次逼近方式,需要进行较多的计算,然后绘制出来,类似这样:
绘制的代码可以在各类计算机图形学书籍中找到.
2.2 在GDI+中实现
GDI+已经封装好了贝塞尔曲线的绘制代码,如果你想画出贝塞尔曲线,调用Graphics.DrawBezier
方法:
public void DrawBezier(Pen pen, Point pt1, Point ctrlPt1, Point pt2, Point ctrlPt2);
- 1
- 1
这是一个三次贝塞尔曲线,其中4个点分别为:起点,起点控制点,终点,终点控制点. 绘制出来的效果如下:
3 与鼠标交互
怎么实现Photoshop里那样可以调整的贝塞尔曲线呢?两种方法:
- 输入新参数生成曲线
- 用鼠标交互调整曲线
很显然第二种看起来比较好,那么就来试试看.
例如想要获得是这样的效果:
这是一条三次贝塞尔曲线,图中各点含义为:
几个需要解决的问题:
- 表示贝塞尔曲线的锚点和控制点
- 绘制曲线和控制点/控制柄
- 鼠标交互
接下来分别解决。.
3.1 锚点
对于三次贝塞尔曲线而言,有两个锚点:起始点
和结束点
. 每个锚点有两个坐标:本身坐标和控制点坐标. 于是,可以用这样的类来描述:
// Anchorpublic class AnchorPoint { public static AnchorPoint Empty { get; } public Point Point { get; set; } public Point ControlPoint { get; set; }}
- 1
- 2
- 3
- 4
- 5
- 6
- 1
- 2
- 3
- 4
- 5
- 6
3.2 三次贝塞尔曲线
三次曲线前面已经说过原理了,它的结构应该就是这样的:
public class BezierSegment { public AnchorPoint Begin; public AnchorPoint End;}
- 1
- 2
- 3
- 4
- 1
- 2
- 3
- 4
3.3 一个简单的渲染器
为了简单,就用一个最基本的渲染器来画,代码如下:
public class BezierRenderer { public void DrawSegment(Graphics g, BezierSegment seg, Color color) { using (Pen p = new Pen(color)) { g.DrawBezier( p, seg.Begin.Point, seg.Begin.ControlPoint, seg.End.Point, seg.End.ControlPoint); } public void DrawHandle(Graphics g, Point pt, bool solid, Color color) { if (solid) using (SolidBrush b = new SolidBrush(color)) g.FillRectangle(b, pt.X - 2, pt.Y - 2, 4, 4); else using (Pen p = new Pen(color)) g.DrawRectangle(b, pt.X - 2, pt.Y - 2, 4, 4); } public void DrawBar(Graphics g, Point pt1, Point pt2, Color color) { using (Pen p = new Pen(color)) g.DrawLine(p, pt1, pt2); }}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
绘制曲线和控制点及其手柄:
// 画曲线renderer.DrawSegment(g, seg, Color.DimGray);// 画锚点renderer.DrawHandle(g, seg.Begin.Point, false, Color.DimGray);renderer.DrawHandle(g, seg.End.Point, false, Color.DimGray);// 画控制柄renderer.DrawBar(g, seg.Begin.Point, seg.Begin.ControlPoint, Color.Black);renderer.DrawHandle(g, seg.Begin.ControlPoint, false, Color.Black);renderer.DrawBar(g, seg.End.Point, seg.End.ControlPoint, Color.Black);renderer.DrawHandle(g, seg.End.ControlPoint, false, Color.Black);// 当前控制柄为实心if (target != null) renderer.DrawHandle(g, target.ControlPoint, true, Color.Black);
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
画出来的效果如下:
3.4 鼠标交互
和鼠标实际上是这样交互的:
- 按下鼠标,如果落点在某个控制点上,就表示选中了该点,否则落空
- 移动鼠标,如果选中了某个控制点,则调整控制点坐标至新坐标,否则忽略
- 放开鼠标,取消任何选择
看起来只需要处理MouseDown
,MouseMove
和MouseUp
这三个事件就够了.
先弄一个全局标记:
// 热点检测区Rectangle rectBegin, rectEnd;// 激活标识AnchorPoint target = null;
- 1
- 2
- 3
- 4
- 5
- 1
- 2
- 3
- 4
- 5
然后处理鼠标事件.
3.4.1 MouseDown事件
if (rectBegin.Contains(e.Location)) target = seg.Begin;else if (rectEnd.Contains(e.Location)) target = seg.End;refresh();
- 1
- 2
- 3
- 4
- 5
- 1
- 2
- 3
- 4
- 5
3.4.2 MouseMove事件
if (target == null) return;if (!this.ClientRectangle.Contains(e.Location)) return;target.ControlPoint = e.Location;refresh();
- 1
- 2
- 3
- 4
- 1
- 2
- 3
- 4
3.4.3 MouseUp事件
target = null;refresh();
- 1
- 2
- 1
- 2
3.4.4 refresh()
方法
简便起见,refresh()
方法只作简单的刷新:
Invalidate();
- 1
- 1
更高效的刷新应该只处理脏区.
3.5 效果
最后的效果如图:
修改渲染器,可以得到更多的图像效果:
4 扩展和优化
要实现Photoshop那种曲线效果,需要多个锚点连接起来,用和本文类似的方法来画。上面的方法在效率上也还有可以提高的地方。
(完)
- 鼠标操作贝塞尔曲线
- 鼠标操作贝塞尔曲线
- 贝塞尔曲线,以及用鼠标和贝塞尔曲线交互
- 贝塞尔曲线,以及用鼠标和贝塞尔曲线交互
- BGRABitmap图像操作3:用鼠标在窗体画断续的曲线
- BGRABitmap图像操作3:用鼠标在窗体画连续的曲线
- 三次贝塞尔曲线的可视化操作(完善)
- BGRABitmap图像操作7:贝塞尔曲线
- Java随鼠标画曲线
- 曲线平滑-贝塞尔曲线
- Revit二次开发曲线操作
- 鼠标操作
- 鼠标操作
- 鼠标操作
- 鼠标操作
- PictureBox中拖动鼠标画曲线;
- 使用html5,鼠标绘制贝赛尔曲线
- OpenGL: 鼠标动态绘制三次Bezier曲线
- XmlResourceParser出错解决
- 安卓学习笔记---Android-PickerView实现 3D滚轮效果(时间选择器、省市区三级联动,单项选择效果)
- 类何时加载和初始化
- oracle配置监听
- centos 7.2 安装Nginx 及配置php-fpm识别php文件
- 鼠标操作贝塞尔曲线
- bzoj 4579 [Usaco2016 Open]Closing the Farm
- navicat连接mysql出现1862的错误
- PHP设计模式系列
- 解决ImportError: No module named items
- 如何能去掉Ueditor的提示 “本地保存成功”
- FTP登录特别慢的解决方式
- java 面向对象(转载)
- java list按照元素对象的指定多个字段属性进行排序