如何通过 3 个点计算循环弧并在 3d 中将其参数化为 0..1

tha*_*alm 5 c# math robotics

如何在 3d 中计算通过 3 个点 A、B、C 的弧。从 A 到 C 通过 B(处理顺序)。

大多数机器人手臂都有这种移动命令。我需要模拟它并对它应用不同的速度动态,因此需要一个参数 0..1 将位置从 A 移动到 C。

编辑:

我所拥有的是圆弧的半径和中心,但是如果我知道开始和结束角度,我如何在 3d 中参数化圆?

编辑2:

越来越近。如果我在圆所在的平面上有两个单位长度的垂直向量 v1 和 v2,我可以进行如下参数化:x (t) = c + r * cos(t) * v1 + r * sin(t) * v2

所以我取v1 = ac,我现在只需要找到v2。有任何想法吗?

tha*_*alm 2

回到这个问题,这非常棘手。代码尽可能短,但仍然比我想象的要多。

您可以创建此类的实例,并SolveArc使用 3 个位置(按正确的顺序)调用该方法来设置该类。然后该Arc方法将为您提供圆弧上从 0..1 线速度开始的位置。如果您找到更短的解决方案,请告诉我。

class ArcSolver
{
    public Vector3D Center { get; private set; }

    public double Radius { get; private set; }

    public double Angle { get; private set; }

    Vector3D FDirP1, FDirP2;

    //get arc position at t [0..1]
    public Vector3D Arc(double t)
    {
        var x = t*Angle;
        return Center + Radius * Math.Cos(x) * FDirP1 + Radius * Math.Sin(x) * FDirP2;
    }

    //Set the points, the arc will go from P1 to P3 though P2.
    public bool SolveArc(Vector3D P1, Vector3D P2, Vector3D P3)
    {
        //to read this code you need to know that the Vector3D struct has
        //many overloaded operators: 
        //~ normalize
        //| dot product
        //& cross product, left handed
        //! length

        Vector3D O = (P2 + P3) / 2;
        Vector3D C = (P1 + P3) / 2;
        Vector3D X = (P2 - P1) / -2;

        Vector3D N = (P3 - P1).CrossRH(P2 - P1);
        Vector3D D = ~N.CrossRH(P2 - O);
        Vector3D V = ~(P1 - C);

        double check = D|V;
        Angle = Math.PI;
        var exist = false;

        if (check != 0)
        {
            double t = (X|V) / check;
            Center = O + D*t;
            Radius = !(Center - P1);
            Vector3D V1 = ~(P1 - Center);

            //vector from center to P1
            FDirP1 = V1;
            Vector3D V2 = ~(P3 - Center);
            Angle = Math.Acos(V1|V2);

            if (Angle != 0)
            {
                exist = true;
                V1 = P2-P1;
                V2 = P2-P3;
                if ((V1|V2) > 0)
                {
                    Angle = Math.PI * 2 - Angle;
                }
            }
        }

        //vector from center to P2
        FDirP2 = ~(-N.CrossRH(P1 - Center));
        return exist;
    }
}
Run Code Online (Sandbox Code Playgroud)