Add Velocity Relative To Object - javascript

I am trying to make a train in js but i want add the velocity to the train.
but the train has an other axis relative to the canvas so how can i add the velocity relative to canvas
http://snapsoft.eu/example.png

If train system is rotated relative to stationary system by angle Theta, then you can transform velocity vector Vr (in rotated) to Vs (in stationary):
Vs.X = Vr.X * Cos(Theta) - Vr.Y * Sin(Theta)
Vs.Y = Vr.X * Sin(Theta) + Vr.Y * Cos(Theta)
If rotated system moves with velocity W, then add W also
Vs.X = W.X + Vr.X * Cos(Theta) - Vr.Y * Sin(Theta)
Vs.Y = W.Y + Vr.X * Sin(Theta) + Vr.Y * Cos(Theta)
In your example
Theta = -Pi/4
Vs.X = 0.5 * 0.707 + 0 * 0.707 = 0.3535
Vs.Y = - 0.5 * 0.707 + 0 * 0.707 = -0.3535

Related

How to rotate a squashed circle (ellipse) in degrees

I draw a circle path with a point (that's circle_x and circle_Y) in my code like this:
var circSize = 15;
var circArc = 2 * Math.PI;
var aspectAdd = 10;
var circle_x = (circSize + aspectAdd) * Math.cos(circArc);
var circle_y = (circSize * Math.sin(circArc);
The circle is then squashed with aspectAdd to make it an ellipse.
The ellipse is pure an invisible path that is used as an animation path for another point.
How do I rotate the ellipse in degrees?
It has to be in pure mathematics. I don't use the canvas ctx or svg path script for this instance (where I could easily give a rotation value).
You probably should've asked this in a math stackoverflow.
You need to apply a rotation to your parameteric functions.
Specifically,
r_x = x * cos(theta) - y * sin(theta)
r_y = x * sin(theta) + y * cos(theta)
I'll let you handle the substitions.
Equation to find points of ellipse with semi-axes rx and ry, rotated by angle fi.
Calculate points for t parameter in range 0..2*Pi with needed step.
x = rx * Cos(t) * Cos(fi) - ry * Sin(t) * Sin(fi) + cx
y = rx * Cos(t) * Sin(fi) + ry * Sin(t) * Cos(fi) + cy
Example for for rx=100, ry=60, fi=-Pi/6:
Addition:
seems you calculate ellipse points in fluid.js file here:
var r_x = circle_x * Math.cos(circRot) - circle_y * Math.sin(circRot);
var r_y = circle_x * Math.sin(circRot) + circle_y * Math.cos(circRot);
So you need to modify these lines to test them:
var ellipseRot = Math.PI / 4
var r_x = circle_x * Math.cos(circRot) * Math.cos(ellipseRot)- circle_y * Math.sin(circRot) * Math.sin(ellipseRot);
var r_y = circle_x * Math.sin(circRot) *Math.sin(ellipseRot) + circle_y * Math.cos(circRot) * Math.cos(ellipseRot);
then change ellipseRot with slider

Move an object along the trajectory of a hexagon

As you can see in the attached GIF, the white dot moves in circular path.
How to make it move along the trajectory of the hexagon. in other words, make the dot follow the hexagon path?
I am rotating the white dot using the following code:
const angle = Math.PI / 6 * delta; // delta is the current time to increment the angle.
const radius = 300;
const x = center.x + Math.cos(angle) * radius;
const y = center.y + Math.sin(angle) * radius;
thank you
There are various ways of doing this. If you want to keep a constant angular rotation speed around the centre of the hexagon, then you could modify the radius of the moving object according to the angle of rotation.
First choose the radius corresponding to the vertices of the hexagon. In this example, I'm using a radius of 90px. The inner radius (of the inscribed circle tangential to the sides of the hexagon) is sqrt(0.75) times this value:
r_outer = 90.0
r_inner = r_outer * Math.sqrt(0.75)
If an angle of zero corresponds to the middle of one side of the hexagon, then by simple geometry the radius along this side will equal r_inner / Math.cos(theta) as theta varies from −30° to +30°. You can use a floating-point modulus operator to confine the angle to the range from 0 to 60°. To keep the angle within ±30° for the radius calculations, just add 30° to the angle before calculating the modulus, and subtract it afterwards.
So the complete calculation looks something like this:
r0 = 90.0 (Outer radius)
r1 = r0 * sqrt(0.75) (Inner radius)
d30 = 30 * pi/180 (30 degrees in radians)
d60 = 60 * pi/180 (60 degrees in radians)
r = r1 / cos((theta + d30) % d60 - d30)
x = x_center + sin(theta) * r
y = y_center - cos(theta) * r
Here's a working example:
let theta=0.0;
let r0 = 90.0; // Outer radius
let r1 = r0 * Math.sqrt(0.75); // Inner radius
let d30 = 30 * Math.PI/180; // 30 degrees in radians
let d60 = 60 * Math.PI/180; // 60 degrees in radians
function move_dot() {
theta += 0.025;
let r = r1 / Math.cos((theta + d30) % d60 - d30);
let x = Math.sin(theta) * r;
let y = -Math.cos(theta) * r;
document.getElementById('dot').style.cx=x.toFixed(2)+'px';
document.getElementById('dot').style.cy=y.toFixed(2)+'px';
}
document.body.onload=function(){setInterval(move_dot,30);}
#hex { fill:none; stroke:#aaf; stroke-width:1; }
#dot { fill:#000; stroke:none; cx:90px; cy:0px; }
<svg width="200" height="200" viewBox="-100 -100 200 200">
<path id="hex" d="M45-77.94 90 0 45 77.94-45 77.94-90 0-45-77.94Z"/>
<circle id="dot" cx="90" cy="0" r="5"/>
</svg>

Html5 canvas - Translate function behaving weirdly

Im trying to use the translate function when drawing a circle, but when i try to do it it doesnt behave properly. Instead of drawing the circle it draws this:
if the image doesnt show up: click here
This is my code for the drawing of the circle (inside a circle class):
ctx.strokeStyle = "white"
ctx.translate(this.x, this.y)
ctx.beginPath()
// Draws the circle
ctx.arc(0, 0, this.r, 0, 2 * Math.PI)
ctx.stroke()
ctx.closePath()
// tried with and without translating back, inside and outside of this function
ctx.translate(0, 0)
This is the rest of my code:
let canvas
let ctx
let circle
function init() {
canvas = document.querySelector("#canvas")
ctx = canvas.getContext("2d")
// x, y, radius
circle = new Circle(canvas.width/5, canvas.height/2, 175)
requestAnimationFrame(loop)
}
function loop() {
// Background
ctx.fillStyle = "black"
ctx.fillRect(0, 0, canvas.width, canvas.height)
// The function with the drawing of the circle
circle.draw()
requestAnimationFrame(loop)
}
Btw: When i dont use the translate function it draws the circle normally.
Edit:
I answered my own question below as i found that the translate functions a little bit differently in javascript than how i thought it would.
Answer
Your function
ctx.strokeStyle = "white"
ctx.translate(this.x, this.y)
ctx.beginPath()
// Draws the circle
ctx.arc(0, 0, this.r, 0, 2 * Math.PI)
ctx.stroke()
ctx.closePath()
// tried with and without translating back, inside and outside of this function
ctx.translate(0, 0)
Can be improved as follows
ctx.strokeStyle = "white"
ctx.setTransform(1, 0, 0, 1, this.x, this.y); //BM67 This call is faster than ctx.translate
ctx.beginPath()
ctx.arc(0, 0, this.r, 0, 2 * Math.PI)
ctx.stroke()
// ctx.closePath() //BM67 This line does nothing and is not related to beginPath.
// tried with and without translating back, inside and outside of this function
//ctx.translate(0, 0) //BM67 You don't need to reset the transform
// The call to ctx.setTransfrom replaces
// the current transform before you draw the circle
and would look like
ctx.strokeStyle = "white"
ctx.setTransform(1, 0, 0, 1, this.x, this.y);
ctx.beginPath()
ctx.arc(0, 0, this.r, 0, 2 * Math.PI)
ctx.stroke()
Why this is better will need you to understand how 2D transformations work and why some 2D API calls should not be used, and that 99% of all transformation needs can be done faster and with less mind f with ctx.setTransform than the poorly named ctx.translate, ctx.scale, or ctx.rotate
Read on if interested.
Understanding the 2D transformation
When you render to the canvas all coordinates are transformed via the transformation matrix.
The matrix consists of 6 values as set by setTransform(a,b,c,d,e,f). The values a,b,c,d,e,f are rather obscure and the literature does not help explaining them.
The best way to think of them is by what they do. I will rename them as setTransform(xAxisX, xAxisY, yAxisX, yAxisY, originX, originY) they represent the direction and size of the x axis, y axis and the origin.
xAxisX, xAxisY are X Axis X, X Axis Y
yAxisX, yAxisY are Y Axis X, Y Axis Y
originX, originY are the canvas real pixel coordinates of the origin
The default transform is setTransform(1, 0, 0, 1, 0, 0) meaning that the X Axis moves across 1 down 0, the Y Axis moves across 0 and down 1 and the origin is at 0, 0
You can manually apply the transform to a 2D point as follows
function transformPoint(x, y) {
return {
// Move x dist along X part of X Axis
// Move y dist along X part of Y Axis
// Move to the X origin
x : x * xAxisX + y * yAxisX + originX,
// Move x dist along Y part of X Axis
// Move y dist along Y part of Y Axis
// Move to the Y origin
y : x * xAxisY + y * yAxisY + originY,
};
}
If we substitute the default matrix setTransform(1, 0, 0, 1, 0, 0) we get
{
x : x * 1 + y * 0 + 0,
y : x * 0 + y * 1 + 0,
}
// 0 * n is 0 so removing the * 0
{
x : x * 1,
y : y * 1,
}
// 1 time n is n so remove the * 1
{
x : x,
y : y,
}
As you can see the default transform does nothing to the point
Translation
If we set the translation ox, oy to setTransform(1, 0, 0, 1, 100, 200) the transform is
{
x : x * 1 + y * 0 + 100,
y : x * 0 + y * 1 + 200,
}
// or simplified as
{
x : x + 100,
y : y + 200,
}
Scale
If we set the scale of the X Axis and Y Axis to setTransform(2, 0, 0, 2, 100, 200) the transform is
{
x : x * 2 + y * 0 + 100,
y : x * 0 + y * 2 + 200,
}
// or simplified as
{
x : x * 2 + 100,
y : y * 2 + 200,
}
Rotation
Rotation is a little more complex and requires some trig. You can use cos and sin to get a unit vector in a direction angle (NOTE all angles are in radians PI * 2 is 360deg, PI is 180deg, PI / 2 is 90deg)
Thus the unit vector for 0 radians is
xAxisX = Math.cos(0);
yAxisY = Math.sin(0);
So for angles 0, PI * (1 / 2), PI, PI * (3 / 2), PI * 2
angle = 0;
xAxisX = Math.cos(angle); // 1
yAxisY = Math.sin(angle); // 0
angle = Math.PI * (1 / 2); // 90deg (points down screen)
xAxisX = Math.cos(angle); // 0
yAxisY = Math.sin(angle); // 1
angle = Math.PI; // 180deg (points to left screen)
xAxisX = Math.cos(angle); // -1
yAxisY = Math.sin(angle); // 0
angle = Math.PI * (3 / 2); // 270deg (points to up screen)
xAxisX = Math.cos(angle); // 0
yAxisY = Math.sin(angle); // -1
Uniform transformation
In 90% of cases when you transform points you want the points to remain square, that is the Y axis remains at PI / 2 (90deg) clockwise of the X axis and the Scale of the Y axis is the same as the scale of the X axis.
You can rotate a vector 90 deg by swapping the x and y and negating the new x
x = 1; // X axis points from left to right
y = 0; // No downward part
// Rotate 90deg clockwise
x90 = -y; // 0 no horizontal part
y90 = x; // Points down the screen
We can take advantage of this simple 90 rotation to create a uniform rotation by only defining the angle of the X Axis
xAxisX = Math.cos(angle);
xAxisY = Math.sin(angle);
// create a matrix as setTransform(xAxisX, xAxisY, -xAxisY, xAxisX, 0, 0)
// to transform the point
{
x : x * xAxisX + y * (-xAxisY) + 0,
y : x * xAxisY + y * xAxisX + 0,
}
// to simplify
{
x : x * xAxisX - y * xAxisY,
y : x * xAxisY + y * xAxisX,
}
Rotate, scale, and translate
Using the above info you can now manually create a uniform matrix using only 4 values, The origin x,y the scale, and the rotate
function transformPoint(x, y, originX, originY, scale, rotate) {
// get the direction of the X Axis
var xAxisX = Math.cos(rotate);
var xAxisY = Math.sin(rotate);
// Scale the x Axis
xAxisX *= Math.cos(rotate);
xAxisY *= Math.sin(rotate);
// Get the Y Axis as X Axis rotated 90 deg
const yAxisX = -xAxisY;
const yAxisY = xAxisX;
// we have the 6 values for the transform
// [xAxisX, xAxisY, yAxisX, yAxisY, originX, originY]
// Transform the point
return {
x : x * xAxisX + y * yAxisX + originX,
y : x * xAxisY + y * yAxisY + originY,
}
}
// we can simplify the above down to
function transformPoint(x, y, originX, originY, scale, rotate) {
// get the direction and scale of the X Axis
const xAxisX = Math.cos(rotate) * scale;
const xAxisY = Math.sin(rotate) * scale;
// Transform the point
return {
x : x * xAxisX - y * xAxisY + originX,
// note the ^ negative
y : x * xAxisY + y * xAxisX + originY,
}
}
Or we can create the matrix using ctx.setTransform using the above and let the GPU hardware do the transform
function createTransform(originX, originY, scale, rotate) {
const xAxisX = Math.cos(rotate) * scale;
const xAxisY = Math.sin(rotate) * scale;
ctx.setTransform(xAxisX, xAxisY, -xAxisY, xAxisX, originX, originY);
}
Setting or Multiplying the transform.
I will rename this section to
WHY YOU SHOULD AVOID ctx.translate, ctx.scale, or ctx.rotate
The 2D API has some bad naming which is the reason for 90% of the transform question that appear in html5-canvas tag.
If we rename the API calls you will get a better understanding of what they do
ctx.translate(x, y); // should be ctx.multiplyCurrentMatirxWithTranslateMatrix
// or shorten ctx.matrixMutliplyTranslate(x, y)
The function ctx.translate does not actually translate a point, but rather it translates the current matrix. It does this by first creating a matrix and then multiplying that matrix with the current matrix
Multiplying one matrix by another, means that the 6 values or 3 vectors for X Axis, Y Axis, and Origin are transform by the other matrix.
If written as code
const current = [1,0,0,1,0,0]; // Default matrix
function translate(x, y) { // Translate current matrix
const translationMatrix = [1,0,0,1,x,y];
const c = current
const m = translationMatrix
const r = []; // the resulting matrix
r[0] = c[0] * m[0] + c[1] * m[2]; // rotate current X Axis with new transform
r[1] = c[0] * m[1] + c[1] * m[3];
r[2] = c[2] * m[0] + c[3] * m[2]; // rotate current Y Axis with new transform
r[3] = c[2] * m[1] + c[3] * m[3];
r[4] = c[4] + m[4]; // Translate current origine with transform
r[5] = c[5] + m[5];
c.length = 0;
c.push(...r);
}
That is the simple version. Under the hood you can not multiply the two matrix as they have different dimensions. The actual matrix is stored as 9 values and requires 27 multiplications and 18 additions
// The real 2D default matrix
const current = [1,0,0,0,1,0,0,0,1];
// The real Translation matrix
const translation = [1,0,0,0,1,0,x,y,1];
//The actual transformation calculation
const c = current
const m = translationMatrix
const r = []; // the resulting matrix
r[0] = c[0] * m[0] + c[1] * m[3] + c[2] * m[6];
r[1] = c[0] * m[1] + c[1] * m[4] + c[2] * m[7];
r[2] = c[0] * m[2] + c[1] * m[5] + c[2] * m[8];
r[3] = c[3] * m[0] + c[4] * m[3] + c[5] * m[6];
r[4] = c[3] * m[1] + c[4] * m[4] + c[5] * m[7];
r[5] = c[3] * m[2] + c[4] * m[5] + c[5] * m[8];
r[6] = c[6] * m[0] + c[7] * m[3] + c[8] * m[6];
r[7] = c[6] * m[1] + c[7] * m[4] + c[8] * m[7];
r[8] = c[6] * m[2] + c[7] * m[5] + c[8] * m[8];
That's a bucket load of math that is always done under the hood when you use ctx.translate and NOTE that this math is not done on the GPU, it is done on the CPU and the resulting matrix is moved to the GPU.
If we continue the renaming
ctx.translate(x, y); // should be ctx.matrixMutliplyTranslate(
ctx.scale(scaleY, scaleX); // should be ctx.matrixMutliplyScale(
ctx.rotate(angle); // should be ctx.matrixMutliplyRotate(
ctx.transform(a,b,c,d,e,f) // should be ctx.matrixMutliplyTransform(
It is common for JS scripts to use the above function to scale translate and rotates, usually with reverse rotations and translations because their objects are not defined around there local origins.
Thus when you do the following
ctx.rotate(angle);
ctx.scale(sx, sy);
ctx.translate(x, y);
The under the hood math must do all of the following
// create rotation matrix
rr = [Math.cos(rot), Math.sin(rot), 0, -Math.sin(rot), Math.cos(rot), 0, 0, 0, 1];
// Transform the current matix with the rotation matrix
r[0] = c[0] * rr[0] + c[1] * rr[3] + c[2] * rr[6];
r[1] = c[0] * rr[1] + c[1] * rr[4] + c[2] * rr[7];
r[2] = c[0] * rr[2] + c[1] * rr[5] + c[2] * rr[8];
r[3] = c[3] * rr[0] + c[4] * rr[3] + c[5] * rr[6];
r[4] = c[3] * rr[1] + c[4] * rr[4] + c[5] * rr[7];
r[5] = c[3] * rr[2] + c[4] * rr[5] + c[5] * rr[8];
r[6] = c[6] * rr[0] + c[7] * rr[3] + c[8] * rr[6];
r[7] = c[6] * rr[1] + c[7] * rr[4] + c[8] * rr[7];
r[8] = c[6] * rr[2] + c[7] * rr[5] + c[8] * rr[8];
// STOP the GPU and send the resulting matrix over the bus to set new state
c = [...r]; // set the current matrix
// create the scale matrix
ss = [scaleX, 0, 0, 0, scaleY, 0, 0, 0, 1];
// scale the current matrix
r[0] = c[0] * ss[0] + c[1] * ss[3] + c[2] * ss[6];
r[1] = c[0] * ss[1] + c[1] * ss[4] + c[2] * ss[7];
r[2] = c[0] * ss[2] + c[1] * ss[5] + c[2] * ss[8];
r[3] = c[3] * ss[0] + c[4] * ss[3] + c[5] * ss[6];
r[4] = c[3] * ss[1] + c[4] * ss[4] + c[5] * ss[7];
r[5] = c[3] * ss[2] + c[4] * ss[5] + c[5] * ss[8];
r[6] = c[6] * ss[0] + c[7] * ss[3] + c[8] * ss[6];
r[7] = c[6] * ss[1] + c[7] * ss[4] + c[8] * ss[7];
r[8] = c[6] * ss[2] + c[7] * ss[5] + c[8] * ss[8];
// STOP the GPU and send the resulting matrix over the bus to set new state
c = [...r]; // set the current matrix
// create the translate matrix
tt = [1, 0, 0, 0, 1, 0, x, y, 1];
// translate the current matrix
r[0] = c[0] * tt[0] + c[1] * tt[3] + c[2] * tt[6];
r[1] = c[0] * tt[1] + c[1] * tt[4] + c[2] * tt[7];
r[2] = c[0] * tt[2] + c[1] * tt[5] + c[2] * tt[8];
r[3] = c[3] * tt[0] + c[4] * tt[3] + c[5] * tt[6];
r[4] = c[3] * tt[1] + c[4] * tt[4] + c[5] * tt[7];
r[5] = c[3] * tt[2] + c[4] * tt[5] + c[5] * tt[8];
r[6] = c[6] * tt[0] + c[7] * tt[3] + c[8] * tt[6];
r[7] = c[6] * tt[1] + c[7] * tt[4] + c[8] * tt[7];
r[8] = c[6] * tt[2] + c[7] * tt[5] + c[8] * tt[8];
// STOP the GPU and send the resulting matrix over the bus to set new state
c = [...r]; // set the current matrix
So that is a total of 3 GPU state changes, 81 floating point multiplications, 54 floating point additions, 4 high level math calls and about 0.25K RAM allocated and dumped for GC to clean up.
Easy and Fast
The function setTransform does not multiply matrices. It converts the 6 arguments to a 3 by 3 matrix by directly putting the values into the current transform and the moving it to the GPU
// ct is the current transform 9 value under hood version
// The 6 arguments of the ctx.setTransform call
ct[0] = a;
ct[1] = b;
ct[2] = 0;
ct[3] = c;
ct[4] = d;
ct[5] = 0;
ct[6] = e;
ct[7] = f;
ct[8] = 1;
// STOP the GPU and send the resulting matrix over the bus to set new state
So if you use the JS function
function createTransform(originX, originY, scale, rotate) {
const xAxisX = Math.cos(rotate) * scale;
const xAxisY = Math.sin(rotate) * scale;
ctx.setTransform(xAxisX, xAxisY, -xAxisY, xAxisX, originX, originY);
}
You reduce the complexity under the hood to 2 floating point multiplications, 2 high level math function calls, 1 floating point addition (negating the -xAxisY), one GPU state change, and using only 64 bytes of RAM from the heap.
And because the ctx.setTransform does not depend on the current state of the 2D transform you don't need to use ctx.resetTransform, or ctx.save and restore
When animating many items the performance benefit is noticeable. When struggling with the complexity of transformed matrices the simplicity of setTransform can save you hours of time better spend creating good content.
The problem is that after each translation in Circle.draw(), the context is not restored to its original state. Future translate(this.x, this.y); calls keep moving the context right and downward relative to the previous transformation endlessly.
Use ctx.save() and ctx.restore() at the beginning and end of your draw() function to move the context back to its original location after drawing.
class Circle {
constructor(x, y, r) {
this.x = x;
this.y = y;
this.r = r;
}
draw() {
ctx.save();
ctx.strokeStyle = "white";
ctx.translate(this.x, this.y);
ctx.beginPath();
ctx.arc(0, 0, this.r, 0, 2 * Math.PI);
ctx.closePath();
ctx.stroke();
ctx.restore();
}
}
let canvas;
let ctx;
let circle;
(function init() {
canvas = document.querySelector("canvas");
canvas.width = innerWidth;
canvas.height = innerHeight;
ctx = canvas.getContext("2d");
circle = new Circle(canvas.width / 2, canvas.height / 2, 30);
loop();
})();
function loop() {
ctx.fillStyle = "black";
ctx.fillRect(0, 0, canvas.width, canvas.height);
circle.draw();
requestAnimationFrame(loop);
}
body {
margin: 0;
height: 100vh;
}
<canvas></canvas>
Alternately, you can just write:
ctx.strokeStyle = "white";
ctx.beginPath();
ctx.arc(this.x, this.y, this.r, 0, 2 * Math.PI);
ctx.closePath();
ctx.stroke();
and skip the translation step entirely.
I just found the answer. As #mpen commented ctx.translate(0, 0) doesnt reset the translation, but this does: ctx.setTransform(1, 0, 0, 1, 0, 0);. The ctx.translate function translates related to the previous translation.
In your code, the ctx.translate(0, 0) does absolutely nothing, because that function sets transformation relative to current transformation. You are telling the context "move 0 pixels right and 0 pixels down". You could fix that by changing the line to ctx.translate(-this.x, -this.y) so you do the opposite transformation.
However, usually, this is done by saving the context state with CanvasRenderingContext2D.save before making transformations and then restoring it with CanvasRenderingContext2D.restore. In your example, it would look like this:
ctx.save(); // here, we are saving state of the context
ctx.strokeStyle = "white";
ctx.translate(this.x, this.y);
ctx.beginPath();
// Draws the circle
ctx.arc(0, 0, this.r, 0, 2 * Math.PI);
ctx.stroke();
ctx.closePath();
ctx.restore(); // after this, context will have the state it had when we called save()
This way is good in cases when you want to return the context to its original state after the operation, rather than the default state (which you usually do when making more complex operations), and when you do multiple transformations which would be complicated to revert.

How to "push out "XYZ coordinates forming a 3D orbit with an offset in the middle

I have a orbit of length 200. But it is centered around a sun of radius 0 (length 0). Now I want to expand the sun to have a radius of 1 and "push" out the outer orbits as well.
The XYZ coordinates look like this:
[-6.76, 5.75, -1.06],
[-6.95, 5.54, -0.91],
[-7.13, 5.33, -0.75],
[-7.31, 5.11, -0.58]
... followed by 196 more coordinates
I tried tried a lot of things to make the circle bigger * radius and / someNumbers. To at least try to do it myself.
But i lost it when i made an if like this:
If(the x coordination > 0)
the x coordination += 1;
}
Else{
the x coordination += 1;
}
And also for Y and Z but when they came close to the 1 and -1 position of that axis they skipped to the other side.
Creating a line (with the width of 1 on both sides) of emptiness along the axis.
Result of MBo's awnser(view from above):
// arrayIndex is a number to remember at which point it is in the orbit array
satellites.forEach(function (element) {
if (element.arrayIndex>= element.satellite.coordinates.length) {
element.arrayIndex= 0;
}
var posX = element.satellite.coordinates[element.arrayIndex][0];
var posY = element.satellite.coordinates[element.arrayIndex][1];
var posZ = element.satellite.coordinates[element.arrayIndex][2];
R = Math.sqrt(posX^2 + posY^2 + posZ^2);
cf = (R + earthRadius) / R;
xnew = posX * cf;
ynew = posY * cf;
znew = posZ * cf;
// var posX = earthRadius * (element.satellite.coordinates[element.test][0] / (200 * earthRadius) * earthRadius);
// var posY = earthRadius * (element.satellite.coordinates[element.test][1] / (200 * earthRadius) * earthRadius);
// var posZ = earthRadius * (element.satellite.coordinates[element.test][2] / (200 * earthRadius) * earthRadius);
// divide by 100 to scale it down some more
element.position.x = xnew / 100;
element.position.y = ynew / 100;
element.position.z = znew / 100;
element.arrayIndex= element.arrayIndex+ 1;
});
You have orbit radius
/////////R = Sqrt(x^2 + y^2 + z^2)
Edit to avoid confusion:
R = Sqrt(x * x + y * y + z * z)
You need to modify coordinates to make orbit radius R+r. To preserve orbit form, for every point find it's R, and multiply all components by coefficient (R+r)/R
R = Sqrt(x^2 + y^2 + z^2)
cf = (R + r) / R
xnew = x * cf
ynew = y * cf
znew = z * cf

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.

Categories

Resources