I have one point (hereafter referred to as the original point) on a grid, say for example, [3, 3].
I also have a set of points that are in the same horizontal and vertical lines as the original point, say, [[3,1],[3,2],[3,4],[7,3],[8,3]].
I want some function that will return an array of at most four points: the points closest to the original point in each direction (i.e. left, right, above, below). With the example above, it would return,
[[3,2],[3,4],[7,3]]
because [3,2] is the closest point on the left, [3,4] is the closest point on the right, [7,3] is the closest point above, and there are no points below. (Order of direction is not important.)
Is there an elegant and reasonably concise way to do this, using Javascript/JQuery?
I don't know JavaScript, but the following algorithm would be very simple, if you can formulate it with JavaScript.
Let (X0, Y0) be the original point.
Iterate through the array, [(X1, Y1), ..., (XN, YN)], and keep account of the minimum values of
R = Xi - X0 > 0
and
L = X0 - Xi > 0
as you proceed.
At the end of the iteration these values give you the closest points, i.e., X0 + R
and X0 - L.
Do a similar iteration on the vertical line of points.
Related
The idea is to find the mid point of a bezeir curve. Following is the De Casteljau's algorithm for finding the midpoint of a curve with four points.
How can I implement such an algorithm in javascript using recursion?
Following is the four starting points. From here we start the algorithm and through recursion we arrive the tip of the tree.
(0, 0)
\
(1/2, 0) --> this node is calculated as follows [(x1 + x2)/2, (y1 + y2)/2]
/ \
(1, 0) (3/4, 1/4)
\ / \
(1, 1/2) (3/4, 1/2)
/ \ /
(1, 1) (3/4, 3/4)
\ /
(1/2, 1)
/
(0, 1)
for example the sample input of points will be like this
const points = [[0,2], [4,5], [6,7], [3,8]]
output = [3,5]
// so the output will be just an array of two numbers for eg: [3,5] (just a rough figure for demo) which represents the midpoint of the above four points obtained by the above algorithm.
So this tip of the tree (output) will be the midpoint of the given curve.
This is the code a fellow coder of stack overflow (Nina Scholz) have come up with and it works perfectly for me. But I want to extend it further. I've given an illustration. Nina's code is perfect for finding the midpoint for the first time. I want to find the remaining points by segmenting the curve as follows.
const
getB = array => {
if (array.length === 1) return array[0];
const result = [];
for (let i = 1; i < array.length; i++) {
result.push([(array[i - 1][0] + array[i][0]) / 2, (array[i - 1][1] + array[i][1]) / 2]);
}
return getB(result);
},
points = [[0, 2], [4, 5], [6, 7], [3, 8]];
console.log(getB(points));
UPDATE
Remember each node is calculated as follows [(x1 + x2)/2, (y1 + y2)/2]. i.e., by taking the average of similar coordinates of two adjacent points.= .
UPDATE
The code suggested by Nina Scholz works fine.
But I want to extend it further. Ninas code returns the first midpoint. But I want to extend it to find more points as illustrated below.
UPDATE
This is not to segment the curve. But to find points at equal distance, by starting at the mid point then dividing the curve in to two segment, then again finding midpoint of those two segments, like wise this repeats till the number of points required is reached/exhausted. So the requirement is to find the points of a cubic bezeir curve.
NOTE
Once the middle point is returned this point becomes the starting point and ending point of the lines obtained by the previous midpoint, in this way it proceeds further till the number of points required is reached. This way we can find the location/coordinates of points separated by equal distance starting at the midpoint.
JUST CONSIDER IT LIKE FOLDING A PAPER. INSTEAD HERE WE FOLDS THE CURVE & finds the points of the curve at each fold/ points of segmentation.
I am trying to figure out the (x,y) position of the s2 node from the given example.
1
With trilateration I was able to calculate the first node s1 position based on the fixed anchors. Now I am trying to calculate the s2 node possible coordinates, what I have is:
Coordinates of two points:
A2:{y:0,x:4}
S1:{y:2,x:2}
Distances:
A2-S2: 2
S1-S2: 2
A2-S1: 2
Is there a way to calculate the possible positions of the s2 node based on this data in JavaScript? This should work on any type of triangle.
Update:
I think I found a solution, I can threat the 2 known position as the centre of two circle and the distances to the unknown point as radius, than I have to calculate the intersection of the two circle to get the possible coordinates.
A JavaScript function that returns the x,y points of intersection between two circles?
You have two known points A and B, unknown point C and distances dAC and dBC (dAB is useless). So you can build equation system
(C.X - A.X)^2 + (C.Y - A.Y)^2 = dAC^2
(C.X - B.X)^2 + (C.Y - B.Y)^2 = dAB^2
and solve it for C.X and C.Y (there are possible two, one and zero solutions).
Note that it is worth to shift coordinates by (-A.X, -B.X) to get simpler equations and solution, then add (A.X, B.X) to the solution coordinates
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 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!
I've created a multi-dimensional array based on the x/y coords of the perimeter of a circle. An object can be dragged along the arc (in javascript) and then 'dropped' anywhere on it. The problem is, I need to find the closest x and y coordinate to where the object is 'dropped.'
My current solution involves looping through an array and finding the closest value to x, and then looping again to find the y coordinate, but it doesn't seem very clean and there are problems with it.
Does anyone have any suggestions?
Thanks!
So, let's see. We assume a predefined set of (x, y) coordinates. You are given another point and have to find the nearest element of the array to that given point. I am going to assume "nearest" means the smallest Pythagorean or Euclidean distance from the given point to each of the other points.
The simplest algorithm is probably the best (if you want to look at others in Wikipedia, have at it). Since you didn't give us any code for the structure, I'm going to assume an array of objects, each object having an x and a y property, ditto for the given point.
var findNearestPoint = function (p, points) {
var minDist = Number.POSITIVE_INFINITY,
minPoint = -1,
i,
l,
curDist,
sqr = function(x) { return x * x; };
for (i = 0, l = points.length; i < l; i++) {
curDist = sqr(p.x - points[i].x) + sqr(p.y - points[i].y);
if (curDist < minDist) {
minDist = curDist;
minPoint = i;
}
}
return points[i];
};
(Untested, but you get the idea.)
If your arrays are created in sequential order (that is from smallest to greatest or greatest to smallest), you could use introduce a Binary Search Algorithm.
Get middle element of x array.
If x equals your value, stop and look for y, otherwise.
If x is lower, search in the lower half of the array (starting from step 1).
If x is higher, search in the upper half of the array (starting from step 1).
Then use the same formula on y. You might have to change to algorithm a bit to make it so it works with the closest matching element. Having not seen your array, I can't offer code to solve to problem.