Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/268.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# .Net在DrawClosedCurve、DrawCurve和DrawBezier之间的转换_C#_.net_Graphics_Bezier_Spline - Fatal编程技术网

C# .Net在DrawClosedCurve、DrawCurve和DrawBezier之间的转换

C# .Net在DrawClosedCurve、DrawCurve和DrawBezier之间的转换,c#,.net,graphics,bezier,spline,C#,.net,Graphics,Bezier,Spline,我需要在DrawClosedCurve和DrawBezier之间进行转换。例如,如果我有一条闭合曲线: Point point1 = new Point(100, 100); Point point2 = new Point(200, 50); Point point3 = new Point(250, 200); Point point4 = new Point(50, 150); Point[] points = {point1, point2, point3, point4}; e.Gr

我需要在DrawClosedCurve和DrawBezier之间进行转换。例如,如果我有一条闭合曲线:

Point point1 = new Point(100, 100);
Point point2 = new Point(200,  50);
Point point3 = new Point(250, 200);
Point point4 = new Point(50, 150);
Point[] points = {point1, point2, point3, point4};
e.Graphics.DrawClosedCurve(pen, points, tension, FillMode);
我需要能够定义与此形状匹配的[四条?]贝塞尔曲线,即给定上面的闭合曲线,我需要为每个线段找到两个定位点。例如,第一段的贝塞尔曲线:

e.Graphics.DrawBezier(pen, point1, anchor1, anchor2, point2)
同样,给定bezier曲线,我需要定义一条匹配的闭合曲线

我提到DrawCurve是因为我不明白为什么这两个函数不能产生相同的结果:

e.Graphics.DrawClosedCurve(pen, points, tension, FillMode);
e.Graphics.DrawCurve(pen, {point1, point2, point3, point4, point1}, tension);
编辑-或者什么会使后者产生相同的结果


我理解,但我不理解基数,我假设它是所使用的样条曲线。我也不明白给出的答案。

让我先回答你的第二个问题

我不明白为什么这两个函数不能产生相同的结果

基数样条曲线需要相邻点来计算切线。因此,您需要在两侧再添加一点:

e.Graphics.DrawCurve(pen, new PointF[] { point4, point1, point2, point3, point4, point1, point2}, tension);
当然,这也将绘制这些附加段。如果忽略这些,则曲线完全相同。除此之外,无法使
DrawCurve
DrawClosedCurve
产生相同的输出:

在此图中,
DrawCurve
使用蓝色笔,
DrawClosedCurve
使用红色笔。除了另外两条蓝色线段外,曲线是相等的

现在,对于贝塞尔曲线:

显然,两个点之间的每个线段都需要一条贝塞尔曲线

for(int i = 0; i < points.Length; ++i)
现在,我们可以使用基数样条曲线的定义计算切线:

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));
最后转换成贝塞尔曲线。端点保持不变。内部控制点需要反映端点切线,并按系数
1/3
缩放(基于Hermite和Bezier曲线之间的关系):

最后画出曲线:

e.Graphics.DrawBezier(Pens.Purple, p1, c1, c2, p2);

以下是完整的代码:

for(int i = 0; i < points.Length; ++i)
{
    // draw segment points[i] - points[(i + 1) % n]
    var pPrev1 = points[(i - 1 + points.Length) % points.Length];
    var p1 = points[i];
    var p2 = points[(i + 1) % points.Length];
    var pAfter2 = points[(i + 2) % points.Length];

    // 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);

    e.Graphics.DrawBezier(Pens.Purple, p1, c1, c2, p2);
}

显然,传递到
DrawClosedCurve
的点是端点
{p1、p2、p3}
。我们唯一的自由度是张力参数。贝塞尔曲线具有更多的自由度(所有内部控制点各有两个维度)。因此,可能有一个独特的张力参数适用于所有人,但可能性很小。计算张力参数需要执行与上述非常类似的操作。您可以设置一个优化问题,以找到最精确地类似于贝塞尔曲线的张力参数。但这是另一个问题的故事。

让我先回答你的第二个问题

我不明白为什么这两个函数不能产生相同的结果

基数样条曲线需要相邻点来计算切线。因此,您需要在两侧再添加一点:

e.Graphics.DrawCurve(pen, new PointF[] { point4, point1, point2, point3, point4, point1, point2}, tension);
当然,这也将绘制这些附加段。如果忽略这些,则曲线完全相同。除此之外,无法使
DrawCurve
DrawClosedCurve
产生相同的输出:

在此图中,
DrawCurve
使用蓝色笔,
DrawClosedCurve
使用红色笔。除了另外两条蓝色线段外,曲线是相等的

现在,对于贝塞尔曲线:

显然,两个点之间的每个线段都需要一条贝塞尔曲线

for(int i = 0; i < points.Length; ++i)
现在,我们可以使用基数样条曲线的定义计算切线:

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));
最后转换成贝塞尔曲线。端点保持不变。内部控制点需要反映端点切线,并按系数
1/3
缩放(基于Hermite和Bezier曲线之间的关系):

最后画出曲线:

e.Graphics.DrawBezier(Pens.Purple, p1, c1, c2, p2);

以下是完整的代码:

for(int i = 0; i < points.Length; ++i)
{
    // draw segment points[i] - points[(i + 1) % n]
    var pPrev1 = points[(i - 1 + points.Length) % points.Length];
    var p1 = points[i];
    var p2 = points[(i + 1) % points.Length];
    var pAfter2 = points[(i + 2) % points.Length];

    // 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);

    e.Graphics.DrawBezier(Pens.Purple, p1, c1, c2, p2);
}

显然,传递到
DrawClosedCurve
的点是端点
{p1、p2、p3}
。我们唯一的自由度是张力参数。贝塞尔曲线具有更多的自由度(所有内部控制点各有两个维度)。因此,可能有一个独特的张力参数适用于所有人,但可能性很小。计算张力参数需要执行与上述非常类似的操作。您可以设置一个优化问题,以找到最精确地类似于贝塞尔曲线的张力参数。但这是另一个问题的故事。

如果它们产生相同的结果,就不需要有两个不同的函数。:-)不管怎样,你不了解基数样条曲线的Wiki页面中的哪一部分。特别是间隔(x_k,x_k+1)。我熟悉t∈ [0,1]。符号(…,x_k,x_k+1,…)用于定义三次Hermite样条曲线(这意味着它包含多个三次多项式段)。您可以将每个线段视为三次贝塞尔曲线,并将参数转换为t=(x-x_k)/(x_k+1-x_k)。如果它们产生相同的结果,则无需使用两个不同的函数。:-)不管怎样,你不了解基数样条曲线的Wiki页面中的哪一部分。特别是间隔(x_k,x_k+1)。我熟悉t∈ [0,1]。符号(…,x_k,x_k+1,…)用于定义三次Hermite样条曲线(这意味着它包含多个三次多项式段)。您可以将每个线段视为三次贝塞尔曲线,并将参数转换为t=(x-x_k)/(x_k+1-x_k)。感谢您的详细回答!既然您已经演示了基数样条线的工作原理,我将尝试优化张力参数。谢谢您的详细回答!既然已经演示了基数样条线的工作原理,我将尝试优化张力参数。