【转】Graphics.DrawCurve的算法
public static class Spline
{
[System.Diagnostics.DebuggerDisplay("({X},{Y})")]
public partial struct Vec2
{
public float X, Y; public Vec2(float x, float y) { this.X = x; this.Y = y; } public static implicit operator PointF(Vec2 v) { return new PointF(v.X, v.Y); } public static implicit operator Vec2(PointF p) { return new Vec2(p.X, p.Y); } public static Vec2 operator +(Vec2 v1, Vec2 v2) { return new Vec2(v1.X + v2.X, v1.Y + v2.Y); } public static Vec2 operator -(Vec2 v1, Vec2 v2) { return new Vec2(v1.X - v2.X, v1.Y - v2.Y); } public static Vec2 operator *(Vec2 v, float f) { return new Vec2(v.X * f, v.Y * f); } public static Vec2 operator /(Vec2 v, float f) { return new Vec2(v.X / f, v.Y / f); } }
/// <summary>
/// '贝塞尔'内插。结果不包括头尾点
/// </summary>
public static PointF[] InterpolateBezier(PointF p0, PointF p1, PointF p2, PointF p3, int samples)
{
PointF[] result = new PointF[samples];
for (int i = ; i < samples; i++)
{
float t = (i + ) / (samples + 1.0f);
result[i] =
(Vec2)p0 * ( - t) * ( - t) * ( - t) +
(Vec2)p1 * ( * ( - t) * ( - t) * t) +
(Vec2)p2 * ( * ( - t) * t * t) +
(Vec2)p3 * (t * t * t);
}
return result;
} public static PointF[] InterpolateCardinalSpline(PointF p0, PointF p1, PointF p2, PointF p3, int samples)
{
const float tension = 0.5f;
Vec2 u = ((Vec2)p2 - (Vec2)p0) * (tension / ) + p1;
Vec2 v = ((Vec2)p1 - (Vec2)p3) * (tension / ) + p2;
return InterpolateBezier(p1, u, v, p2, samples);
}
/// <summary>
/// '基数样条'内插法。 points为通过点,samplesInSegment为两个样本点之间的内插数量。
/// </summary>
public static PointF[] CardinalSpline(PointF[] points, int samplesInSegment)
{
List<PointF> result = new List<PointF>();
for (int i = ; i < points.Length - ; i++)
{
result.Add(points[i]);
result.AddRange(InterpolateCardinalSpline(
points[Math.Max(i - , )],
points[i],
points[i + ],
points[Math.Min(i + , points.Length - )],
samplesInSegment
));
}
result.Add(points[points.Length - ]);
return result.ToArray();
}
}
测试方法
public partial class Form1 : Form
{
protected override void OnPaint(PaintEventArgs e)
{
PointF[] ps = {new PointF(,), new PointF(, ), new PointF(, ), new PointF(,)};
// 系统的Graphics.DrawCurve,桃色
e.Graphics.DrawCurve(new Pen(Brushes.PeachPuff, ), ps);
// 自己取样,蓝色
e.Graphics.DrawLines(Pens.Blue, Spline.CardinalSpline(ps, ));
}
}
原文地址:https://blog.csdn.net/zheng558888/article/details/15816009
【转】Graphics.DrawCurve的算法的更多相关文章
- 戏说 .NET GDI+系列学习教程(二、Graphics类的方法)
一.DrawBezier 画立体的贝尔塞曲线 private void frmGraphics_Paint(object sender, PaintEventArgs e) { Graphics g ...
- 从零开始学习GDI+ (二) 基本概念与基本操作
从零开始学习GDI+ (一)我的第一个GDI+程序 上文给新手学习GDI+讲述了vs环境等的准备工作,并且可以直接用GDI+绘图了.本文开始,讲述的可能偏理论,建议学习的过程中大胆尝试,多使用API. ...
- [译]处理文本数据(scikit-learn 教程3)
原文网址:http://scikit-learn.org/stable/tutorial/text_analytics/working_with_text_data.html 翻译:Tacey Won ...
- GDI+ 笔记
1.GDI+模板 #include<windows.h> #include<GdiPlus.h> #include <time.h> #include <ma ...
- {Reship}{C#}{GDI+}GDI+画笔,线,区域类型
=================================================================================== This article is ...
- Java实验三报告
一. 实验内容 (一)敏捷开发与XP 摘要:一项实践在XP环境中成功使用的依据通过XP的法则呈现,包括:快速反馈.假设简单性.递增更改.提倡更改.优质工作.XP软件开发的基石是XP的活动,包括:编码 ...
- .Net验证码实现基础--Draw
命名空间 using System.Draw; using System.Draw.Drawing2D; 在form等控件的 事件中 添加 paint事件 ///////画各种形状(空心)////// ...
- C#窗体程序画倾斜一定角度的椭圆
using System;using System.Collections.Generic;using System.ComponentModel;using System.Data;using Sy ...
- GDI+: Curved Shapes
原文 http://www.functionx.com/vcsharp2003/gdi/curves.htm Curves Introduction to Curves A curve is ...
随机推荐
- HTML5学习笔记(十六):原型、类和继承【JS核心知识点】
理解原型 在JavaScript中,只要声明了一个函数,就会为该函数创建一个名为prototype的属性,该属性指向当前函数的原型对象. 而函数的原型对象有一个constructor属性,该属性指向刚 ...
- angular-1.3 之ng-model-options指令
ng-model-options是angular-1.3新出的一个指令,这篇文章就来介绍这个指令的用法. ng-model-options允许我们控制ng-model何时进行同步. 比如:1.当某个确 ...
- (原创)sqlite封装库SmartDB1.3发布
最近终于稍微有点空对SmartDB进行升级了,SmartDB1.3比之前的版本做了简化,增强了易用性和灵活性. SmartDB对sqlite做了一层封装,屏蔽了诸多细节,使得我们使用起来很方便.在注重 ...
- DIOCP开源项目-Delphi高性能无锁队列(lock-free)
最近想在DIOCP中加入任务调度线程,DIOCP的工作线程作为生产者(producer)将接受到的数据对象,投递到任务调度线程中,然后统一进行分配.然而这一切都需要一个队列, 这几天都在关注无锁队列. ...
- tcp/udp只发不接,会丢包还是send失败?
这篇文章源于我看libevent的源码时想到的问题,对于libevent的buffer机制,如果接受端一直不取数据的话,会怎样?如果丢包,不现实,因为会导致数据丢失,如果不丢包,就会导致占用内存一直扩 ...
- LeetCode: Pascal's Triangle 解题报告
Pascal's Triangle Given numRows, generate the first numRows of Pascal's triangle. For example, given ...
- 浅析notifyDataSetChanged内部工作流程
Reference: http://blog.csdn.net/hp910315/article/details/47174531 首先我们知道notifyDataSetChanged是Adater的 ...
- Python操作SQLAlchemy之连表操作
多对一连表操作 首先有两个知识点: 改变数据输出的方式:可以在表的类中定义一个特殊成员:__repr__,return一个自定义的由字符串拼接的数据连接方式. 数据库中表关系之间除了MySQL中标准的 ...
- C#学习笔记(30)——系统自带委托Func和Action
说明(2017-11-23 10:46:33): 1. Func有返回值,Action无返回值,以后就不用定义delegate委托了. 2. 不过还是不知道什么时候该用委托,蒋坤在讲完事件后,留了个作 ...
- ARKit从入门到精通(11)-ARKit开发常见问题及解决方案
转载请注明出处:ARKit从入门到精通(11)-ARKit开发常见问题及解决方案 本文主要介绍ARKit开发过程中一些常见问题 1.ARKit框架无法导入问题 2.ARKit运行黑屏或者白屏问题:Un ...