There is a spiral rise effect as showed bellow: A demo can be found here: http://openlayers.org/en/latest/examples/dynamic-data.html
In the bottom of the demo page, an algorithm is used to implement this effect. But I can not figure out how does it work.
var t = theta + 2 * Math.PI * i / n;
var x = (R + r) * Math.cos(t) + p * Math.cos((R + r) * t / r);
var y = (R + r) * Math.sin(t) + p * Math.sin((R + r) * t / r);
What does R, r and p means? And how to understand the formula above? Can someone explain detail for me? Any help is appreciated.
I can recognize that code draws epicycloid curve (+ it's phase theta permanently changes to provide moving effect).
You can refer to R as radius of inner (here bigger) circle, p and r (equal values here) as radius of outer (here smaller) circle. Here r looks like radius of coil of toroidal spring.
The first summands correspond to the center of outer circle, the second ones - to the second-order rotation about outer circle center.
Play with these values and observe effects
Note that if you change p to make it not equal to r, you'll get epitrochoid curve (more general kind of epicycloid)
Related
I'm making a game in javascript, where an object is supposed to bounce from walls. I really tried to get it to work myself, but it never works correctly.
Let's say theres a ball bouncing inside this cage (blue = 30°, brown = 60°);
The ball's coordinates are known. The angle of movement is known. The point of collision (P) coordinates are known. The angle of the wall is known. The ball's position is updating it's coordinates inside a setInterval function using this function:
function findNewPoint(x, y, angle, distance) {
var result = {};
result.x =(Math.cos(angle * Math.PI / 180) * distance + x);
result.y = (Math.sin(angle * Math.PI / 180) * distance + y);
return result;
So, upon colliding, there should be a function that properly changes the ball's angle. It's a very complicated problem it seems, because even if I know that the wall is 30°, its important to know from what side the ball is colliding into it. I tried using the "Reflection across a line in the plane" formula and also some vectors, but it never worked out for me. I'm not expecting a complete answer with code, if someone could suggest in what way this should be programmed, it would help aswell.
Edit:
Thanks for your tips guys, I realized what was causing the most confustion; if I select an angle on the canvas with my mouse, the starting coordinate(0,0) is in the bottom left corner. But since the canvas' starting coordinate is in the top left corner, this has to be considered.
Basically using this formula for calculating the angle:
function angle(cx, cy, ex, ey) {
var dy = ey - cy;
var dx = ex - cx;
var theta = Math.atan2(dy, dx);
theta *= 180 / Math.PI;
return theta;
}
if the ball moved from (50,50) to (100,100), the angle would be -45.
Now, this angle changes in the following way when hitting walls:
If im honest, I got these out of trial and error, am not really understanding why exactly 60 and 120.
It is not wise to use angle for moving ball and calculate Cos/Sin again and again. Instead use unit velocity direction vector with components vx, vy like this:
new_x = old_x + vx * Velocity_Magnitude * Time_Interval
Note that vx = Cos(angle), vy = Sin(angle), but with direction approach you seldom need to use trigonometric functions.
Tilted wall with angle Fi has normal
nx = -Sin(Fi)
ny = Cos(Fi)
To find reflection , you need to calculate dot product of velocity and normal
dot = vx * nx + vy * ny
Velocity after reflection transforms:
vnewx = v.x - 2 * dot * n.x
vnewy = v.y - 2 * dot * n.y
Use these values for further moving
(note that you can use both internal and external normal direction, because direction flip changes both components, and sign of 2 * dot * n.x remains the same)
Examples:
horizontal moving right
vx=1, vy=0
30 degrees wall has normal
nx=-1/2, ny=Sqrt(3)/2
dot = -1/2
vnewx = 1 - 2 * (-1/2) * (-1/2) = 1/2
vnewy = 0 - 2 * (-1/2) * Sqrt(3)/2 = Sqrt(3)/2
(velocity direction angle becomes 60 degrees)
horizontal moving left
vx=-1, vy=0
330 degrees wall (left bottom corner) has normal
nx=1/2, ny=Sqrt(3)/2
dot = -1/2
vnewx = -1 - 2 * (-1/2) * (1/2) = -1/2
vnewy = 0 - 2 * (-1/2) * (Sqrt(3)/2) = Sqrt(3)/2
(velocity direction angle becomes 120 degrees)
Here is a function that returns the angle of reflection given an angle of incidence and a surface angle (in degrees). It also ensures that the returned angle is between 0 and 359 degrees.
function angleReflect(incidenceAngle, surfaceAngle){
var a = surfaceAngle * 2 - incidenceAngle;
return a >= 360 ? a - 360 : a < 0 ? a + 360 : a;
}
Here's a demonstration, where the blue line is the angle of incidence, the purple line is the angle of reflection, and the black line is the surface.
If you're assuming that the ball behaves like light bouncing off a mirror, then the angle of incidence equals the angle of reflection.
So your board is 30° from 0° (straight up). The means the normal (perpendicular to the board at the point the ball hits ) is 300°. Say the ball arrives from 280°, it must leave at 320° as the difference between the angle of incidence and the normal and the angle of reflection and the normal must be equal.
In the Social Isometric Games book, page 53, there is a description of the method, that defines a title using mouse cursor coordinates. It works well, but it is not clear what principles are used to make it work. Can someone explain this algorithm in details? Maybe you have some links to the formula. Or maybe you can advise me on which field of science i should look at.
Here is an example of a code that I am interested in:
var col = (e.clientY - gridOffsetY) * 2; //???
col = ((gridOffsetX + col) - e.clientX) / 2; //???
var row = ((e.clientX + col) - tile.height) - gridOffsetX; //???
As I can see, height of the rhombus cell is 2*p, width is 4*p, where p is characteristic size value.
Let's coordinates of base point - top vertice of top cell is (0, 0).
So top-right edge vector is tr=(2p, p), top-left vector is tl=(-2p, p).
Let's mouse point is (mx, my) relative to base point. To find what cell it belongs to, one could decompose vector (mx, my) by basis vectors tl, tr
mx = R * tl.x + C * tr.x
my = R * tl.y + C * tr.y
or
mx = R * 2 * p + C * p
my = R * (- 2 * p) + C * p
to find C , we can add both equations
mx + my = 2 * C * p
C = (mx + my) / (2 * p)
column = Floor(C) //integer part of C
to find R, subtract equations
R = (mx - my) / (4 * p)
row = Floor(R)
other calculations take into account shift of the grid on the screen
it's probably not the right place to post this but i don't know where else to post it.
i have 5 lines (d1 -> d5) equally distributed from each other in 3d perspective, i have the values of (a) angle, (d1) and (b5). i need to calculate (b2, b3, b4, d2, d3, d4, d5) with jquery.
i can calculate d5 with:
d5 = d1 - ( b5 * Math.tan(a))
but i have no idea how to calculate b2, b3 and b4. (d1 is divided into 4 identical segaments (s))
any help would be appreciated.
What you're looking for is a projective scale. The easiest way to do this computationally is to use homogenous coordinates, take a rectangle (like the one in the first picture below) on which V is "infinitely far to the right" and find a projective transformation that maps this rectangle to the trapezium in the second picture. The vertices of the rectangle are (0|0), (0|d1), (b5|d1), (b5|0) and the corresponding vertices of the trapezium are (0|0), (0|d1), (b5|d5), (b5|0).
Since these are four points of which no three are collinear, we can find a unique matrix (up to scaling) M for this transformation. After some maths, it turns out that this matrix is:
[d1*b5,0,0]
[0,b5*d5,0]
[d1-d5,0,b5*d5]
If you want to find the coordinates b3 and d3, for instance, you can multiply this matrix with homogenous coordinates of the point in the middle of the line, i.e. the vector (0.5*b5,d1,1)^T and you get the homogenous coordinates of the point (b3|d3), which can be converted into Euclidean coordinates by dehomogenisation, i.e. dividing the first two components by the third.
In general, if you have two points (b1|d1) and (bn|dn) and want to know the coordinates of n-2 equidistant points inbetween on a projective scale like this, you can compute the coordinates bi and di as like this (in your case, n would be 5, of course):
let M := matrix [[d1*bn, 0, 0], [0, bn*dn, 0], [d1-dn, 0, bn*dn]]
let v := ((i-1)/(n-1)*bn, d1, 1)
let (x,y,z) := M*v
let bi := x/z and di := y/z
As you see, this is a simple algorithm for computing the coordinates of these projectively equidistant points, and it generalises nicely to arbitrary numbers of points.
If you'd rather have a closed formula, you can compute the bi and di directly as:
let bi := (bn*d1*(i-1))/(dn*n+(d1-dn)*i-d1)
let di := d1*dn*(n-1)/(dn*n+(d1-dn)*i-d1)
First we need to calculate what the length of the adjacent side of the whole triangle d1->v->c is (the left vertical side of it):
tan(Θ) = opposite / adjacent
opposite * tan(Θ) = adjacent
adjacent = opposite * tan(Θ)
adjacent = d1 * tan(a)
Next thing we need is to know how much off the ground each line from v is when it gets to line d1. Given that variable s is the same for all divisions and assuming N dividing segments (in this case 3), our counter is i that starts from 1 and goes to N:
opposite(i) = i * (d1 / N)
Now we need the angle that line from v to each marker s makes:
tan(Θi) = opposite / adjacent
Θi = arctan(opposite / adjacent)
Θi = arctan(opposite(i) / adjacent)
Θi = arctan((i * (d1 / N)) / (d1 * tan(a)))
Using some geometry/trig we can say that angle going from d1 through point c to top of d5 is (90° - a). We will call this angle a'
a' = 90° - a
Law of sines tells us that:
A' / sin(a') = opposite(i) / sin(b')
so now we solve for A' since we need some help with getting the dimensions of the orange square:
A' = (opposite(i) * sin (a')) / sin(b')
since b' = (a + Θi) this turns into:
A' = (opposite(i) * sin (90° - a)) / sin(a + Θi)
Same thing applied but solving for h in the orange triangle (see picture):
h / sin(90°-Θi) = A' / sin(90°)
h = (A' * sin(90°-Θi)) / sin(90°)
b2 = h
Putting it all together (hopefully without copy/paste mistakes on my part) and without simplifications:
b2 = (((( i * (d1 / N)) * sin (90° - a)) / sin(a + Θi)) * sin(90° - arctan((i * (d1 / N)) / (d1 * tan(a))))) / sin(90°)
Now rinse/repeat for each value of i and turn into code (I would have done that but I'm too tired) :)
I'm trying to develop a small application using html5 and canvas/KineticJS. I'd like to trace a number of rays that start from a 2d point to infinite, just setting a custom angle degree. For example, if I set 90° the app should render four rays (two straight lines, one vertical and one horizontal that meet in my 2d point). If I set 60° I should see 3 straight lines, like an asterisk *
The longest line you'll ever have to draw is the size of the canvas's diagonal:
var r = Math.sqrt(Math.pow(canvas.width, 2) + Math.pow(canvas.height, 2));
Use sin and cos to calculate each of your end points at that radius:
var theta = delta * Math.PI / 180.0;
var dx = r * Math.cos(n * theta);
var dy = r * Math.sin(n * theta);
Then, just draw lines from (x, y) to (x + dx, y + dy). Simples.
I found this excellent question and answer which starts with x/y (plus the center x/y and degrees/radians) and calculates the rotated-to x'/y'. This calculation works perfectly, but I would like to run it in the opposite direction; starting with x'/y' and degrees/radians, I would like to calculate the originating x/y and the center x/y.
(x', y') = new position
(xc, yc) = center point things rotate around
(x, y) = initial point
theta = counterclockwise rotation in radians (radians = degrees * Pi / 180)
dx = x - xc
dy = y - yc
x' = xc + dx cos(theta) - dy sin(theta)
y' = yc + dx sin(theta) + dy cos(theta)
Or, in JavaScript/jQuery:
XYRotatesTo = function($element, iDegrees, iX, iY, iCenterXPercent, iCenterYPercent) {
var oPos = $element.position(),
iCenterX = ($element.outerWidth() * iCenterXPercent / 100),
iCenterY = ($element.outerHeight() * iCenterYPercent / 100),
iRadians = (iDegrees * Math.PI / 180),
iDX = (oPos.left - iCenterX),
iDY = (oPos.top - iCenterY)
;
return {
x: iCenterX + (iDX * Math.cos(iRadians)) - (iDY * Math.sin(iRadians)),
y: iCenterY + (iDX * Math.sin(iRadians)) + (iDY * Math.cos(iRadians))
};
};
The math/code above solves for the situation in Figure A; it calculates the position of the destination x'/y' (green circle) based on the known values for x/y (red circle), the center x/y (blue star) and the degrees/radians.
But I need math/code to solve for Figure B; where I can find not only the destination x/y (green circle), but also the destination center x/y (green star) from the known values of the starting x/y (grey circle, though probably not needed), the destination x'/y' (red circle) and the degrees/radians.
The code above will solve for the destination x/y (green circle) via iDegrees * -1 (thanks to #andrew cooke's answer which has since been removed by him), but in order to do that I need to feed into it the location of the destination center x/y (green star), and that is the calculations I'm currently missing, as you can see in Diagram C, below:
So... how do I find the coordinates ?/? (green star) given n, A (angle) and x'/y' (red circle)?
You're trying to find an inverse transformation. You start with the composition of two linear transformations, a translation T and a rotation R. You apply R first to a vector x and T second, so the expression is y = TRx. To solve the inverse problem you need the inverse of TR, written (TR)-1, which is equal to R-1T-1. The inverse of the rotation R is just the rotation by the negative of the angle (which you mention). The inverse of the translation is, similarly, the original translation multiplied by -1. So your answer is x = R-1T-1y.
In your present situation, you're given the rotation by means of its angle, but you'll need to compute the translation. You'll need the grey circle, which you didn't think you would need. Apply the rotation R (not its inverse) to the gray circle. Subtract this point from the red circle. This is the original translation T. Reverse the sign to get T-1.