Rotating a sine curve - javascript

I'm drawing out sine curves using the following formula,
this.x += this.speed
this.y = this.amp * Math.sin( this.x * this.cycles ) + this.center
I'm dotting out points by drawing tiny circles every frame. What this achieves is a nice looking sine curve that draws from left to right. But if I want to rotate this curve so that it draws in a random 360 degree, how should I modify the code? Aka, sometimes I want the curve to be the same drawing from left to right, other times I want it drawing at a 45 degree downwards, sometimes, backwards, etc...

One option is to calculate the point in Cartesian coordinates, convert to polar, add your angle offset, and convert back to Cartesian again.
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);
This increases the number of Math library calls from one to five, so I would expect it to be about one fifth as fast as your original calculation. This may or may not be acceptable. We can actually do a little better using the trigonometric identities sin(a+b) = sin(a)cos(b) + cos(a)sin(b) and cos(a+b) = cos(a)cos(b) - sin(a)sin(b) identities.
For the rotated X-coordinate:
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)
For the rotated Y-coordinate:
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)
Our new code looks like this:
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);
We introduced variables x and y since we need each in its original form to calculate each of this.x and this.y. We no longer need to work in polar coordinates because our identities allowed us to eliminate those intermediate steps. Also, if rotation_angle is constant, it can be pre-computed; otherwise, you can leave the calls in the calculation of each point and get spiral-type effects.
If you prefer not to work with angles at all, you can work in terms of arbitrary functions by using parametric definitions x = f(t) and y = g(t) to define a curve, determining the perpendicular at each point t - either by analytically finding and encoding f'(t) and g'(t) - or by approximating these numerically around points of interest. Then, you simply plot a point at a displacement along that directed normal line equal to the value you are currently calculating for this.y. So, if you wanted to plot a sine curve along a parabola, you could do this:
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));
}
I haven't tried running that, so it might have some errors, but in theory those errors should be fixable so that you get the intended effect: a sine curve wrapped around the (directed!) parabola y = x^2 oriented to from negative to positive x.

Related

How to move an object diagonally and in zigzag?

I created an algorithm to move a particle diagonally and it works fine using an angle. Basically, this is what I do:
this.x += this.speed * Math.cos(this.angle * Math.PI / 180);
this.y += this.speed * Math.sin(this.angle * Math.PI / 180);
this.draw();
How can I combine this with a zigzag movement?
I recommend calculating the lateral deviation from the normal path or amplitude which is given by
// Triangle wave at position t with period p:
function amplitude(t, p) {
t %= p;
return t > p * 0.25 ? t < p * 0.75 ? p * 0.5 - t : t - p : t;
}
where t will be set to the length of the traveled path, and p is the period of the 'zigzag' triangle wave pattern.
Given the amplitude and the previous position, we can now easily compute the next position by moving ahead as described by your original code and then adding the lateral deviation to our position:
var amplitude = amplitude(distance, p) - this.amplitude(previous_distance, p);
this.x += amplitude * Math.sin(this.angle * Math.PI/180);
this.y -= amplitude * Math.cos(this.angle * Math.PI/180);
A complete example with two movable objects, one moving 'normally' and one following a 'zigzag' pattern:
function Movable(x, y, speed, angle, period) {
this.x = x;
this.y = y;
this.speed = speed;
this.angle = angle;
this.period = period;
this.distance = 0;
}
Movable.prototype.moveDiagonal = function() {
this.distance += this.speed;
this.x += this.speed * Math.cos(this.angle * Math.PI / 180);
this.y += this.speed * Math.sin(this.angle * Math.PI / 180);
}
Movable.prototype.amplitudeZigZag = function() {
var p = this.period, d = this.distance % p;
return d > p * 0.25 ? d < p * 0.75 ? p * 0.5 - d : d - p : d;
}
Movable.prototype.moveZigZag = function() {
var amplitude1 = this.amplitudeZigZag();
this.moveDiagonal();
var amplitude2 = this.amplitudeZigZag();
var amplitude = amplitude2 - amplitude1;
this.x -= amplitude * Math.sin(this.angle * Math.PI/180);
this.y += amplitude * Math.cos(this.angle * Math.PI/180);
}
Movable.prototype.draw = function(context) {
context.beginPath();
context.arc(this.x, this.y, 1, 0, 2 * Math.PI);
context.stroke();
}
var canvas = document.getElementById("canvas");
var context = canvas.getContext("2d");
var m1 = new Movable(0, 0, 2, 0, 50);
var m2 = new Movable(0, 0, 2, 0, 50);
for (var i = 0; i < 1000; ++i) {
m1.angle += Math.cos(i * Math.PI/180);
m2.angle += Math.cos(i * Math.PI/180);
m1.moveDiagonal();
m2.moveZigZag();
m1.draw(context);
m2.draw(context);
}
<canvas id="canvas" width="600" height="200"></canvas>
So let's say that you're moving in the direction this.angle and you want to zig-zag in that direction moving side to side ±45° from that direction. All you need to do is have a variable like var zigzag = 45; and add zigzag to this.angle when calculating the new positions. And to make it zig-zag, you need to negate it every so often like this zigzag *= -1;. If you want to stop zig-zagging, set zigzag = 0;.
The trick is knowing when to alternate between ±45°. Maybe you can have the switch timed and keep a reference to the last time you switched using Date.now();. You can check the difference between the current time and the recorded time, then negate zigzag once you've surpassed a certain number of milliseconds. Just remember to record the new time of the last switch. You could also keep track of distance travelled and use the same approach, whatever works for you.

Creating dashes in a pattern of a circle using Javascript Math

I don't understand a lot about the code below and I would like someone to break it down piece by piece.
$(function() {
var centerX = 200,
centerY = 200,
radius = 100,
width = 15,
angles = []
function draw() {
var ctx = document.getElementById("canvas").getContext("2d");
var angle;
//why 180
for (var i = 0; i < 180; i += 10) {
//is the "angle" increasing on every iteration? can you demostrate this please
angle = 2.1 + (i * Math.PI / 90);
angles.push(angle)
ctx.beginPath();
ctx.moveTo(
centerX + Math.sin(angle) * radius,
centerY + Math.cos(angle) * radius
);
ctx.lineTo(
centerX + Math.sin(angle) * (radius + width),
centerY + Math.cos(angle) * (radius + width)
);
ctx.closePath();
ctx.stroke();
}
}
draw()
console.log(angles)
var str = "";
angles.forEach(function(e, i) {
str += " " + i + " : " + e + "|| Math.sin = " + Math.sin(e) + "|| Math.sin * radius = " + Math.sin(e) * radius
$(".display").html(str)
})
})
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.0.2/jquery.min.js"></script>
<canvas id="canvas" width="400" height="400"></canvas>
<div class="display"></div>
like for this part angle = 2.1 + (i * Math.PI / 90); I see i is incrementing by 10 and the author is multiplying it by Math.PI / 90 which is equal to 0.0348888888888889. I know Math.PI is 180 degrees, but were not doing 180/90. We're increasing the number 2.1 by small amount. I can't put all the pieces together.
and in for(var i = 0; i < 180; i += 10){ why did the author choose 180. I know 180 degrees is a half a circle is that why they chose it?
And I always see in other code people use cos for the x coord and sin for the y coord. It doesn't look like the author uses it like the way i just described. could you elaborate.
Any help would be appreciated!
EDIT: I'm also wondering when we use for(var i = 0; i < 180; i += 10){ we get the dashes in a full circle and when i do i < 90 we get a half a circle but the half circle is not straight like against an x or y axis its on an angle. why is it not on the axis? why is it on an angle?
Let's start with SOH CAH TOA (link).
Given Right angled triangle (one side is 90 deg)..
Triangle has an angle.
Triangle has a side that's Opposite (O) to the angle.
Triangle has side that touches both, the angle and the right angle, called (A) Adjacent Side.
Triangle has a side that is called Hypotenuse (H). This is the side that also touches the Angle but doesn't make a right angle with Opposite side.
Now to find any side you need to know at minimum the angle and 1 another side.
Ex: You know angle, Q, is 40deg and Hypotenuse is 10. So what is Adjacent;
Looking at SOH CAH TOA. I See that I know H, and need to know A. CAH has both. So I choose CAH.
Cos Q = Adj/Hyp
Now if you put this Triangle inside circle. Then Hyp will become the radius, like so:
Cos Q = Adj/radius
Now to draw line going outward from a circle i need to know a starting point and the ending point of a line AND i need to make those points align with circle angles.
To get starting point i can just use circle's boundary.
So to get x,y for a point on circle boundary i solve this equation further..
Cos Q * radius = Adj
Cos Q * radius = x //adj is x
& for y...
SOH
Sin Q = Opp/Hyp
Sin Q = Opp/radius
Sin Q * radius = Opp
Sin Q * radius = y
So
x = Cos Q * radius
y = Sin Q * radius
or in js..
var x = Math.cos(angle) * radius;
var y = Math.sin(angle) * radius;
Now we have points that follow a circle's boundary. But for there to be line like we want, we need two points.
This code simply puts in a bigger radius, which gives bigger circle, which gives 2nd points what we needed.
ctx.lineTo(
centerX + Math.sin(angle) * (radius + width),
centerY + Math.cos(angle) * (radius + width));
Code Formatted to be clear:
var centerX = 200,
centerY = 200,
radius = 100,
width = 15,
angles = [],
ctx = document.getElementById("canvas").getContext("2d");
function draw() {
var angle;
for (var i = 0; i < 180; i += 10) {
angle = 2.1 + (i * Math.PI / 90);
ctx.beginPath();
ctx.moveTo(
centerX + Math.sin(angle) * radius,
centerY + Math.cos(angle) * radius);
ctx.lineTo(
centerX + Math.sin(angle) * (radius + width),
centerY + Math.cos(angle) * (radius + width));
ctx.closePath();
ctx.stroke();
}
}
draw();
The code you cite is a bit awkward.
To navigate around a circle, it would be more clear to increment i from 0 to 360 (as in 360 degrees).
for(var i=0; i<360; i++){
Instead, the coder increments from 0 to 180, but then they compensate for halving the 360 degrees by doubling the formula that converts degrees to radians.
// this is the usual conversion of degrees to radians
var radians = degrees * Math.PI / 180;
// This "compensating" conversion is used by the coder
// This doubling of the conversion compensates for halving "i" to 180
var radians = degrees * Math.PI / 90;
A clearer factoring of the iteration would look like this:
// the conversion factor to turn degrees into radians
var degreesToRadians = Math.PI / 180;
// navigate 360 degrees around a circle
for(var i=0; i<360; i++){
// use the standard degrees-to-radians conversion factor
var angle = i * degreesToRadians;
// This roughly rotates the angle so that it starts
// at the 12 o'clock position on the circle
// This is unnecessary if you're navigating completely
// around the circle anyway (then it doesn't matter where you start)
angle += 2.1;
....
}
And...
The code is intentionally drawing lines that radiate away from the circles circumference. The coder is not attempting to follow the circumference at all.

Math returns NaN

Im trying to make an particle move towards where on canvas was clicked however the formula returns NaN. Why is this and how can I fix this?
step 1: Particle gets placed at player.x, player.y properly.
step 2: At first tick the particle goes to the upper left point of the canvas without x,y position.
Screenie of particle props
example at jsfiddle
Particle Object
function Shuriken(mouseX, mouseY) {
this.rot = 0;
this.vel = 2;
this.angle = 0;
this.x = player.x || WIDTH / 2;
this.y = player.y || HEIGHT / 2;
this.mouseX = mouseX || WIDTH /2;
this.mouseY = mouseY || HEIGHT /2
this.width = shurikenImg.width;
this.height = shurikenImg.height;
}
update on tick
Shuriken.prototype.move = function() {
this.angle = Math.atan2(this.mouseY, this.x) * (180 / Math.PI);
this.x += this.vel * Math.cos(this.angle);
this.y += this.vel * Math.sin(this.angle);
}
You convert angle from radians into degrees. Nicer to debug (because degrees are still taught in school) but alas, the sin and cos in the next lines expect their arguments to be in radians again. Granted, the functions ought still to work; but the values you get are no longer what you expect.
this.vel is undefined in the jsfiddle. This is most likely what lead to the observed NaN.
This is a wrong calculation:
this.x = this.vel * Math.cos(this.angle);
this.y = this.vel * Math.sin(this.angle);
You don't want the x and y positions calculated this way. Add or subtract the (adjusted) velocity from the x/y coordinates.

Circular animation in javascript, greensock tweenlite

I have a point drawn in an canvas (html5). Then I want this point to animate in a circular path.
I saw an example using time differences to set the x and y variables, in respect to time. Some of the variables and formulas used are quite vague, I have forgotten my physics, d*mn. But I have researched quite a bit on circular motion, so I can understand some of it. Here is my codepen on how it was done.
Basically here are the parts I have identified so far:
this.orbit = 100; // this is the radius of the circular orbit
this.radius = 5; // orbiting object's radius
this.velocity = 50; // yeah velocity but without direction, should be speed (agree?)
var angle = 0; starting angle of the point in the orbit inside the canvas's quadrant,
set x and y coordinates with respect to the coordinates of the canvas
first get the center of the canvas by dividing the width and the height by 2
then adding to the product of the orbit's radius and the position of x and y
with respect to the initial position in the orbit(angle), and since Math trigonometric
functions uses radians, we should multiply it to the quotient of PI and 180.
this.x = _width / 2 + this.orbit * Math.cos(angle * Math.PI / 180)
this.y = _height / 2 + this.orbit * Math.sin(angle * Math.PI / 180)
// by doing the above, we now get the initial position of x and y in the orbit.
What is quite trivial to me are the next variables _dx and _dy and also the _magnitude.
Here is how the point is animated:
Point.prototype.update = function(dt) {
var dps = this.orbit * 2 * Math.PI / this.velocity;
var angle = (360 / dps) * dt / 1000 * -1;
this.vx = this.vx * Math.cos(angle * Math.PI / 180) - this.vy*Math.sin(angle * Math.PI / 180);
this.vy = this.vx * Math.sin(angle * Math.PI / 180) + this.vy*Math.cos(angle * Math.PI / 180);
var _magnitude = Math.sqrt( this.vx * this.vx + this.vy * this.vy);
this.vx = this.vx / _magnitude * this.velocity;
this.vy = this.vy / _magnitude * this.velocity;
this.x += this.vx * dt / 1000;
this.y += this.vy * dt / 1000;
}
And here is the execution of the script:
function animate () {
dt = new Date() - ldt;
if (dt < 500) {
// context.clearRect(0, 0, canvas.width, canvas.height);
point.update(dt);
point.draw(context);
};
ldt = new Date();
setTimeout(function() {
window.requestAnimationFrame(animate);
}, 1000 / 30)
}
ldt = new Date();
animate();
With the unclear variables, like _dx _dy _magnitude I cannot understand how it works and how the computation of variables, vx vy which I assume the velocity with respect to x and y respectively.
I wanted to use greensock tweenlite for the animation and it is done like so:
Point.prototype.update = function(p){
var _to = {
x: , // change the value of x
y: , // change the value of y
ease: Cubic.easeInOut,
onComplete: function () { this.update(p) }
}
TweenLite.to(point, 2, _to)
}
As you can see the first parameter is the current object (point), then the second parameter is the time, I assume this to be the velocity and the the third parameter is the change in the object's properties, x and y.
Question
I made the codepen, now How do I use gsap tweenlite to animate the circle like what I did, I suppose using tweenlite will make it a little simple.
In your case you are trying to use TweenLite to animate point as the crow flies, and you trigger TweenLite.to() function for each new position of point. This method of using TweenLite.to() function has no sense and performance, because distance between 2 position of point is too short. So, this method will only slow down your animation because instead of just draw point in new position you want to animate it.
The best solution in this case is trying to use TweenLite's methods to animate whole circle.
Take a look on this article: Tween around circle
Especially on these examples:
1) http://codepen.io/GreenSock/pen/jCdbq (not canvas, but it displays the main idea)
TweenMax.to("#logo", 4, {rotation:360, transformOrigin:"40px -100px", repeat:10, ease:Linear.easeNone});
2) and http://codepen.io/rhernando/pen/kjmDo

Getting choppy movement using time-based movement

I am using time based movement, but its still super choppy. this code shoots in arrow in the air then calculates the difference in movement to determine to rotation of the arrow. It works most of the time, but sometimes it just jitters.
for(i=0;i<this.arrows.length;i++){
a = this.arrows[i];
point0 = [a.x,a.y];
x_speed = e.delta/1000*a.speed * Math.cos(a.angle * Math.PI / 180);
y_speed = e.delta/1000*a.speed * Math.sin(a.angle * Math.PI / 180);
a.x += x_speed;
a.y += y_speed;
a.y += a.velocity;
a.velocity += e.delta/1000*this.gravity;
alert(e.delta);
ang = Math.atan2(point0[1]-a.y,point0[0]-a.x);
ang = (ang * (180/Math.PI))+180;
a.rotation = ang;
}
1) I'm surprised you are using a.angle, ang and a.rotation. I guess ang is a var declared before the for loop, but isn't there an issue here ?
2) You might use radians, not degrees, to avoid conversions.
3) There's also an issue with speed vs velocity : you don't update speed (linear speed) when you change velocity (speed on Y).
•• Anyway there's a simpler way of proceeding : compute speed/position just like for a regular point moving, then use the speed vector to compute where the end of the arrow is.
It works fine in this fiddle : http://jsbin.com/dexaroriwixo/1/
update :
var i=0, a=null, delta_ms = 1e-3 * e.delta;
for(i=0;i<this.arrows.length;i++){
a = this.arrows[i];
a.x += delta_ms*a.speedX;
a.y += delta_ms*a.speedY;
a.speedY += delta_ms*this.gravity;
a.speedNorm = Math.sqrt(sq(a.speedX)+sq(a.speedY));
}
to draw :
Arrow.prototype.draw = function(ctx) {
ctx.beginPath();
ctx.moveTo(this.x, this.y);
ctx.lineTo(this.x+ this.length*this.speedX/this.speedNorm,
this.y+ this.length*this.speedY/this.speedNorm );
ctx.strokeStyle = '#F00';
ctx.stroke();
}
to 'launch' an arrow,
Arrow.prototype.launch(initialSpeed, angle) {
this.speedX = initialSpeed * Math.cos(angle);
this.speedY = initialSpeed * Math.sin(angle);
}

Categories

Resources