WPF将点列连接成光滑曲线——贝塞尔曲线
背景
最近在写一个游戏场景编辑器,虽然很水,但是还是遇到了不少问题。连接离散个点列成为光滑曲线就是一个问题。主要是为了通过关键点产生2D的赛道场景。总之马路不可能是直线相连的,当然需要曲线光滑相连。现在我就来解决这个问题。
贝塞尔曲线
贝塞尔曲线,又称贝兹曲线或贝济埃曲线,一般的矢量图形软件通过它来精确画出曲线,贝兹曲线由线段与节点组成,节点是可拖动的支点,线段像可伸缩的皮筋,我们在绘图工具上看到的钢笔工具就是来做这种矢量曲线的。当然在一些比较成熟的位图软件中也有贝塞尔曲线工具,如PhotoShop等。在Flash4中还没有完整的曲线工具,而在Flash5里面已经提供出贝塞尔曲线工具。
这里是百度里面的介绍。直接搬过来了。
问题

如图,这些绿色的点我们希望用光滑的曲线连接它们。
看看WPF给我们提供的函数:


来自MSDN
我们发现point3和point4是我们需要的,这两个点我们直接可以从点列中取得,但是point1和point2如何获取呢?控制点到底是个什么东西。当然我试了很多次失败了很多次~~
巧妙的解决方案
大致思路就是 先算出相邻原始点的中点,在把相邻中点连成的线段平移到对应的原始点,以平移后的中点作为控制点,相邻原始点为起始点画贝塞尔曲线,这样就保证了连接处的光滑。而贝塞尔曲线本身是光滑的,所以就把这些原始点用光滑曲线连起来了。
(http://liyiwen.javaeye.com/blog/705489)

实验结果

看起来连接的还是比较光滑的。
相关代码
Path path;
public void UpdateRoad()
{
MapCanvas.Children.Remove(path);
if (ScenePoint.roadPoint.Count > 0)
{
List<Point> list = new List<Point>();
foreach (ScenePoint sp in ScenePoint.roadPoint)
{
list.Add(new Point((sp.position.X + Shift.X) * Zoom, (sp.position.Y + Shift.Y) * Zoom));
}
PathFigure pf = new PathFigure(); pf.StartPoint = list[0];
List<Point> controls = new List<Point>();
for (int i = 0; i < list.Count; i++)
{
controls.AddRange(Control1(list, i));
}
for (int i = 1; i < list.Count; i++)
{
BezierSegment bs = new BezierSegment(controls[i * 2 - 1], controls[i * 2], list[i], true);
bs.IsSmoothJoin = true; pf.Segments.Add(bs);
}
PathFigureCollection pfc = new PathFigureCollection();
pfc.Add(pf);
PathGeometry pg = new PathGeometry(pfc); path = new Path();
path.Stroke = Brushes.Black;
path.Data = pg;
MapCanvas.Children.Add(path);
}
}
public void UpdateHeightCanvas()
{
HeightCanvas.Children.Clear();
foreach (ScenePoint sp in ScenePoint.listPoint)
{
HeightCanvas.Children.Add(sp.Ellipseh);
}
}
public List<Point> Control1(List<Point> list, int n)
{
List<Point> point = new List<Point>();
point.Add(new Point());
point.Add(new Point());
if (n == 0)
{
point[0] = list[0];
}
else
{
point[0] = Average(list[n - 1], list[n]);
}
if (n == list.Count - 1)
{
point[1] = list[list.Count - 1];
}
else
{
point[1] = Average(list[n], list[n+1]);
}
Point ave = Average(point[0], point[1]);
Point sh = Sub(list[n], ave);
point[0] = Mul(Add(point[0], sh),list[n],0.6);
point[1] = Mul(Add(point[1], sh),list[n],0.6);
//Line line = new Line();
//line.X1 = point[0].X;
//line.Y1 = point[0].Y;
//line.X2 = point[1].X;
//line.Y2 = point[1].Y;
//line.Stroke = Brushes.Red;
//MapCanvas.Children.Add(line);
return point;
}
public Point Average(Point x, Point y)
{
return new Point((x.X+y.X)/2,(x.Y+y.Y)/2);
}
public Point Add(Point x, Point y)
{
return new Point(x.X + y.X, x.Y + y.Y);
}
public Point Sub(Point x, Point y)
{
return new Point(x.X - y.X, x.Y - y.Y);
}
public Point Mul(Point x, Point y,double d)
{
Point temp = Sub(x, y);
temp = new Point(temp.X * d, temp.Y * d);
temp = Add(y, temp);
return temp;
}
WPF将点列连接成光滑曲线——贝塞尔曲线的更多相关文章
- WPF绘制光滑连续贝塞尔曲线
1.需求 WPF本身没有直接把点集合绘制成曲线的函数.可以通过贝塞尔曲线函数来绘制. 贝塞尔曲线类是:BezierSegment,三次贝塞尔曲线,通过两个控制点来控制开始和结束方向. Quadrati ...
- 关于曲线 规划 算法 线性 S曲线 贝塞尔曲线
工控领域经常会涉及速度加减速的算法:线性加减速,S曲线加减速(sin函数,拓展其他三角函数曲线), 贝塞尔曲线,等等. 线性加减速: 设定起始速度V0,目标速度V1,加速时间Ta(s,或加速度) ...
- Unity3d游戏中自定义贝塞尔曲线编辑器[转]
关于贝塞尔曲线曲线我们再前面的文章提到过<Unity 教程之-在Unity3d中使用贝塞尔曲线>,那么本篇文章我们来深入学习下,并自定义实现贝塞尔曲线编辑器,贝塞尔曲线是最基本的曲线,一般 ...
- Unity游戏中使用贝塞尔曲线
孙广东 2015.8.15 比方在3D rpg游戏中.我们想设置弹道,不同的轨迹类型! 目的:这篇文章的主要目的是要给你关于在游戏怎样使用贝塞尔曲线的基本想法. 贝塞尔曲线是最主要的曲线,一般用在 ...
- svg path中的贝塞尔曲线
首先介绍以下什么是贝塞尔曲线 贝塞尔曲线又叫贝茨曲线(Bezier),由两个端点以及若干个控制点组成,只有两个端点在曲线上,控制点不在曲线上,只是控制曲线的走向. 控制点个数为0时,它是一条直线; 控 ...
- iOS - Quartz 2D 贝塞尔曲线
1.贝塞尔曲线 贝塞尔曲线(Bézier curve),又称贝兹曲线或贝济埃曲线,是应用于二维图形应用程序的数学曲线.一般的矢量图形软件通过它来精确画出曲线,贝兹曲线由线段与节点组成,节点是可拖动的支 ...
- 【Unity】贝塞尔曲线关于点、长度、切线计算在 Unity中的C#实现
原文:[Unity]贝塞尔曲线关于点.长度.切线计算在 Unity中的C#实现 写在前面 最近给项目做了个路径编辑,基本思路是满足几个基本需求: [额外说明]其实本篇和这个没关系,可以跳过" ...
- 贝塞尔曲线 WPF MVVM N阶实现 公式详解+源代码下载
源代码下载 效果图: 本程序主要实现: N阶贝塞尔曲线(通用公式) 本程序主要使用技术 MVVM InterAction 事件绑定 动态添加Canvas的Item 第一部分公式: n=有效坐标点数量 ...
- WPF贝塞尔曲线示例
WPF贝塞尔曲线示例 贝塞尔曲线在之前使用SVG的时候其实就已经有接触到了,但应用未深,了解的不是很多,最近在进行图形操作的时候需要用到贝塞尔曲线,所以又重新来了解WPF中贝塞尔曲线的绘制. 一阶贝塞 ...
随机推荐
- android使用Gson来解析json
Gson是一种对象的解析json,非常好用,介绍一个站点http://json.parser.online.fr/能够帮我们看一个字符串是不是Json 对于Json文件 { "id" ...
- (转自aierong原创技术随笔)sqlserver字符串拆分(split)方法汇总
sqlserver字符串拆分(split)方法汇总 --方法0:动态SQL法declare @s varchar(100),@sql varchar(1000)set @s='1,2,3,4,5, ...
- 如何在PHP页面中原样输出HTML代码(是该找本php的数来看了)
如何在PHP页面中原样输出HTML代码(是该找本php的数来看了) 一.总结 一句话总结:字符串与HTML之间的相互转换主要应用htmlentities()函数来完成. 1.php中的html标签如何 ...
- 【最大M子段和】dp + 滚动数组
题目描述 给定 n 个数求这 n 个数划分成互不相交的 m 段的最大 m 子段和. 给出一段整数序列 A1,A2,A3,A4,...,Ax,...,An ,其中 1≤x≤n≤1,000,000, -3 ...
- Swift语言实现代理传值
需求:利用代理实现反响传值(下面样例採用点击第二个视图控制器中的button来改变第一个视图控制器中的Label的内容) 一.创建RootViewController import Foundatio ...
- linux下jar包的生存与开机自动启动
前言 作为一名Android开发,有的时候也是要做做其他工作的,前段时间写了一个很简单的java消息转发程序,因为和三方厂商合作,对方只提供了java的sdk,然而我们这边都是清一色的C#后台开发人员 ...
- 【record】10.17..10.23
.
- Function函数
一般大家都用这个写法来定义一个函数: function Name([parameters]){ functionBody }; //alert(typeof Name) // Function 当我们 ...
- MySQL中 MySQL X.X Command Line Client 一闪而过
问题介绍:我安装完MySQL(我安装的是5.5)后,使用MySQL 5.5 Command Line Client,每次点击,总是一闪而过. 从网上我查了下,都是暂时的解决的方法,不能够解决使点击 M ...
- 树莓派挂载移动硬盘开启samba
本文参考 [https://blog.csdn.net/u010906068/article/details/38455363],原文部分步骤在我的树莓派上,可能是版本不同吧,进行了修改后部署成功 一 ...