【问题标题】:How calculate a 1/4 circle arc to move along (bezier curve)?如何计算 1/4 圆弧移动(贝塞尔曲线)?
【发布时间】:2025-02-19 10:25:01
【问题描述】:

我正在使用JQuery.path 沿贝塞尔曲线移动对象。单击该项目时,我可以确定起点和终点。如何计算角度和长度以使元素在与起点和终点相交的圆的 1/4 的圆弧上从 A 点移动到 B 点?

我基本上希望它沿着一条曲线移动,该曲线永远不会低于起始 y 位置,也永远不会低于终点 x 位置的左侧。

    var path = {
        start: {
            x: currentLeft,
            y: currentTop,
            angle: ????, //Don't know how to calculate this
            length: ???? //Don't know how to calculate this
        },
        end: {
            x: endLeft,
            y: endTop,
            angle: ????, //Don't know how to calculate this
            length: ???? //Don't know how to calculate this
        }
    };

    jQuery(myElement).animate(
        {
            path: new jQuery.path.bezier(path)
        }
    );

大约。我想要的是:

大概我得到的(他们浸得太低了):

【问题讨论】:

  • @zzzzBov 这是相关的,但不是同一个问题或答案。我仍然需要知道如何计算角度。请看我附上的图片。
  • 这可能需要一些math 所以你应该指定圆的半径。
  • @aug 知道起点和终点,如何计算半径?
  • @DonRhummy 角度和长度是什么意思?我查看了文档,但它根本没有用。

标签: javascript jquery bezier


【解决方案1】:

一个通用的解决方案有点棘手,因为它必须处理四个对角线方向、水平和垂直方向的对角线运动。

首先,您需要几个实用函数:

function r2d(x) {
    /* radians to degrees */
    return x * 180 / Math.PI;
}
function smaller(x, y) {
    /* returns the closer of x|y to zero */
    var x_ = Math.abs(x);
    var y_ = Math.abs(y);
    return (Math.min(x_, y_) === x_) ? x : y;
}

现在一个主函数 anim 接受一个 jQuery 对象(包含感兴趣的元素)和一个 end 对象(具有属性 .left 和 .top )。

function anim($el, end) {
    var current = $el.position();

    var slope1 = (end.top - current.top) / (end.left - current.left);
    var slope2 = 1 / slope1;
    var endAngle = r2d(Math.atan(smaller(slope1, slope2)));
    var startAngle = -endAngle;
    var length = 1/3; //Vary between 0 and 1 to affect the path's curvature. Also, try >1 for an interesting effect.

    //For debugging
    $("#endAngle").text(endAngle);
    $("#startAngle").text(startAngle);
    $("#length").text(length);

    var path = {
        start: {
            x: current.left,
            y: current.top,
            angle: startAngle,
            length: length
        },
        end: {
            x: end.left,
            y: end.top,
            angle: endAngle,
            length: length
        }
    };

    $el.animate({ path: new jQuery.path.bezier(path) });
}

endAngle 的计算对于每个单独的情况(四个对角线,水平和垂直)都非常简单,但对于通用解决方案来说有点棘手。我花了一段时间才开发出适用于所有情况的东西。

DEMO

【讨论】:

    【解决方案2】:

    如果“你想要的”真的是你所需要的,即 90 度出发和到达,那么我们几乎可以立即解决这个问题:

    p_start = { X:..., Y:... }
    p_end = { X:..., Y:... }
    dx = p_end.X - p_start.X
    dy = p_end.Y - p_start.Y
    control_1 = { X: p_start.X, Y: p_start.Y + 0.55228 * dy }
    control_2 = { X: p_end.X - 0.55228 * dx, Y: p_end.Y }
    

    完成了。我们所做的基本上是假设起点和终点位于一个圆上,然后计算控制点,使得生成的贝塞尔曲线在四分之一圆弧上的误差最小。

    在角度方面:从起点出发总是在角度π/2,到达终点总是在角度0。

    【讨论】:

    • 我将如何在 jQuery 动画中使用它?
    • lots 的 jQuery 动画库,以及 lot 的纯 CSS(通常更快)。我已经添加了出发角和到达角,但是如果没有你的 jsbin 让我改变值,就很难以任何明确的方式说出来。
    • 我的意思是,由于您使用不同的名称(控制、dx/dy),其中哪些是开始角度/结束角度,我将把什么作为长度? (假设我使用的是原始 JQuery.path)
    • control_1control_2 是实际的贝塞尔曲线坐标,它定义了曲线的长度。如果我们只想要角度和长度,那么让我们利用基本几何:我们近似四分之一圆,四分之一圆的长度是π·radius/2(因为它是周长除以 4,即 2·π·半径/4,即π·radius/2),所以我们的曲线长度介于π·min(dx,dy)/2π·max(dx,dy)/2 之间。但是我们现在已经把它变成了一个相当简单的几何问题,网上有很多解释。
    • @Mike'Pomax'Kamermans,如果我理解正确,贝塞尔样条曲线肯定会影响曲线的长度,但不会直接影响曲线的长度,就像你上面建议的那样。此外,jQuery.path 期望其样条曲线的角度是相对于连接起点和终点的直线定义的,而不是相对于 X-Y 轴。这两点都会对如何编写有效的解决方案产生重大影响。