递归贝塞尔曲线算法在 C# 中不起作用

问题描述

在这文章中复制了确切的算法,但不知何故它在 C# Recursive function of Bezier Curve python 中不起作用。这是我的代码

        private static Vector2 GetPointByInterpolation(List<Vector2> controlPoints,float interpolation)
        {
            if (interpolation < 0 || interpolation > 1)
            {
                throw new ArgumentException("\'interpolation\' value can only range from 0 to 1");
            }
            if (controlPoints.Count == 0)
            {
                throw new ArgumentException("\'controlPoints\' doesn't contain any points");
            }
            if (controlPoints.Count == 1)
            {
                return controlPoints[0];
            }
            else
            {
                Vector2 p1 = GetPointByInterpolation(controlPoints.GetRange(0,controlPoints.Count - 1),interpolation);
                Vector2 p2 = GetPointByInterpolation(controlPoints.GetRange(1,interpolation);
                return (1 - interpolation) * p1 + interpolation * p2;
            }
        }

        private static void Main(string[] args)
        {
            List<Vector2> controlPoints = new List<Vector2>
            {
                new Vector2(0,0),new Vector2(0,100),new Vector2(100,100)
            };
            for (int i = 0; i < 100; i++)
            {
                Console.WriteLine(GetPointByInterpolation(controlPoints,1 / 100 * i));
            }
            Console.Read();
        }

我在上面的链接中测试了算法,它按预期工作,但在我用 C# 重写后,该函数总是返回 controlPoints 中的第一个点。我怀疑问题是因为 Vector2 是一种值类型,但似乎并非如此。

解决方法

我认为这里有两个问题。

  1. 您的范围看起来不正确。
  2. 您执行整数除法,结果不会很好。

对于整数类型的操作数,/ 运算符的结果是整数类型,等于两个操作数的商向零舍入...而且,我知道在我的心你不想要这个。

给定

private static Vector2 GetPointByInterpolation(ReadOnlySpan<Vector2> controlPoints,float interpolation)
{
   if (interpolation < 0 || interpolation > 1)
      throw new ArgumentException("value can only range from 0 to 1",nameof(interpolation));

   if (controlPoints.Length == 0)
      throw new ArgumentException("doesn't contain any points",nameof(controlPoints));

   if (controlPoints.Length == 1)
      return controlPoints[0];

   // first to last - 1
   var p1 = GetPointByInterpolation(controlPoints[0..^1],interpolation);
   // second to last
   var p2 = GetPointByInterpolation(controlPoints[1..],interpolation);
   var nt = 1 - interpolation;
   return new Vector2(nt * p1.X + interpolation * p2.X,nt * p1.Y + interpolation * p2.Y);

}

注意:我正在使用 ReadOnlySpan,因为好吧......为什么不呢,切片非常有效并且可以使用 C# 范围。

使用

var controlPoints = new[]
{
   new Vector2(0,0),new Vector2(0,100),new Vector2(100,100)
};

// take special note of (float)100,we are now performing floating point division
for (int i = 0; i < 100; i++)
   Console.WriteLine(GetPointByInterpolation(controlPoints.AsSpan(),1 / (float)100 * i));

免责声明:我一生中从未写过 python 代码(并且不想开始:p),我也不知道什么是递归贝塞尔曲线算法确实如此,所以我不确定范围是否正确,或者代码是否还有其他问题。