画布上的正弦运动:在转折点调用函数

时间:2014-05-30 14:30:02

标签: javascript math canvas

在画布上,圆圈在椭圆路径上移动:http://jsfiddle.net/NwwsP/

代码的相关部分:

function step() {

    x = Math.sin(counter) * 10 + 100;
    y = Math.cos(counter) * 50 + 100;

    // draw Circle with x / y position

    counter += 0.025;
    window.requestAnimationFrame(step);
}
window.requestAnimationFrame(step);

现在我想在椭圆运动的垂直转折点调用一个函数,所以当y处于最高/最低值时。最好的方法是什么?

我尝试将之前的y值与当前的y值进行比较,但这样做不正常。 (或只在一个方向。)

提前感谢您的帮助!

4 个答案:

答案 0 :(得分:1)

var canvas = document.querySelector('canvas'),
    ctx = canvas.getContext('2d'),
    w = canvas.width,
    h = canvas.height,
    x = y = 0;
    counter = 0;

function step() {
    if (counter < Math.PI*2 && counter+0.025 > Math.PI*2) {
        var maxY = Math.max(Math.cos(counter)*50+100, Math.cos(counter+0.025)*50+100);
        console.log("Max Y: " + maxY);
    }
    if (counter < Math.PI && counter+0.025 > Math.PI) {
        var minY = Math.min(Math.cos(counter)*50+100, Math.cos(counter+0.025)*50+100);
        console.log("Min Y: " + minY);
    }

    x = Math.sin(counter) * 10 + 100;
    y = Math.cos(counter) * 50 + 100;

    ctx.clearRect(0, 0, w, h);
    ctx.save();    
    ctx.beginPath();
    ctx.arc(x, y, 4, 0, 2*Math.PI, false);
    ctx.fill();    
    ctx.restore();

    counter += 0.025;
    if (counter > Math.PI*2) {
        counter %= Math.PI*2;
    }
    window.requestAnimationFrame(step);
}
window.requestAnimationFrame(step);

这是my solution。我想这就是你的要求。

答案 1 :(得分:1)

你可以做的事情没有太多的数学,总是计算前一个y的值,然后当方向改变时,改变一个标志的值来帮助你确定每个案例,基本上像这样:

var canvas = document.querySelector('canvas'),
ctx = canvas.getContext('2d'),
w = canvas.width,
h = canvas.height,
x = y = prev_y = 0;
counter = 0;
flag = 1;

function step() {

    x = Math.sin(counter) * 10 + 100;
    y = Math.cos(counter) * 50 + 100;

    if(prev_y > y && flag == 1){
         //Function for lowest position goes here
        flag = 0;
    }
    if(prev_y < y && flag == 0){
        //Function for highest position goes here
        flag = 1;
    }

    ctx.clearRect(0, 0, w, h);
    ctx.save();    
    ctx.beginPath();
    ctx.arc(x, y, 4, 0, 2*Math.PI, false);
    ctx.fill();    
    ctx.restore();

    counter += 0.025;
    window.requestAnimationFrame(step);

    prev_y = y;   

}

window.requestAnimationFrame(step);

<强> JSFiddle Demo

答案 2 :(得分:0)

积分!

您可以通过获取y的导数并找到该导数等于0的位置来找到y的局部极值(最高值和最低值)。

如果您对微积分了解不多,则用于计算任意给定点的线斜率的导数,y'的导数(有时)表示为0 ,发音为&#34; y-prime。&#34;

知道斜率有用的原因是因为当给定点的导数为0时,函数的瞬时斜率0,这意味着< em>原始函数既不增加也不减少,因此我们必须处于局部最大值或局部最小值。 (你可以通过更多的微积分魔法来判断你是在最小值还是最大值。)

如果这没有意义,想象一下你爬山了。当你走路时,坡度是正的。一旦到达顶部,斜率为0,因为您没有上坡或下坡。在两座山间行走也是如此 - 一旦你到达一切平坦的山谷(Math.cos(counter) * 50 + 100斜坡),你就会在底部。

所以......如果你想学习 如何获取衍生物,请查看this link。否则,快速回答是-50 * Math.sin(counter)的导数是0。你需要做的就是找到这个导数n * 180的位置,它发生在每n * Math.PI度,或counter % 180 === 0弧度,无论你使用哪个。

快速回答

您需要在counter时调用您的函数。

但问题是,Math.PI变量递增的时间间隔将永远不会等于0,因此您永远不会得到精确的{{1}的斜率}。我建议您将时间间隔转换为接近您所拥有的时间间隔,但会平均分配到3.14159..,例如0.008 * Math.PI(大约为.02513,但您可以对此进行微调)想):

counter += 0.008 * Math.PI;

答案 3 :(得分:0)

当您处理浮点值时,您需要检查角度是否有一些容差,因为舍入错误可能永远无法获得与之比较的精确值。

我建议采用以下方法:

  • 使用步骤值(就像您一样)
  • 定义顶角和底角
  • 定义tolerance = step / 2

示例:

var step = 0.025,            // angle step
    bottom = 0.5 * Math.PI,  // bottom angle (=90 deg)
    top = 1.5 * Math.PI,     // top angle (=270 deg)
    tol = step * 0.5;        // tolerance, 50% of step

现在你可以比较那个角度和容差:

if (counter > bottom - tol && counter < bottom + tol) {...bottom...}
else if (counter > top - tol && counter < top + tol) {...top...};

通过将计数器限制为360°,确保计数器不会超过一个回合:

counter = counter % (2 * Math.PI);

<强> FIDDLE

其他一些事情:

  • 你已经改变了cos / sin。 Cos代表x,sin代表y,否则它将反向。
  • var x = y = 0不按照您的想法执行,y不会在此处声明。