旋转正弦曲线

时间:2017-10-26 11:14:33

标签: javascript math curve

我正在使用以下公式绘制正弦曲线

this.x += this.speed
this.y = this.amp * Math.sin( this.x * this.cycles ) + this.center

我通过每帧绘制小圆圈来点出点。这实现了一个从左到右绘制的漂亮的正弦曲线。但是如果我想旋转这条曲线使其随机360度绘制,我应该如何修改代码呢? Aka,有时我希望曲线从左到右是相同的图形,有时我希望它以45度向下,有时,向后等绘制......

1 个答案:

答案 0 :(得分:4)

一种选择是计算笛卡尔坐标系中的点,转换为极坐标,添加角度偏移,然后再转换回笛卡尔坐标。

this.x += this.speed
this.y = this.amp * Math.sin( this.x * this.cycles ) + this.center

this.r = Math.sqrt(this.x * this.x + this.y * this.y);
this.a = Math.atan2(this.y, this.x);

this.a += rotation_angle;

this.x = this.r * Math.cos(this.a);
this.y = this.r * Math.sin(this.a);

这会将数学库调用的数量从1增加到5,所以我希望它的速度大约是原始计算的五分之一。这可能是也可能是不可接受的。实际上,我们可以使用三角形身份sin(a+b) = sin(a)cos(b) + cos(a)sin(b)cos(a+b) = cos(a)cos(b) - sin(a)sin(b)身份做得更好。

对于旋转的X坐标:

  this.r * cos(this.a)
= this.r * cos(atan2(this.y, this.x) + rotation)
= this.r * (cos(atan2(this.y, this.x))cos(rotation) - sin(atan2(this.y, this.x))sin(rotation))
= this.r * ((this.x / this.r)cos(rotation) - (this.y / this.r)sin(rotation))
= this.x * cos(rotation) - this.y * sin(rotation)

对于旋转的Y坐标:

  this.r * sin(this.a)
= this.r * sin(atan2(this.y, this.x) + rotation)
= this.r * (sin(atan2(this.y, this.x))cos(rotation) + cos(atan2(this.y, this.x))sin(rotation))
= this.r * ((this.y / this.r)cos(rotation) + (this.x / this.r)sin(rotation))
= this.y * cos(rotation) + this.x * sin(rotation)

我们的新代码如下所示:

x = this.x + this.speed
y = this.amp * Math.sin( x * this.cycles ) + this.center

this.x = x * cos(rotation_angle) - y * sin(rotation_angle);
this.y = y * cos(rotation_angle) + x * sin(rotation_angle);

我们引入了变量xy,因为我们需要每个变量以原始形式计算this.xthis.y中的每一个。我们不再需要在极坐标中工作,因为我们的身份允许我们消除那些中间步骤。此外,如果rotation_angle是常数,则可以预先计算;否则,您可以在每个点的计算中保留调用并获得螺旋型效果。

如果您不想使用角度,可以使用参数定义x = f(t)y = g(t)来定义曲线,确定每个点的垂线t。 1}} - 通过分析查找和编码f'(t)g'(t) - 或者通过在数据周围逼近这些点来近似这些。然后,您只需在该定向法线上的位移处绘制一个点,该点等于您当前为this.y计算的值。因此,如果您想沿抛物线绘制正弦曲线,您可以这样做:

t += speed;
r = this.amp * Math.sin(t * this.cycles) + this.center;

x = t;
y = t * t;

dxdt = 1;
dydt = 2t;
dydx = dydt / dxdt;
if (-epsilon <= dydt && dydt <= epsilon) {
    this.x = x;
    this.y = y + r;
} else {
    normal = -1.0 / dydx;
    this.x = x + r * ( 1.0 / Math.sqrt(1 + dydx * dydx));
    this.y = y + r * (dydx / Math.sqrt(1 + dydx * dydx));
}

我没有尝试过运行它,所以它可能会有一些错误,但理论上这些错误应该是可以修复的,这样你才能获得预期的效果:一条正弦曲线缠绕在(定向!)抛物线上y = x^2从消极到积极x