当前位置:网站首页>C#绘制带控制点的Bezier曲线,用于点阵图像及矢量图形
C#绘制带控制点的Bezier曲线,用于点阵图像及矢量图形
2022-07-05 08:45:00 【大可山人】
【摘要】不借助第三方, 使用c# + GDI+进行SVG等绘图,绘制带控制点的Bezier曲线。可用于点阵图像及矢量图形(如SVG)绘图。
先看效果:
(不知为何,已两次上传图片,无法显示,求助csdn)
图注:使用方法二绘制。
方法一:
/// <summary>
/// Bezier样条曲线
/// </summary>
public static class BezierSpline
{
/// <summary>
/// Get open-ended Bezier Spline Control Points.
/// </summary>
/// <param name="knots">Input Knot Bezier spline points.</param>
/// <param name="firstControlPoints">Output First Control points
/// array of knots.Length - 1 length.</param>
/// <param name="secondControlPoints">Output Second Control points
/// array of knots.Length - 1 length.</param>
/// <exception cref="ArgumentNullException"><paramref name="knots"/>
/// parameter must be not null.</exception>
/// <exception cref="ArgumentException"><paramref name="knots"/>
/// array must contain at least two points.</exception>
public static void GetCurveControlPoints(Point[] knots,
out Point[] firstControlPoints, out Point[] secondControlPoints)
{
if (knots == null)
throw new ArgumentNullException("knots");
int n = knots.Length - 1;
if (n < 1)
throw new ArgumentException
("At least two knot points required", "knots");
if (n == 1)
{ // Special case: Bezier curve should be a straight line.
firstControlPoints = new Point[1];
// 3P1 = 2P0 + P3
firstControlPoints[0].X = (2 * knots[0].X + knots[1].X) / 3;
firstControlPoints[0].Y = (2 * knots[0].Y + knots[1].Y) / 3;
secondControlPoints = new Point[1];
// P2 = 2P1 – P0
secondControlPoints[0].X = 2 *
firstControlPoints[0].X - knots[0].X;
secondControlPoints[0].Y = 2 *
firstControlPoints[0].Y - knots[0].Y;
return;
}
// Calculate first Bezier control points
// Right hand side vector
double[] rhs = new double[n];
// Set right hand side X values
for (int i = 1; i < n - 1; ++i)
rhs[i] = 4 * knots[i].X + 2 * knots[i + 1].X;
rhs[0] = knots[0].X + 2 * knots[1].X;
rhs[n - 1] = (8 * knots[n - 1].X + knots[n].X) / 2.0;
// Get first control points X-values
double[] x = GetFirstControlPoints(rhs);
// Set right hand side Y values
for (int i = 1; i < n - 1; ++i)
rhs[i] = 4 * knots[i].Y + 2 * knots[i + 1].Y;
rhs[0] = knots[0].Y + 2 * knots[1].Y;
rhs[n - 1] = (8 * knots[n - 1].Y + knots[n].Y) / 2.0;
// Get first control points Y-values
double[] y = GetFirstControlPoints(rhs);
// Fill output arrays.
firstControlPoints = new Point[n];
secondControlPoints = new Point[n];
for (int i = 0; i < n; ++i)
{
// First control point
firstControlPoints[i] = new Point(x[i], y[i]);
// Second control point
if (i < n - 1)
secondControlPoints[i] = new Point(2 * knots
[i + 1].X - x[i + 1], 2 *
knots[i + 1].Y - y[i + 1]);
else
secondControlPoints[i] = new Point((knots
[n].X + x[n - 1]) / 2,
(knots[n].Y + y[n - 1]) / 2);
}
}
/// <summary>
/// Solves a tridiagonal system for one of coordinates (x or y)
/// of first Bezier control points.
/// </summary>
/// <param name="rhs">Right hand side vector.</param>
/// <returns>Solution vector.</returns>
private static double[] GetFirstControlPoints(double[] rhs)
{
int n = rhs.Length;
double[] x = new double[n]; // Solution vector.
double[] tmp = new double[n]; // Temp workspace.
double b = 2.0;
x[0] = rhs[0] / b;
for (int i = 1; i < n; i++) // Decomposition and forward substitution.
{
tmp[i] = 1 / b;
b = (i < n - 1 ? 4.0 : 3.5) - tmp[i];
x[i] = (rhs[i] - x[i - 1]) / b;
}
for (int i = 1; i < n; i++)
x[n - i - 1] -= tmp[n - i] * x[n - i]; // Backsubstitution.
return x;
}
}
方法二:
private void DrawCurve(Graphics g, PointF[] points, float tension)
{
int n=points.Length;
Pen rPen = new Pen(Color.Red, 2f);
Pen blPen= new Pen(Color.Blue, 1f);
Pen bzPen = new Pen(Color.DarkGoldenrod, 2f);
for (int i = 0; i < n; ++i)
{
// draw segment points[i] - points[(i + 1) % n]
var pPrev1 = points[(i - 1 + n) % n];
var p1 = points[i];
var p2 = points[(i + 1) % n];
var pAfter2 = points[(i + 2) % n];
// tangents 切线控制点
var t1 = new PointF(tension * (p2.X - pPrev1.X), tension * (p2.Y - pPrev1.Y));
var t2 = new PointF(tension * (pAfter2.X - p1.X), tension * (pAfter2.Y - p1.Y));
// interior Bezier control points
var c1 = new PointF(p1.X + t1.X / 3.0f, p1.Y + t1.Y / 3.0f);
var c2 = new PointF(p2.X - t2.X / 3.0f, p2.Y - t2.Y / 3.0f);
//画贝塞尔曲线
g.DrawBezier(bzPen, p1, c1, c2, p2);
//画关键点到切线控制点的直线
g.DrawLine(blPen, p1, c1);
g.DrawEllipse(rPen, p1.X - 2, p1.Y - 2, 4, 4);
g.DrawEllipse(rPen, c1.X - 2, c1.Y - 2, 4, 4);
g.DrawLine(blPen, p2, c2);
g.DrawEllipse(rPen, p2.X - 2, p2.Y - 2, 4, 4);
g.DrawEllipse(rPen, c2.X - 2, c2.Y - 2, 4, 4);
g.FillEllipse(new SolidBrush(Color.Green), new RectangleF(p1.X-2, p1.Y-2, 4, 4));
}
}
方法二的调用方法:
//这里使用的是Panel上绘图,其他控件(如PictureBox)道理一样。
Graphics g = pnlWorkArea.CreateGraphics();
g.Clear(Color.White);
g.CompositingQuality = CompositingQuality.HighQuality;
g.InterpolationMode = InterpolationMode.HighQualityBicubic;
g.SmoothingMode = SmoothingMode.HighQuality;
g.TextRenderingHint = TextRenderingHint.AntiAliasGridFit;
PointF[] points = { new PointF(568,200),new PointF(168,110),new PointF(60,186),new PointF(300,191),new PointF(600,300),new PointF(800,431),new PointF(300,650), new PointF(568, 200) };
float tension=0.68f;
DrawCurve(g, points, tension);
这里有一个不错的链接:
C# GraphicsPath AddBeziers(params System.Drawing.Point[] points)
C# GraphicsPath AddBeziers(System.Drawing.PointF[] points)
源码也可以在此下载:C#带控制点的贝塞尔Bezier曲线算法(源码)-C#文档类资源-CSDN下载
边栏推荐
猜你喜欢
Typescript hands-on tutorial, easy to understand
Guess riddles (6)
Guess riddles (10)
An enterprise information integration system
Halcon snap, get the area and position of coins
Guess riddles (8)
Business modeling of software model | object modeling
猜谜语啦(8)
资源变现小程序添加折扣充值和折扣影票插件
Yolov4 target detection backbone
随机推荐
Task failed task_ 1641530057069_ 0002_ m_ 000000
Guess riddles (142)
【日常訓練--騰訊精選50】557. 反轉字符串中的單詞 III
MPSoC QSPI Flash 升级办法
Guess riddles (6)
深度学习模型与湿实验的结合,有望用于代谢通量分析
Numpy 小坑:维度 (n, 1) 和 维度 (n, ) 数组相加运算后维度变为 (n, n)
It cold knowledge (updating ing~)
[formation quotidienne - Tencent Selection 50] 557. Inverser le mot III dans la chaîne
[牛客网刷题 Day4] JZ55 二叉树的深度
皮尔森相关系数
Dynamic dimensions required for input: input, but no shapes were provided. Automatically overriding
Guess riddles (11)
[daiy4] copy of JZ35 complex linked list
容易混淆的基本概念 成员变量 局部变量 全局变量
golang 基础 ——map、数组、切片 存放不同类型的数据
C language data type replacement
Typical low code apaas manufacturer cases
ROS learning 4 custom message
asp. Net (c)