首页 > 编程语言 >C# .net中B样条曲线转贝塞尔曲线

C# .net中B样条曲线转贝塞尔曲线

时间:2023-02-27 12:32:34浏览次数:40  
标签:曲线 PointF C# res float points net pts Math


PointF[] Spline2Bezier(PointF[] points, int start, int num, bool closed, float tension)

private static PointF[] Spline2Bezier(PointF[] points, int start, int num, bool closed, float tension)
{
var res = new ArrayList();
int len = points.Length - 1;
_ = res.Add(points[0]);
_ = res.Add(ControlPoint(points[1], points[0], tension));
for (int i = 1; i < len; ++i)
{
PointF[] pts = ControlPoints(points[i - 1], points[i + 1], points[i], tension);
_ = res.Add(pts[0]);
_ = res.Add(points[i]);
_ = res.Add(pts[1]);
}
_ = res.Add(ControlPoint(points[len - 1], points[len], tension));
_ = res.Add(points[len]);
if (closed)
{
//adjust rh cp of point 0
PointF[] pts = ControlPoints(points[len], points[1], points[0], tension);
res[1] = pts[1];
//adjust lh cp of point l and add rh cp
pts = ControlPoints(points[len - 1], points[0], points[len], tension);
res[res.Count - 2] = pts[0];
_ = res.Add(pts[1]);
//add new end point and its lh cp
pts = ControlPoints(points[len], points[1], points[0], tension);
_ = res.Add(pts[0]);
_ = res.Add(points[0]);
return (PointF[])res.ToArray(typeof(PointF));
}
else
{
var subset = new ArrayList();
for (int i = start * 3; i < (start + num) * 3; ++i)
_ = subset.Add(res[i]);
_ = subset.Add(res[(start + num) * 3]);
return (PointF[])subset.ToArray(typeof(PointF));
}
}

其中:ControlPoints方法如下:

#region ControlPoint
private static PointF ControlPoint(PointF prev, PointF current, float t)
{
var v = new PointF(prev.X - current.X, prev.Y - current.Y);
float vlen = (float)Math.Sqrt((v.X * v.X) + (v.Y * v.Y));
v.X /= (float)Math.Sqrt(vlen / (10 * t * t));
v.Y /= (float)Math.Sqrt(vlen / (10 * t * t));
return new PointF(current.X + v.X, current.Y + v.Y);
}
private static PointF[] ControlPoints(PointF prev, PointF next, PointF current, float t)
{
//points to vectors
var lv = new PointF(prev.X - current.X, prev.Y - current.Y);
var rv = new PointF(next.X - current.X, next.Y - current.Y);
var nlv = new PointF(lv.X - rv.X, lv.Y - rv.Y);
var nrv = new PointF(rv.X - lv.X, rv.Y - lv.Y);
float nlvlen = (float)Math.Sqrt((nlv.X * nlv.X) + (nlv.Y * nlv.Y));
nlv.X /= (float)Math.Sqrt(nlvlen / (10 * t * t));
nlv.Y /= (float)Math.Sqrt(nlvlen / (10 * t * t));
float nrvlen = (float)Math.Sqrt((nrv.X * nrv.X) + (nrv.Y * nrv.Y));
nrv.X /= (float)Math.Sqrt(nrvlen / (10 * t * t));
nrv.Y /= (float)Math.Sqrt(nrvlen / (10 * t * t));
var ret = new PointF[2];
ret[0] = new PointF(current.X + nlv.X, current.Y + nlv.Y);
ret[1] = new PointF(current.X + nrv.X, current.Y + nrv.Y);
return ret;
}
#endregion ControlPoint

调用方法:

#region DrawCurve
/// <summary>
/// Implemented. The <c>DrawCurve</c> functions emulate GDI behavior by drawing a coaligned cubic bezier. This seems to produce
/// a very good approximation so probably GDI+ does the same.
/// </summary>
public void DrawCurve(Pen pen, PointF[] points)
{
PointF[] pts = Spline2Bezier(points, 0, points.Length - 1, false, .5f);
DrawBeziers(pen, pts);
}

/// <summary>
/// Implemented
/// </summary>
public void DrawCurve(Pen pen, PointF[] points, float tension)
{
PointF[] pts = Spline2Bezier(points, 0, points.Length - 1, false, tension);
DrawBeziers(pen, pts);
}

/// <summary>
/// Implemented
/// </summary>
public void DrawCurve(Pen pen, PointF[] points, int offset, int numberOfSegments)
{
PointF[] pts = Spline2Bezier(points, offset, numberOfSegments, false, .5f);
DrawBeziers(pen, pts);
}

/// <summary>
/// Implemented
/// </summary>
public void DrawCurve(Pen pen, PointF[] points, int offset, int numberOfSegments, float tension)
{
PointF[] pts = Spline2Bezier(points, offset, numberOfSegments, false, tension);
DrawBeziers(pen, pts);
}

/// <summary>
/// Implemented
/// </summary>
public void DrawCurve(Pen pen, Point[] points)
{
PointF[] pts = Spline2Bezier(Point2PointF(points), 0, points.Length - 1, false, .5f);
DrawBeziers(pen, pts);
}

/// <summary>
/// Implemented
/// </summary>
public void DrawCurve(Pen pen, Point[] points, float tension)
{
PointF[] pts = Spline2Bezier(Point2PointF(points), 0, points.Length - 1, false, tension);
DrawBeziers(pen, pts);
}

/// <summary>
/// Implemented
/// </summary>
public void DrawCurve(Pen pen, Point[] points, int offset, int numberOfSegments, float tension)
{
PointF[] pts = Spline2Bezier(Point2PointF(points), offset, numberOfSegments, false, tension);
DrawBeziers(pen, pts);
}
#endregion DrawCurve

另:将GDI+中的DrawArc方法转为Svg中的Path路径:

public static string GdiPlusArc2SvgPath(float x, float y, float width, float height, float startAngle, float sweepAngle, bool pie)
{
int longArc = 0;

var start = new PointF();
var end = new PointF();
var center = new PointF(x + (width / 2f), y + (height / 2f));

startAngle = startAngle / 360f * 2f * (float)Math.PI;
sweepAngle = sweepAngle / 360f * 2f * (float)Math.PI;

sweepAngle += startAngle;

#pragma warning disable IDE0180
if (sweepAngle > startAngle)
{
float temp = startAngle;
startAngle = sweepAngle;
sweepAngle = temp;
}
#pragma warning restore IDE0180

if (sweepAngle - startAngle > Math.PI || startAngle - sweepAngle > Math.PI) longArc = 1;

start.X = ((float)Math.Cos(startAngle) * (width / 2f)) + center.X;
start.Y = ((float)Math.Sin(startAngle) * (height / 2f)) + center.Y;

end.X = ((float)Math.Cos(sweepAngle) * (width / 2f)) + center.X;
end.Y = ((float)Math.Sin(sweepAngle) * (height / 2f)) + center.Y;

string s = "M " + start.X.ToString("F", CultureInfo.InvariantCulture) + "," + start.Y.ToString("F", CultureInfo.InvariantCulture) +
" A " + (width / 2f).ToString("F", CultureInfo.InvariantCulture) + " " + (height / 2f).ToString("F", CultureInfo.InvariantCulture) + " " +
"0 " + longArc.ToString() + " 0 " + end.X.ToString("F", CultureInfo.InvariantCulture) + " " + end.Y.ToString("F", CultureInfo.InvariantCulture);

if (pie)
{
s += " L " + center.X.ToString("F", CultureInfo.InvariantCulture) + "," + center.Y.ToString("F", CultureInfo.InvariantCulture);
s += " L " + start.X.ToString("F", CultureInfo.InvariantCulture) + "," + start.Y.ToString("F", CultureInfo.InvariantCulture);
}

return s;
}

标签:曲线,PointF,C#,res,float,points,net,pts,Math
From: https://blog.51cto.com/u_15983015/6088280

相关文章

  • WINFORM + C# GDI+编程实现Photoshop, Illustrator类似绘图工具箱
    先看效果:其中,比较麻烦的是颜色选取工具,如下图: 要求点击上图颜色区域均可弹出如下图所示的颜色选取器对话框,其中:1、左侧左上角为对象填充,点击右侧右下角为边框颜色选择,左侧......
  • 从.net Framework4.6WPF升级到.netcore3.1/net5/6/7.0版本
    因项目需要,需将.netFramework4.6WPF升级到.netcore3.1/net5.0/6.0/7.0版本,通过很多办法解决,开始搞得一头雾水。终于,找到了办法。1、首先下载upgrade-assistant工具(.net升级......
  • C#使用拉依达准则(3σ准则)剔除异常数据(.Net剔除一组数据中的奇异值)
    1、问题的提出:电池生产中,遇到一批电池的测量结果数据:电压值电池个数电压值电池个数电压值电池个数电压值电池个数0.0561 4.091 4.14617 4.174134340.3211 4.0941 4.147......
  • leetcode 862. 和至少为 K 的最短子数组
    一个双端单调队列:如果新加入的数比队列尾的数小,那么队列尾的数就可以丢去,这是因为如果未来的一个数能和队列尾的数满足条件,那么也一定可以和新加入的数满足条件。另外,如果......
  • CentOS 7关闭图形化界面
    CentOS7关闭图形化界面旋转的冬瓜皮于2021-12-1316:46:46发布7344收藏36分类专栏:linux文章标签:centos服务器linux版权华为云开发者联盟该内容已被华为云开发者......
  • 将后端的application/json的格式数据类型转换成前端需要的类型格式
    前提:后端返回的数据内容但是红框的数据对于前端来说是不正确的数据所以我感觉前端处理这个数据本身这个操作都很傻X但是我尝试进行转换代码如下:得到的数据:点击查......
  • 推荐 7 个学习 TypeScript 的宝库,2021 学 TS 看这篇就够了!
    前言猫哥是一个常年混迹在GitHub上的猫星人,所以发现了不少好的前端开源项目、常用技巧,在此分享给大家。公众号:前端GitHub,专注于挖掘GitHub上优秀的前端开源项目,并以......
  • css背景颜色
     background-color属性定义了元素的背景颜色.页面的背景颜色使用在body的选择器中:实例body{background-color:#b0c4de;}CSS中,颜色值通常以以下方式定义:十六......
  • css背景图像
    background-image属性描述了元素的背景图像.默认情况下,背景图像进行平铺重复显示,以覆盖整个元素实体.页面背景图片设置实例:实例body{background-image:url('paper.......
  • 必选三款scrum敏捷项目管理软件
    Leangoo领歌Leangoo是国产的一个项目管理软件,www.leangoo.com ,专门的Scrum敏捷开发工具,看板的管理方式,高度可视化。它支持敏捷开发全流程。从产品路线图-需求-迭代-缺......