利用 2 轴运动计算抛物线路径的算法

标签 algorithm

关于附图,我需要一个计算算法来将 A 轴向下移动 n 英寸,将 B 轴从左向右移动 m 英寸,以便组件圆 D 遵循抛物线的曲线;圆 D 并不总是 10 英寸,可以更小。我不是数学专业的,所以这对我来说有点复杂。我知道我在 A 轴上有一个必须计算的弧长(我不知道该怎么做。),然后我在 B 轴上也有一个弧长并且弧正在引用的位置移动轴 A,与圆 D 的直径相关联的弧长将决定圆 D 和抛物线之间的交点在抛物线上的位置。为了从左到右跟随抛物线的曲线,反之亦然 - 我需要一个公式来跟随抛物线。考虑 D 大小的变化。有人可以提供一些关于如何做到这一点的答案吗?一个很好的公式,带有一些解释性信息 - 至少足够详细,我可以搜索这些部分和位以了解要做什么。

2 Axis With Circle to follow Path of Parabola

I have looked and found some information that may be helpful to me but does not answer my question at all: https://stackoverflow.com/questions/4039039/fastest-way-to-fit-a-parabola-to-set-of-points

最佳答案

看来您需要计算作为抛物线偏移的曲线。

在接下来的 C++ 程序中,我将展示如何首先找到抛物线的公式,然后如何计算该曲线的偏移量,最后如何找到两个轴彼此形成的角度。

我将点 (0,0) 视为抛物线的左端,该点(顶点)的底部将位于坐标 (12,-8.75),而右端位于 (24,0)。以这张图为引用(抛物线为蓝色,圆心轨迹为橙色):

enter image description here

请注意,如果圆太大,虽然它在一侧相切,但它可能会在另一侧与抛物线相交。我不确定 12"是抛物线的总宽度还是只有一半,但在后一种情况下,10"的工具会太大:

enter image description here

程序会打印出代表刀具的圆与抛物线相切点的坐标、对应的圆心坐标(刀具的位置)和角度的一些样本(25)两个轴(alpha 和 beta)。

#include <iostream>
#include <iomanip>
#include <vector>
#include <cmath>

using std::cout;
using std::setw;
using std::vector;

int main() {

    // set number of steps or points of approximation
    int n_steps = 25;

    // declare vectors to store coordinates into
    vector<double> x2(n_steps), y2(n_steps);

    // calculate the parameters of the parabola expressed by the formula 
    // y = ax^2 + bx + c
    // Knowing 2 points, one of which is the vertex.
    // xv = -b/2a               | b = -2axv   
    // y0 = ax0^2 + bx0 + c  => | yv - y0 = a(xv^2 - x0^2) + b(xv - x0)
    // yv = axv^2 + bxv + c     | yv - y0 = a(xv - x0)(xv + x0) + b(xv - x0)
    // 
    // a ((xv - x0)*(xv + x0) - 2xv(xv - x0)) = yv - y0
    // a (xv - x0)*(xv + x0 - 2xv) = yv - y0

    // Known coordinates
    double  xv = 12.0,
            yv = -8.75,
            x0 = 0.0,
            y0 = 0.0; 

    double  dx = xv - x0,
            a = (y0 - yv) / ( dx * dx ),
            b = - 2.0 * a * xv,
            c = y0 - x0 * ( a * x0 + b );

    cout << "Parabola formula:\n" 
         << "y = " << a << "x^2 + " << b << "x + " << c << "\n\n"
         << "max acceptable diameter: " << 1.0 / a << "\n\n";

    // Coordinates of rotating axes, extrapolated from your drawing
    double  r1 = 13,
            r2 = 9,
            x1 = xv - r1,
            y1 = r2;
    // some helper values (constant) I'll use later
    double  rad_to_deg = 180.0 / M_PI,
            r1quad = r1 * r1,
            r2quad = r2 * r2,
            rdif = r1quad - r2quad,
            rsum = r1quad + r2quad,
            rden = 1.0 / ( 2.0 * r1 * r2 );

    // radius of the circle (tool)
    double  diameter = 10,
            radius = diameter / 2.0;
    cout << "Diameter of tool (circle): " << diameter << "\n\n";


    // calculate parabola points
    cout << "\t\t\tTangent\t\t\t\tCenter of circle\t\t  alpha\t\tbeta\n";
    // xt[0] = x0    xt[n_steps] = x0 + 2*(xv - x0)
    double step = 2.0 * dx / ( n_steps - 1 );
    for ( int i = 0; i < n_steps; ++i ) {
        // calculate the tangent points which lies on the parabola
        double  xt = x0 + i * step,
                yt = xt * ( a * xt + b ) + c;

        // calculate the offset points, coordinates of the center of the circle
        // first derivative of the parabola
        double delta = 2.0 * a * xt + b;

        // point perpendicular to the tangent at distance equal to radius
        double k = radius / sqrt(delta * delta + 1.0);
        x2[i] = xt - k * delta;
        y2[i] = yt + k;

        // distance from x,y to x1,y1
        double  dx1 = x2[i] - x1,
                dy1 = y2[i] - y1,
                r3quad = dx1 * dx1 + dy1 * dy1,
                r3 = sqrt(r3quad);

        // Now that I know the coordinates of the vertices of the triangle 
        // and the lengths of its sides I can calculate the inner angles
        // using Carnot teorem, for example: a^2 = b^2 + c^2 - 2bc*cos(alpha)
        double alpha_Carnot = acos((rdif + r3quad) / (2.0 * r1 * r3)),
                beta_Carnot = acos((rsum - r3quad) * rden);

        // angle to the orizzontal of line from x1,y1 to x,y in radians
        double  gamma = atan2(dy1,dx1);
        // angle of Axis A to the orizzontal in degrees
        double  alpha = (gamma + alpha_Carnot) * rad_to_deg;
        // angle of Axis B to Axis A. beta = 0 if parallel
        double  beta = beta_Carnot * rad_to_deg - 180.0;

        // output the coordinates
        cout << std::fixed << setw(4) << i << setw(10) << xt << setw(10) << yt
             << setw(15) << x2[i] << setw(10) << y2[i]
             << setw(15) << alpha << setw(12) << beta << '\n';
    }

    return 0;
}

这是输出:

Parabola formula:
y = 0.0607639x^2 + -1.45833x + 0

max acceptable diameter: 16.4571

Diameter of tool (circle): 10

            Tangent             Center of circle          alpha     beta
   0  0.000000  0.000000       4.123644  2.827642      -7.228866 -142.502245
   1  1.000000 -1.397569       5.003741  1.597437      -7.151211 -132.856051
   2  2.000000 -2.673611       5.860925  0.503378      -7.962144 -123.965745
   3  3.000000 -3.828125       6.690144 -0.454279      -9.159057 -115.700562
   4  4.000000 -4.861111       7.485392 -1.276137     -10.496232 -108.022957
   5  5.000000 -5.772569       8.239777 -1.964178     -11.833367 -100.941141
   6  6.000000 -6.562500       8.945861 -2.522462     -13.081185  -94.488527
   7  7.000000 -7.230903       9.596439 -2.957906     -14.180211  -88.708034
   8  8.000000 -7.777778      10.185964 -3.280939     -15.093523  -83.633631
   9  9.000000 -8.203125      10.712644 -3.505588     -15.805504  -79.267662
  10 10.000000 -8.506944      11.180897 -3.648397     -16.321003  -75.558850
  11 11.000000 -8.689236      11.603201 -3.725755     -16.659970  -72.392050
  12 12.000000 -8.750000      12.000000 -3.750000     -16.845543  -69.600878
  13 13.000000 -8.689236      12.396799 -3.725755     -16.889440  -67.003199
  14 14.000000 -8.506944      12.819103 -3.648397     -16.782985  -64.443028
  15 15.000000 -8.203125      13.287356 -3.505588     -16.499460  -61.816277
  16 16.000000 -7.777778      13.814036 -3.280939     -16.005878  -59.069041
  17 17.000000 -7.230903      14.403561 -2.957906     -15.277444  -56.174060
  18 18.000000 -6.562500      15.054139 -2.522462     -14.309495  -53.098717
  19 19.000000 -5.772569      15.760223 -1.964178     -13.126180  -49.773973
  20 20.000000 -4.861111      16.514608 -1.276137     -11.788732  -46.064496
  21 21.000000 -3.828125      17.309856 -0.454279     -10.409278  -41.729113
  22 22.000000 -2.673611      18.139075  0.503378      -9.184425  -36.337384
  23 23.000000 -1.397569      18.996259  1.597437      -8.503984  -29.006402
  24 24.000000  0.000000      19.876356  2.827642      -9.577076  -16.878208

这些是不同位置的一些图片(感谢 excell):

enter image description here enter image description here enter image description here

关于利用 2 轴运动计算抛物线路径的算法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36136175/

相关文章:

performance - MergeSort 中的两个递归调用是什么?

arrays - 如果可以删除任何一个元素,则查找是否可以将数组分为相等和的两个子数组

c++ - 二分查找函数的问题

python - 我在特征脸图像识别部分有错误

algorithm - 如何找到完整无向图中的哈密顿循环数?

algorithm - 从数组中查找每对整数的绝对差的乘积

algorithm - 修改输入数组的计数排序实现

algorithm - 多变量的大 O 效率

java - Dijkstra 算法模拟

c++ - 将二维数组传递给函数时出错