我正在使用以下公式绘制正弦曲线
this.x += this.speed
this.y = this.amp * Math.sin( this.x * this.cycles ) + this.center
我通过每帧绘制小圆圈来点出点。这实现了一个从左到右绘制的漂亮的正弦曲线。但是如果我想旋转这条曲线使其随机360度绘制,我应该如何修改代码呢? Aka,有时我希望曲线从左到右是相同的图形,有时我希望它以45度向下,有时,向后等绘制......
答案 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);
我们引入了变量x
和y
,因为我们需要每个变量以原始形式计算this.x
和this.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
。