I have been making a mod for a game called Minecraft PE and I'm using it to learn. Before I show my code I want you to know that Y is the vertical axis and X and Z is horizontal. Here is some code I used:
Math.asin(Math.sin((fPosXBeforeMoved - sPosX) /
Math.sqrt(Math.pow(fPosXBeforeMoved - sPosX, 2) +
Math.pow(fPosZBeforeMoved - sPosZ, 2))));
I didn't use tan because sometimes it returns something like NaN at a certain angle. This code gives us the sine of the angle when I clearly used Math.asin. angle is a value between -1 and 1, and it works! I know it works, because when I go past the Z axis I was expecting and it did switch from negative to positive. However, I thought it's supposed to return radians? I read somewhere that the input is radians, but my input is not radians. I really want the answer to how my own code works and how I should have done it! I spent all day learning about trigonometry, but I'm really frustrated so now I ask the question from where I get all my answers from!
Can someone please explain how my own code works and how I should modify it to get the angle in radians? Is what I've done right? Am I actually giving it radians and just turned it into some sort of sine degrees type thing?
OK, let's give a quick refresher as to what sin and asin are. Take a look at this right-angle triangle in the diagram below:
Source: Wikipedia
By taking a look at point A of this right-angle triangle, we see that there is an angle formed between the line segment AC and AB. The relationship between this angle and sin is that sin is the ratio of the length of the opposite side over the hypotenuse. In other words:
sin A = opposite / hypotenuse = a / h
This means that if we took a / h, this is equal to the sin of the angle located at A. As such, to find the actual angle, we would need to apply the inverse sine operator on both sides of this equation. As such:
A = asin(a / h)
For example, if a = 1 and h = 2 in our triangle, the sine of the angle that this right triangle makes between AC and AB is:
sin A = 1 / 2
To find the actual angle that is here, we do:
A = asin(1 / 2)
Putting this in your calculator, we get 30 degrees. Radians are another way of representing angle, where the following relationship holds:
angle_in_radians = (angle_in_degrees) * (Math.PI / 180.0)
I'm actually a bit confused with your code, because you are doing asin and then sin after. A property between asin and sin is:
arcsin is the same as asin. The above equation states that as long as x >= -Math.PI / 2, x <= Math.PI / 2 or x >= -90, x <= 90 degrees, then this relationship holds. In your code, the argument inside the sin will definitely be between -1 to 1, and so this actually simplifies to:
(fPosXBeforeMoved - sPosX) / Math.sqrt(Math.pow(fPosXBeforeMoved - sPosX, 2) +
Math.pow(fPosZBeforeMoved - sPosZ, 2));
If you want to find the angle between the points that are moved, then you're not using the right sides of the triangle. I'll cover this more later.
Alright, so how does this relate to your question? Take a look at the equation that you have in your code. We have four points we need to take a look at:
fPosXBeforeMoved - The X position of your point before we moved
sPosX - The X position of your point after we moved
fPosZBeforeMoved - The Z position of your point before we moved
sPosZ - The Z position of your point after we moved.
We can actually represent this in a right-angle triangle like so (excuse the bad diagram):
We can represent the point before you moved as (fPosXBeforeMoved,fPosZBeforeMoved) on the XZ plane, and the point (sPosX,sPosZ) is when you moved after. In this diagram X would be the horizontal component, while Z would be the vertical component. Imagine that you are holding a picture up in front of you. X would be the axis going from left to right, Z would be the axis going up and down and Y would be the axis coming out towards you and going inside the picture.
We can find the length of the adjacent (AC) segment by taking the difference between the X co-ordinates and the length of the opposite (AB) segment by taking the difference between the Z co-ordinates. All we need left is to find the length of the hypotenuse (h). If you recall from school, this is simply done by using the Pythagorean theorem:
h^2 = a^2 + b^2
h = sqrt(a^2 + b^2)
Therefore, if you refer to the diagram, our hypotenuse is thus (in JavaScript):
Math.sqrt(Math.pow(fPosXBeforeMoved - sPosX, 2) + Math.pow(fPosZBeforeMoved - sPosZ, 2));
You'll recognize this as part of your code. We covered sin, but let's take a look at cos. cos is the ratio of the length of the adjacent side over the hypotenuse. In other words:
cos A = adjacent / hypotenuse = b / h
This explains this part:
(sPosX - fPosXBeforeMoved) / Math.sqrt(Math.pow(sPosX - fPosXBeforeMoved, 2) +
Math.pow(sPosZ - fPosZBeforeMoved, 2));
Take note that I swapped the subtraction of sPosX and fPosXBeforeMoved in comparison to what you had in your code from before. The reason why is because when you are examining the point before and the point after, the point after always comes first, then the point before comes second. In the bottom when you're calculating the hypotenuse, this doesn't matter because no matter which order the values are subtracted from, we take the square of the subtraction, so you will get the same number anyway regardless of the order. I decided to swap the orders here in the hypotenuse in order to be consistent. The order does matter at the top, as the value being positive or negative when you're subtracting will make a difference when you're finding the angle in the end.
Note that this division will always be between -1 to 1 so we can certainly use the inverse trigonometric functions here. Finally, if you want to find the angle, you would apply the inverse cosine. In other words:
Math.acos((sPosX - fPosXBeforeMoved) / Math.sqrt(Math.pow(sPosX - fPosXBeforeMoved, 2)
+ Math.pow(sPosZ - fPosZBeforeMoved, 2)));
This is what I believe you should be programming. Take note that this will return the angle in radians. If you'd like this in degrees, then use the equation that I showed you above, but re-arrange it so that you are solving for degrees instead of radians. As such:
angle_in_degrees = angle_in_radians * (180.0 / Math.PI)
As for what you have now, I suspect that you are simply measuring the ratio of the adjacent and the hypotenuse, which is totally fine if you want to detect where you are crossing over each axis. If you want to find the actual angle, I would use the above code instead.
Good luck and have fun!
Related
I need to calculate which side of a point another point is on and I've been googling around but I have absolutely no idea what all those math equations mean or how they translate into code or JavaScript more specifically.
I have the following information:
Point A: x, y and angle (direction which the point is going to, north clockwise)
Point B: x and y
Now how do I know whether point B is on the left or the right side of point A? Answers in JavaScript highly appreciated.
Consider sign of expression (if angle is in degrees, multiply it by Math.PI/180 to get radians)
cross = (B.x - A.x)*Math.sin(angle)-(B.y - A.y)*Math.cos(angle)
Edit: for coordinate system OX north, clockwise it is necessary to exchange cos and sin
cross = (B.x - A.x)*Math.cos(angle)-(B.y - A.y)*Math.sin(angle)
Positive value for right side, negative value for left side (or vice versa depending on your coordinate system orientation)
You have:
a point A(A.x, A.y);
a moving direction for A given as an angle A.angle;
a point B(B.x, B.y).
You want to compare the moving direction of A with the direction of vector AB.
Coordinates of vector AB can be computed with a simple subtraction:
AB.x = B.x - A.x
AB.y = B.y - A.y
You can compute the angle corresponding to direction vector AB using atan2. Conveniently, that function is part of most programming languages' standard math library.
When using atan2, we have to be careful about the convention. In the comments, you specified that you wanted the north-clockwise convention. For other conventions, see Wikipedia: atan2 and conventions.
We also have to convert from radians to degrees, which can be done easily with the conversion factor 180 / pi.
AB.angle = atan2(AB.x, AB.y) * 180 / pi
if AB.angle < 0:
AB.angle = AB.angle + 360
Then all we have to do is check whether AB.angle is in interval [A.angle - 180°, A.angle] (left), or in interval [A.angle, A.angle + 180°] (right), while being careful because all calculations are modulo 180°.
// assuming A.angle > 0 && A.angle < 360
if A.angle > 180:
if AB.angle > A.angle - 180 && AB.angle < A.angle:
return "Left"
else:
return "Right"
else: // A.angle < 180
if AB.angle > A.angle && AB.angle < A.angle + 180:
return "Right"
else:
return "Left"
Let's break this up.
We've got a directed line L, going through point A in direction a (for angle).
We've got a point B.
And the question is: Is B left or right of L?
What we need is the angle of the line (against 'north', a.k.a. positive y-axis) that goes through A and B. This allows us to compare those angles:
if the difference is in -180°..0° or 180°..360° (-pi..0 or pi..2pi in radians), B is to the left of L,
if the difference is in -360°..-180° or 0°..180° (-2pi..-pi or 0..pi in radians), B is to the right of L.
It would be easier to find the right math if your 0°-angle would be 'east, counterclockwise' (as is mathematical convention), but we'll just swap x and y and we're good to go (they're already swapped in the following lines!).
We get that angle (let's call it b) from the points alone, but at first, it'll be in radians (not in degrees):
b_rad = Math.atan((A.x - B.x) / (A.y - B.y));
You did not specify whether the angle is in degrees or radians. Assuming degrees, the result needs to be converted from radians:
b_deg = b_rad * (180 / Math.PI);
Now you only need to take the difference:
delta = a_deg - b_deg;
and use that delta in the comparison I outlined above.
(If I didn't think right, this math gives the opposite results of what is needed -- in this case, you need to swap a_deg and b_deg in the delta calculation)
if pointB.x < pointA.x it's on the left side.
if pointB.x > pointA.x it's on the right side.
if they are equal, you can't really say who's on the left or on the right.
(that is, of course assuming your coordinate space goes left to right on the x axis)
I originally wanted to use four points (as a bezier Curve is defined with 4 points), but that forces me to brute force the position, so I tried a different approach i now need help with:
I have a start point P0, an end point P1 and slopes m0 and m1 which are supposed to give me the start/end slope to calculate a Bezier Curve inbetween them.
The Curve is supposed to be in the form of a function (3rd degree), since I need to get the height y of a given point x.
Using the HTML5Canvas i can draw a bezier curve no problem and using this function
that allows me to calculate any given point given a percentage of the way i can get the center point of the curve. But I don't need it depending on t but rather the y depending on x, so not halfway of the curve but halfway of the x distance between P0 and P1.
Image to visualize:
Left is what i can calculate, right is what i need.
I've been trying to calculate the cubic function given the two points P0, P1 as well as the slopes m0, m1, which results into four equations which i can't seem to be able to solve with only variable inputs. I've also tried to use the above function to calculate the t using the x value (which is known), but no dice there either.
I need to avoid using approximations or costly loops for these calculations as they are performed many times a second for many objects, thus this answer is not feasible for me.
Any help is appreciated.
I've encountered the same problem in a project I'm working on. I don't know of a formula to get the y coordinate from the x, and I suspect you'll have trouble with that route because a bezier curve can have up to 3 points that all have the same x value.
I would recommend using the library BezierEasing, which was designed for this use case and uses various performance enhancing techniques to make lookups as fast as possible: https://github.com/gre/bezier-easing
To solve this problem, you need to rewrite Bezier equation in power polynomial form
X(t) = t^3 * (P3.X-3*P2.X+3*P1.X-P0.X) +
t^2 * (3*P0.X + 6*P1.X+3*P2.X) +
t * (3*P1.X - 3P2.X) +
P0.X
if X(t) = P0.X*(1-ratio) + P3.X*ratio
then
let d = ratio * (P0.X - P3.X)
and solve cubic equation for unknown t
a*t^3 + b*t^2 + c*t + d = 0
JS code here
Then apply calculated t parameter (there might be upto three solutions) to Y-component and get point coordinates. Note that formulas are close (no loops) and should work fast enough
Thank you to everyone that answered before, those are generally great solutions.
In my case I can be 100% sure that I can convert the curve into a cubic function, which serves as the approximation of the bezier curve using the result of this calculation.
Since i have control over my points in my case, I can force the P0 to be on x=0, which simplifies the linear system calculations and thus allows me to calculate the cubic function much easier like this:
let startPoint: Utils.Vector2 = new Utils.Vector2(0, 100);
let endPoint: Utils.Vector2 = new Utils.Vector2(100, 100);
let a: number, b: number, c: number, d: number;
function calculateFunction() {
let m0: number = 0;
let m1: number = 0;
a = (-endPoint.x * (m0 + m1) - 2 * startPoint.y + 2 * endPoint.y) / -Math.pow(endPoint.x, 3);
b = (m1 - m0 - 3 * a * Math.pow(endPoint.x, 2)) / (2 * endPoint.x);
c = m0;
d = startPoint.y;
}
I am writing software that extends Circle-Rectangle collision detection (intersection) to include responses to the collision. Circle-edge and circle-rectangle are rather straight-forward. But circle-circle has me stumped.
For example, let two circles collide, one red and one green, in a discrete event simulation. We might have the following situation:
Immediately after they collide we could have:
Here RIP and GIP were the locations of the circles at the previous clock tick. At the current clock tick, the collision is detected at RDP and GDP. However, the collision occurred between clock ticks when the two circles were at RCP and GCP. At the clock tick, the red circle moves RVy downward and RVx rightward; the green circle moves GVy downward and GVx leftward. RVy does not equal GVy; nor does RVx equal GVx.
The collision occurs when the distance between the circle centers is less than or equal to the sum of the circles' radii, that is, in the preceding figure, d <= ( Rr + Gr ). At a collision where d < ( Rr + Gr ), we need to position the DPs back to the CPs before adjusting the circles' velocity components. In the case of d == ( Rr + Gr ), no repositioning is required since the DPs are at the CPs.
This then is the problem: how do I make the move back to the CPs. Some authors have suggested that one-half of the penetration, given by p in the following figure, be applied.
To me that is just plain wrong. It assumes that the velocity vectors of the two circles are equal that, in this example, is not the case. I think penetration has something to do with the computation but how eludes me. I do know that the problem can be recast as a problem of right similar triangles in which we want to solve for Gcdy and GCdx.
The collision itself will be modeled as elastic, and the math for the exchange of inertia is already in place. The only issue is where to position the circles at collision.
"This then is the problem: how do I make the move."
It is likely that you want to know how "to position the DPs back to the CPs before adjusting the circles' velocity components."
So there are two issues, how to determine the CPs (where the collision occurs) and how to adjust the circles' motion going forward from that point. The first part has a rather easy solution (allowing for different radii and velocity components), but the second part depends on whether an elastic or inelastic response is modelled. In a Comment you write:
The collision will be modeled as elastic. The math for the exchange of inertia
is already in place. The problem is where to position the circles.
Given that I'm going to address only the first issue, solving for the exact position where the collision occurs. Assuming uniform motion of both circles, it is sufficient to know the exact time at which collision occurs, i.e. when does the distance between the circles' centers equal the sum of their radii.
With uniform motion one can treat one circle (red) as motionless by subtracting its velocity from that of the other circle (green). In effect we treat the center of the first circle as fixed and consider only the second circle to be in (uniform) motion.
Now the exact time of collision is found by solving a quadratic equation. Let V = (GVx-RVx, GVy-RVy) be the relative motion of the circles, and let P = (GIPx-RIPx,GIPy-RIPy) their relative positions in the "instant" prior to collision. We "animate" a linear path for the relative position P by defining:
P(t) = P + t*V
and ask when this straight line intersects the circle around the origin of radius Rr+Gr, or when does:
(Px + t*Vx)^2 + (Py + t*Vy)^2 = (Rr + Gr)^2
This is a quadratic equation in unknown time t, all other quantities involved being known. The circumstances are such that (with collision occurring at or before position CP) a positive real solution will exist (typically two solutions, one before CP and one after, but possibly a grazing contact giving a "double root"). The solution (root) t you want is the earlier one, the one where t (which is zero at "instant" RIP,GIP positions) is smaller.
If you're looking for a basic reference on inelastic collisions for circular objects, Pool Hall Lessons: Fast, Accurate Collision Detection Between Circles or Spheres by Joe van den Heuvel and Miles Jackson is very easy to follow.
From least formal to most formal, here are some follow up references on the craft of implementing the programming that underpins the solution to your question (collision responses).
Brian Beckman & Charles Torre The Physics in Games - Real-Time Simulation Explained
Chris Hecker, Physics, Part 3: Collision Response, Game Developer 1997
David Baraff, Physically Based Modeling: Principles and Practice, Online Siggraph '97 Course notes, of particular relevance are the Slides for rigid body simulations.
You're going to have to accept some approximations - Beckman demonstrates in the video that even for very simple cases, it isn't possible to analytically predict what would occur, this is even worse because you are simulating a continuous system with discrete steps.
To re-position the two overlapping circles with constant velocities, all you need to do is find the time at which the collision occurred, and add that factor of their velocities to their positions.
First, instead of two circles moving, we will consider one circle with combined radius and relative position and velocity. Let the input circles have positions P1 and P2, velocities V1 and V2, and radii r1 and r2. Let the combined circle have position P = P2 - P1, velocity V = V2 - V1, and radius r = r1 + r2.
We have to find the time at which the circle crosses the origin, in other words find the value of t for which r = |P + tV|. There should be 0, 1, or 2 values depending on whether the circle does not pass through the origin, flies tangent to it, or flies through it.
r^2 = ||P + tV|| by squaring both sides.
r^2 = (P + tV)*(P + tV) = t^2 V*V + 2tP*V + P*P using the fact that the L2-norm is equivalent to the dot product of a vector with itself, and then distributing the dot product.
t^2 V*V + 2tP*V + P*P - r^2 = 0 turning it into a quadratic equation.
If there are no solutions, then the discriminant b^2 - 4ac will be negative. If it is zero or positive, then we are interested in the first solution so we will subtract the discriminant.
a = V*V
b = 2 P*V
c = P*P - r^2
t = (-b - sqrt(b^2 - 4ac)) / (2a)
So t is the time of the collision.
You can actually derive an expression for the time required to reach a collision, given initial positions and velocity vectors.
Call your objects A and B, and say they have position vectors a and b and velocity vectors u and v, respectively. Let's say that A moves at a rate of u units per timestep (so, at time = t, A is at a; at time = t + 1, A is at a + u).
I'm not sure whether you want to see the derivation; it wouldn't look so great... my knowledge of LaTeX is pretty limited. (If you do want me to, I could edit it in later). For now, though, here's what I've got, using generic C#-ish syntax, with a Vector2 type that is declared Vector2(X, Y) and has functions for vector addition, scalar multiplication, dot product, and length.
double timeToCollision(Vector2 a, Vector2 b, Vector2 u, Vector2 v)
{
// w is the vector connecting their centers;
// z is normal to w and equal in length.
Vector2 w = b - a;
Vector2 z = new Vector2(-1 * w.Y, w.X);
Vector2 s = u - v;
// Dot() represents the dot product.
double m = Dot(z, s) / Dot(w, s);
double t = w.Length() / Dot(w, s) *
(w.Length() - sqrt( ((2 * r) ^ 2) * (1 + m ^ 2) - (m * w.Length()) ^ 2) ) /
(1 + m * m)
return t;
}
As for responding to collisions: if you can fast-forward to the point of impact, you don't have to worry about dealing with the intersecting circles.
If you're interested, this expression gives some cool results when there won't be a collision. If the two objects are moving away from each other, but would have collided had their velocities been reversed, you'll get a negative value for t. If the objects are on paths that aren't parallel, but will never meet (passing by each other), you'll get a negative value inside the square root. Discarding the square root term, you'll get the time when they're the closest to each other. And if they're moving in parallel at the same speed, you'll get zero in the denominator and an undefined value for t.
Well, hopefully this was helpful! I happened to have the same problem as you and decided to see whether I could work it out on paper.
Edit: I should have read the previous responses more carefully before posting this... the mess of a formula above is indeed the solution to the quadratic equation that hardmath described. Apologies for the redundant post.
I have a circle in my canvas. The mouse position is calculated in relation to the canvas. I want the circle to move when the mouse is at <=100px distance from it. The minimum distance to start moving is 100px, at 0.5px/tick. It goes up to 2px/tick at 20px distance.
Basically, the closer the mouse is to the circle, the faster the circle should move.
What I have so far moves the circle when distance is less or equal to 100 -- (I'm using easeljs library)
function handleTick() {
distance = calculateDistance(circle, mX, mY);
if (distance<=100) {
circle.x += 0.3;
stage.update();
}
}
What I want
function handleTick() {
distance = calculateDistance(circle, mX, mY);
if (distance<=100) {
circleSpeed = // equation that takes distance and outputs velocity px/tick.
circle.x += circleSpeed;
stage.update();
}
}
So I thought this was a mathmatical problem and posted it on math exchange, but so far no answers. I tried googling several topics like: "how to come up with an equation for a relation" since I have the domain (100, 20) and the range (0.5, 2). What function can relate them?
Thing is I'm bad at math, and these numbers might not even have a relation - I'm not sure what I'm looking for here.
Should I write a random algorithm "circleSpeed = 2x + 5x;" and hope it does what I want? Or is it possible to do as I did - "I want these to be the minimum and maximum values, now I need to come up with an equation for it"?
A pointer in the right direction would be great because so far I'm shooting in the dark.
If I understand it correctly, you want circleSpeed to be a function of distance, such that
circleSpeed is 0.5 when distance is 100.
circleSpeed is 2 when distance is 20.
There are infinity functions which fulfill that, so I will assume linearity.
The equation of the line with slope m and which contains the point (x₀,y₀) is
y = m (x-x₀) + y₀
But in this case you have two points, (x₁,y₁) and (x₂,y₂), so you can calculate the slope with
y₂ - y₁
m = ───────
x₂ - x₁
So the equation of the line is
y₂ - y₁
y = ─────── (x - x₁) + y₁
x₂ - x₁
With your data,
0.5 - 2
y = ──────── (x - 20) + 2 = -0.01875 x + 2.375
100 - 20
Therefore,
circleSpeed = -0.01875 * distance + 2.375
I assume you want a linear relation between the distance and speed?
If so, you could do something like circleSpeed = (2.5 - 0.5(distance/20)).
That would, however set the speed linearly from 0 to 2.5 on the range (100 to 0), but by using another if like this if (distance < 20) circleSpeed = 2 you would limit the speed to 2.0 at 20 range.
It's not 100% accurate to what you asked for, but pretty close and it should look ok I guess. It could possibly also be tweaked to get closer.
However if you want to make the circle move away from the mouse, you also need to do something to calculate the correct direction of movement as well, and your problem gets a tiny bit more complex as you need to calculate speed_x and speed_y
Here is a simple snippet to animate the speed linearly, what that means is that is the acceleration of the circle will be constant.
if distance > 100:
print 0
elseif distance < 20:
print 2
else:
print 2 - (distance -20 ) * 0.01875
Yet other relationships are possible, (other easings you might call them) but they will be more complicated, hehe.
EDIT: Whoops, I’d made a mistake.
I have a programming question with some math weight. I have a map with shapes(polylines) drown on it. I can take the screen coordinates of that shapes and translate them to map coordinates and reverse. I am capturing mouse position and moving around the map. How can I recognize if I come in proximity to another shape drown on the map while I am moving the mouse. I was thinking to create a radius of points around the mouse cursor, then constantly looping trough available shapes (I imagine I can load their coordinates in arrays) for a match. However that will be very slow I think. The point is that when I am in proximity (for example 15px) I will snap the muse position to that close shape. Any suggestions?
Now - if you really want to make it perfect - you can calculate the distance of a cursor to each line segment.
For each line segment (defined by points D and E)
Calculate line formula for segment DE in format:
Ax + By + C = 0
A = D.y - E.y
B = E.x - D.x
C = (plug in point D) = -1 * (A * D.x + B * D.y)
Now plug in your cursor position to the formula:
A * cursor.x + B * cursor.y + C = YOUR DISTANCE TO THE LINE SEGMENT
*One thing - this is distance to the unbounded line. You now want to make sure that you are between the two segment points. So make sure the angles in your cursor, D, E triangle are all < 90 degrees. A number of ways to do that, look into the dot product formula to learn a fast one.
Now if anlges are less than 90, use the distance to the line, else, use the min distance to either point of segment (D & E). Now you have a complete snap to lines functionality.
If you have every point / line segment of the shapes (which you should with the polylines), here is a possible quick and simple routine:
For each shape
Figure center of shape by averaging each constituent point (i.e. - for a pentagon, add all five point.x up, divide by 5 - do same for all point.y). Call this average shape.x and shape.y. Use distance formula to figure proximity to your mouse. (Mouse.x - Shape.x)^2 + (Mouse.y - Shape.y)^2... you don't have to take the square root of that since you are only interested in the closest shape.
Keep track of the minimum distance "squared" for each shape. The minimum is your closest shape center.
If you want snap to behavior with a maximum range, just also make sure the distance squared is < pixel distance squared.
If you want to make it very effiecient, the shape centers do not need to be constantly refigured, just calculated once. The center will scale and translate the same as any other point if you are converting between screen space and other coordinates as you mentioned.