c# – 迭代地平滑曲线

我一整天都在尝试这样做.基本上,我有一条线和一条点.我希望线条能够弯曲并穿过那个点,但我不想要一条平滑的曲线.我不能像我这样定义曲线中的步数(谨防粗略的mspaint绘图):

等等.我尝试了各种各样的东西,比如从初始线的中心取角度,然后在角度引导的点处分割线,但是我的长度有问题.我会把初始长度除以我所处的步数,但这不太对.

有人知道这样做的方法吗?

谢谢.

解决方法

您可能需要自己编写代码.我认为你可以通过在代码中实现二次贝塞尔曲线函数来实现它,可以找到 here.你可以通过仅求解几个值来决定你想要增量的精度.如果你想要一条直线,只求解0和1并用线连接这些点.如果您想要一个角度示例,请求解0,0.5和1并按顺序连接点.如果你想要你的第三个例子,求解0,0.25,0.5,0.75和1.最好将它放在一个for循环中,如下所示:
float stepValue = (float)0.25;
float lastCalculatedValue;
for (float t = 0; t <= 1; t += stepValue)
{
    // Solve the quadratic bezier function to get the point at t.
    // If this is not the first point,connect it to the prevIoUs point with a line.
    // Store the new value in lastCalculatedValue.
}

编辑:实际上,看起来您希望线路通过您的控制点.如果是这种情况,您不希望使用二次贝塞尔曲线.相反,您可能想要拉格朗日曲线.该网站可能有助于公式:http://www.math.ucla.edu/~baker/java/hoefer/Lagrange.htm.但在任何一种情况下,您都可以使用相同类型的循环来控制平滑度.

第2编辑:这似乎有效.只需将numberOfSteps成员更改为所需的线段总数,并相应地设置点数组.顺便说一句,你可以使用三个以上的点.它只会在它们之间分配线段的总数.但我初始化了数组,结果看起来像你的最后一个例子.

第3次编辑:我稍微更新了代码,因此您可以左键单击表单以添加点,然后右键单击以删除最后一点.另外,我在底部添加一个Numericupdown,因此您可以在运行时更改段的数量.

public class Form1 : Form
{
    private int numberOfSegments = 4;

    private double[,] multipliers;
    private List<Point> points;

    private Numericupdown numberOfSegmentsupdown;

    public Form1()
    {
        this.numberOfSegmentsupdown = new Numericupdown();
        this.numberOfSegmentsupdown.Value = this.numberOfSegments;
        this.numberOfSegmentsupdown.ValueChanged += new System.EventHandler(this.numberOfSegmentsupdown_ValueChanged);
        this.numberOfSegmentsupdown.Dock = DockStyle.Bottom;
        this.Controls.Add(this.numberOfSegmentsupdown);

        this.points = new List<Point> { 
            new Point(100,110),new Point(50,60),new Point(100,10)};

        this.PrecomputeMultipliers();
    }

    public void PrecomputeMultipliers()
    {
        this.multipliers = new double[this.points.Count,this.numberOfSegments + 1];

        double pointCountMinusOne = (double)(this.points.Count - 1);

        for (int currentStep = 0; currentStep <= this.numberOfSegments; currentStep++)
        {
            double t = currentStep / (double)this.numberOfSegments;

            for (int pointIndex1 = 0; pointIndex1 < this.points.Count; pointIndex1++)
            {
                double point1Weight = pointIndex1 / pointCountMinusOne;

                double currentMultiplier = 1;
                for (int pointIndex2 = 0; pointIndex2 < this.points.Count; pointIndex2++)
                {
                    if (pointIndex2 == pointIndex1)
                        continue;

                    double point2Weight = pointIndex2 / pointCountMinusOne;
                    currentMultiplier *= (t - point2Weight) / (point1Weight - point2Weight);
                }

                this.multipliers[pointIndex1,currentStep] = currentMultiplier;
            }
        }
    }

    protected override void OnPaint(PaintEventArgs e)
    {
        base.OnPaint(e);

        Point? prevIoUsPoint = null;
        for (int currentStep = 0; currentStep <= numberOfSegments; currentStep++)
        {
            double sumX = 0;
            double sumY = 0;
            for (int pointIndex = 0; pointIndex < points.Count; pointIndex++)
            {
                sumX += points[pointIndex].X * multipliers[pointIndex,currentStep];
                sumY += points[pointIndex].Y * multipliers[pointIndex,currentStep];
            }

            Point newPoint = new Point((int)Math.Round(sumX),(int)Math.Round(sumY));

            if (prevIoUsPoint.HasValue)
                e.Graphics.DrawLine(Pens.Black,prevIoUsPoint.Value,newPoint);

            prevIoUsPoint = newPoint;
        }

        for (int pointIndex = 0; pointIndex < this.points.Count; pointIndex++)
        {
            Point point = this.points[pointIndex];
            e.Graphics.FillRectangle(Brushes.Black,new Rectangle(point.X - 1,point.Y - 1,2,2));
        }
    }

    protected override void OnMouseClick(MouseEventArgs e)
    {
        base.OnMouseClick(e);

        if (e.Button == MouseButtons.Left)
        {
            this.points.Add(e.Location);
        }
        else
        {
            this.points.RemoveAt(this.points.Count - 1);
        }

        this.PrecomputeMultipliers();
        this.Invalidate();
    }

    private void numberOfSegmentsupdown_ValueChanged(object sender,EventArgs e)
    {
        this.numberOfSegments = (int)this.numberOfSegmentsupdown.Value;
        this.PrecomputeMultipliers();
        this.Invalidate();
    }
}

相关文章

在要实现单例模式的类当中添加如下代码:实例化的时候:frmC...
1、如果制作圆角窗体,窗体先继承DOTNETBAR的:public parti...
根据网上资料,自己很粗略的实现了一个winform搜索提示,但是...
近期在做DSOFramer这个控件,打算自己弄一个自定义控件来封装...
今天玩了一把WMI,查询了一下电脑的硬件信息,感觉很多代码都...
最近在研究WinWordControl这个控件,因为上级要求在系统里,...