Computing an angle from x,y coordinates [duplicate] - algorithm

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Circle line collision detection
I'm trying to do collision testing between a finite line segment, and an arc segment. I have a collision test which does line segment vs. line segment, so I was going to approximate these arc segments with line segments and run my existing test.
The data I have defining the arc segment(s) are three points. Two of which are endpoints that lie on the circumference of a circle, and the third point is the center of that circle.
So far this is what I've got:
Let (a,b) be the center point of the circle, let 'r' be the radius of the circle, and (x1, y1), (x2, y2) be the endpoints of the arc segment which lies on the circumference of the circle.
The following parametric equations give the x, and y locations of an arc. 't' is the parametric variable.
x = a + r * cos(t)
y = b + r * sin(t)
To create the line segments from the arc, I wanted to walk the arc for some fixed ratio of 't' creating line segments along the way, until I've reached the end of the arc. To do this I figured I'd have to find the start and end angle. I'd start walking the arc from the start angle, and end at the end angle. Since I know the start and end points I figured I could use these equations to solve for these angles. The following are my equations for this:
t = arccos((x-a)/r)
or
t = acrcsin((y-b)/r)
The problem I'm having is that the range of values returned by these functions (http://en.wikipedia.org/wiki/Inverse_trigonometric_function) is limited, so there is a high probability that the angle I'm looking for will not be returned because these functions are multivalued: arcsin(0) = 0, but also arcsin(0) = π, arcsin(0) = 2π, etc
How do I get the exact angle(s) I'm looking for? Or, can you think of a better/different way of achieving my goal?

Take a look at the atan2 function, which should exist in whatever programming language or math library you're using. It takes two arguments, the x and y coordinates of a point (for you: (x-a)/r and (y-b)/r) and returns the angle in the range -π to +π.

At least IMO, you're going at this the wrong way. A line has an equation y=mx+b. A circle has an equation x2 + y2 = r2. You're looking for a point at which the x and y of the circle equals the x and y of the line. You can do that by substituting the mx+b equation for the line for the y equation in the circle, and then solve using the quadratic equation.
The equations involved do get a bit long, but quite a few web pages (e.g., http://www.sonoma.edu/users/w/wilsonst/papers/geometry/circles/default.html) have them, at which point it's simple matter of implementing the equations as a couple of functions and plugging in the values for your particular circle/line. A solution based on these equations complete avoids the ambiguity from using an arg tangent.

Your pseudo-code looks a lot like Python. If you don't mind using Python I would recommend the Shapely Library. If you just want the algorithm, check the source.
Shapely objects have the 'simplify' and 'intersection' methods.

Related

Fast Integer Coordinates Inside/along a Circle Centered at origin with radius r

Consider that you have a circle centered at 0,0 with radius r.
I'd like to get all the integer points available that are inside this circle. This problem is easy to solve.
One may just iterate over a square from x = -r to +r and y =-r to +r and see if x * x + y * y <= r * r, if so, add the point to your result.
However, what's the quickest way to do this? I feel there should be some type of hack that we can take the calculations from (2r)^2 to 4/3 r^2
More particularly, I have a feeling that we can calculate the length of the inscribed square, then add the outer remaining components. I'm unsure of how to do this though. The math is a little dense. I'm refraining from posting code because I'd like a general algorithm response, but if one has preference, he may state the final benchmark that this will be used in should use a JVM language.
Any help?
Note: this is similar to the gauss's circle problem, but instead of counting the number of points, I want to know what the points are.
You can get the values directly by computing the maximum y (the second coordinate of the point on the circle at the vertical of (x,0)) for each value of x like that:
for x in [-floor(r), floor(r)]
y_max = floor(sqrt(r^2 - x^2)) # Pythagora's theorem
for y in [-y_max, y_max]
# (x, y) is good !
I don't think you can do much better (maybe you can compute y_max faster but that won't be a big win) because anyway you have these points in the result.
EDIT:
This is in Pi*r^2 time, which is the least you can do since it's the number of points.
You can maybe save a few computations by doing only a quarter circle and getting the other ones by symmetry, but I'm not even sure it's faster, and it's certainly longer to write.

How to detect Line segment intersection with Cylinder? [duplicate]

This question already has answers here:
Trying to optimize line vs cylinder intersection
(4 answers)
Closed 7 years ago.
Say we have a 3d space, Line segment defined by its start and end points (A {Ax, Ay, Az}, B {Bx, By, Bz}) and cylinder defined by its center position C {Cx, Cy, Cz}, radius R and height H. How to get a fact of intersection and if intersection happened than where?
Try this. Google for the win - the answer is even here on SO. This even has source code and links to more information for you to use. With just a little bit of searching, you could have got this yourself.
This is based on #DuckQueen's answer - it just adds projecting the intersection point - if any - to see if it falls within the height of the cylinder.
Let x = (y-a2)/b2 = (z-a3)/b3 be the equation for line.
Let (x-c1)^2 + (y-c2)^2 = d^2 be the equation for the cylinder.
Substitute x from the line equation into the cylinder equation.
You can solve for y using the quadratic equation. You can have 0 solutions (cylinder and line does not intersect), 1 solution or 2 solutions.
Substitute the value of y into the line equation to get x and z coordinates.
For getting line equation from two points see: http://www.nabla.hr/Z_CGLinesAndPlanesIn3DSpace-A.htm
The solution I provided works for cylinder of infinite height. To restrict to a cylinder of height H: Find the points of intersection, if the points are within the height (i.e. z is within limits), output points.

Gradient Of Bezier Curve At Given Point

I cant seem to figure out how to calculate the incline of a curve for the following situation...
Essentially what I am trying to do is increase the speed of an object based on the incline of the curve at a particular point. The speed will be reduced if the incline is upwards and increase if downward.
I was using the derivative of a point t on the bezier curve to establish the tangent but this doesnt seem to be right as I would expect that value to be negative if the slope is downward.
I have been using the below equation for the tangent to evaluate X, Y and Z but then I only use Y to establish the incline...I think that step may be wrong
Any ideas?
EDIT:
Ultimately this is an object moving along an inclined plane but I cant establish the angle of the plane in order to do this, I believe if I could correctly find the angle it may solve the problem. I tried to take the point in question and then another point in front (so for example t = 0.5 and then a point in front would be t=0.51) and then calculate the angle using tan. I completely ignore the Z axis but is that wrong? If not how should I calculate the angle?
Thanks a lot
This should help: http://www.physicsclassroom.com/Class/vectors/U3L3e.cfm .
Essentially, you need to calculate the angle of inclination. If the angle is \theta , then the acceleration depends on sin(\theta).
I am assuming z as the vertical dimension.
if dx,dy and dz is are the gradients in each directions, dw = sqrt( dx^2+dy^2). \theta = tan_inverse( dz/dw). Acceleration = g*sin(\theta).
NOTE: You can directly calculate sin(\theta) without explicitly calculating \theta. sin(\theta) = dz/sqrt(dx^2+dy^2+dz^2).
=== More formal description ===
Let x be the east-west dimension, y be the north-south dimension and z be the up-down dimension.
Let z = F(x,y) give the elevation of the terrain at any given location x,y.
Calculate dz/dx = fx(x,y) and dz/dy = fy(x,y), the partial derivatives of z w.r.t to x and y.
Now, sin(\theta) = dz/sqrt(dx^2+dy^2+dz^2) = 1/(sqrt( (dx/dz)^2+ (dy/dz)^2 )= 1/(sqrt( (1/fx(x,y))^2, (1/fy(x,y))^2 ).
This is how you calculate sin(\theta).
The value of derivation is negative when the slope is "downward". And yes, the derivation is the tangent of the slope angle. Only you should pay attention to the directions. They can change the sign, of course. Only you should take dy/dx, not dy/something else. That is all on 2d curves.
You mention Z in the last paragraph. You curve is 3D? Then, of course, the term "derivation" should be put more precisely. Derivation of what to what do you need? The second idea is - please, explain better, what do you want. BTW, maybe after you write down the task correctly, you'll see the solution as obvious.
If it is 3D, let us say, you have your curve as 3 functions of x(t), y(t), z(t). then you need dz/dq, where dq= dt*sqrt((dx/dt)^2+(dy/dt)^2). Obviously, isn't it?
As I said, no maths here. Merely Pythagor's theorem and proportions. (I take z as height)
Addition: it can be rerecounted as tan(a)=dz/(dt*sqrt((dx/dt)^2+(dy/dt)^2)) => tan(a)=(dz/dt)/sqrt((dx/dt)^2+(dy/dt)^2)) ==> a=ATAN((dz/dt)/sqrt((dx/dt)^2+(dy/dt)^2)). But look out for directions you are moving! They can reverse the sign. For under sqrt(^2+^2) we have lost the direction of the dt proection.

Formula to determine whether a line form by 2 geo points (lat, lon) intersects geo region (circle)?

It does not need to be very accurate. Does anyone know a good way to do this?
any help is much appreciated.
When you say “it does not need to be very accurate” you don’t say how inaccurate a solution you’re prepared to accept. Also, you don’t say how big the geographic region under consideration is likely to be. These two criteria make a big difference to the kind of approach that needs to be taken.
With a small regions (a few kilometres, say), a flat approximation may be good enough (for example, the Mercator projection) and some of the other responses tell you how to do that. With larger regions you have to take the Earth’s sphericity into account. And if you want inaccuracy less than a percent or so, you need to take the eccentricity of Earth into account.
I’m going to assume for the purposes of this answer that a spherical approximation is good enough, and that your points are at similar enough altitudes that we don’t need to worry about their heights.
You can convert a geographical point (ψ, λ) to Cartesian Earth-centred coordinates using the transformation
(ψ, λ) → (a cos(ψ) cos(λ), a cos(ψ) sin(λ), a sin(ψ))
where a is the mean radius of the Earth (6,371 km). So let’s suppose that the two points that define your line are p₀ and p₁; then the shortest line through p₀ and p₁ is a great circle, which defines a plane that slices the Earth into two halves, with normal n = p₀ × p₁.
Now we need to find the border of the circular region. Suppose the centre of this region is at c and that the surface radius of the region is s. Then the straight-line radius of the region is r = a sin(s/a). We’ll also need the true centre of the circular region, c’ = c cos(s/a). (This point is buried deep underground!)
We’d like to intersect the two circles and solve for the points of intersection. Unfortunately, because of numerical imprecision, the chances are that this procedure will never find any solutions because the imprecise circles will miss each other in 3 dimensions. So I suggest the following procedure: intersect the planes of the two circles, getting the dotted line shown below (unless c’ × n = 0 in which case the two circles are parallel and either c’ = o, in which case they are coincident, or else they do not intersect). Then intersect the line with the circular region.
This two-step procedure reduces the problem to two dimensions, and guarantees that a solution will be found even if numerical imprecision makes the two circles miss in 3 dimensions.
If you need more accuracy than this, then you might need to use geodetic coordinates on a reference ellipsoid such as WGS 1984.
I'd say find the closest point on the line to the center of the circle, then determine whether that point is within the circle (i.e. the distance in question is less than or equal to the circle's radius).
Outline for solving the problem: assume the Earth is a sphere of radius one centered at the origin. Convert all three lat, lon points to 3D coordinates. The two points of the line plus the origin define a plane; intersect that plane with the sphere of radius d centered on the other point. If there is no plane-sphere intersection, then the answer is the line does not intersect the region. If there is a plane-sphere intersection, then the problem is simplified to intersecting the circular region defined by the plane-sphere intersection with the shortest circular arc on the plane going between the end points of the line and centered at the origin. This is a straightforward 2D problem if you convert to the coordinate system of the plane.
This question is too vague to be answered precisely. What do you mean by
a line form by 2 geo points (lat, lon)
This can be either a great circle going through them (also called orthodrome) or it a can be a linear function of spherical coordinates (loxodrome).
BTW, I assume your circle is a circle on the surface of the sphere, right?
Assuming line is formed by points (x1, y1) and (x2, y2), and circle has radius r with origin (0,0):
Calculate:
Incidence = r^2 * [(x2 - x1)^2 + (y2 - y1)^2] - (x1 * y2 - x2 * y1)^2
Then, from the value of Incidence, we can determine the following:
Incidence < 0: No intersection
Incidence = 0: Tangent (intersection at 1 point on circle)
Incidence > 0: Intersection
It's likely your circle is not at the origin (0,0), so to fix this, just add the origin coordinates from your line coordinates in the equation above. So, if the circle is at (x3, y3), x1 in the above equation would become x1 + x3. Likewise, y1 would be y1 + y3, and the same goes for x2 and y2.
For more info check out this link

What algorithm can I use to determine points within a semi-circle?

I have a list of two-dimensional points and I want to obtain which of them fall within a semi-circle.
Originally, the target shape was a rectangle aligned with the x and y axis. So the current algorithm sorts the pairs by their X coord and binary searches to the first one that could fall within the rectangle. Then it iterates over each point sequentially. It stops when it hits one that is beyond both the X and Y upper-bound of the target rectangle.
This does not work for a semi-circle as you cannot determine an effective upper/lower x and y bounds for it. The semi-circle can have any orientation.
Worst case, I will find the least value of a dimension (say x) in the semi-circle, binary search to the first point which is beyond it and then sequentially test the points until I get beyond the upper bound of that dimension. Basically testing an entire band's worth of points on the grid. The problem being this will end up checking many points which are not within the bounds.
Checking whether a point is inside or outside a semi-circle (or a rectangle for that matter) is a constant-time operation.
Checking N points lie inside or outside a semi-circle or rectangle is O(N).
Sorting your N points is O(N*lg(N)).
It is asymptotically faster to test all points sequentially than it is to sort and then do a fast culling of the points based on a binary search.
This may be one of those times where what seems fast and what is fast are two different things.
EDIT
There's also a dead-simple way to test containment of a point in the semi-circle without mucking about with rotations, transformations, and the like.
Represent the semi-circle as two components:
a line segment from point a to b representing the diameter of the semi-circle
an orientation of either left-of or right-of indicating that the semi-circle is either to the left or right of line segment ab when traveling from a to b
You can exploit the right-hand rule to determine if the point is inside the semicircle.
Then some pseudo-code to test if point p is in the semi-circle like:
procedure bool is_inside:
radius = distance(a,b)/2
center_pt = (a+b)/2
vec1 = b - center_pt
vec2 = p - center_pt
prod = cross_product(vec1,vec2)
if orientation == 'left-of'
return prod.z >= 0 && distance(center_pt,p) <= radius
else
return prod.z <= 0 && distance(center_pt,p) <= radius
This method has the added benefit of not using any trig functions and you can eliminate all square-roots by comparing to the squared distance. You can also speed it up by caching the 'vec1' computation, the radius computation, center_pt computation, and reorder a couple of the operations to bail early. But I was trying to go for clarity.
The 'cross_product' returns an (x,y,z) value. It checks if the z-component is positive or negative. This can also be sped up by not using a true cross product and only calculating the z-component.
First, translate & rotate the semi-circle so that one end is on the negative X-axis, and the other end is on the positive X-axis, centered on the origin (of course, you won't actually translate & rotate it, you'll just get the appropriate numbers that would translate & rotate it, and use them in the next step).
Then, you can treat it like a circle, ignoring all negative y-values, and just test using the square root of the sum of the squares of X & Y, and see if it's less than or equal to the radius.
"Maybe they can brute force it since they have a full GPU dedicated to them."
If you have a GPU at your disposal, then there are more ways to do it. For example, using a stencil buffer:
clear the stencil buffer and set the stencil operation to increment
render your semicircle to the stencil buffer
render your points
read back the pixels and check the values at your points
the points that are inside the semicircle would have been incremented twice.
This article describes how stencil buffers can be used in OpenGL.
If there's a standard algorithm for doing this, I'm sure someone else will come up with it, but if not: you could try sorting the points by distance from the center of the circle and iterating over only those whose distance is less than the semicircle's radius. Or if computing distance is expensive, I'd just try finding the bounding box of the semicircle (or even the bounding square of the circle of which the semicircle is part) and iterating over the points in that range. To some extent it depends on the distribution of the points, i.e. do you expect most of them or only a small fraction of them to fall within the semicircle?
You can find points in a circle and points on one side of a given slope, right?
Just combine the two.
Here's part of a function I wrote do get a cone firing arc for a weapon in a tile based game.
float lineLength;
float lineAngle;
for(int i = centerX - maxRange; i < centerX + maxRange + 1; i++){
if(i < 0){
continue;
}
for(int j = centerY - maxRange; j < centerY + maxRange + 1; j++){
if(j < 0){
continue;
}
lineLength = sqrt( (float)((centerX - i)*(centerX - i)) + (float)((centerY - j)*(centerY - j)));
lineAngle = lineAngles(centerX, centerY, forwardX, forwardY, centerX, centerY, i, j);
if(lineLength < (float)maxRange){
if(lineAngle < arcAngle){
if( (float)minRange <= lineLength){
AddToHighlightedTiles(i,j);
}
}
}
}
}
The variables should be self explanatory and the line angles function takes 2 lines and finds the angle between them. The forwardX and forwardY is just one tile in the correct direction from the center X and Y based on what angle you're pointing in. Those can be gotten easily with a switch statement.
float lineAngles(int x1, int y1, int x2, int y2, int x3, int y3, int x4, int y4){
int a = x2 - x1;
int b = y2 - y1;
int c = x4 - x3;
int d = y4 - y3;
float ohSnap = ( (a * c) + (b * d) )/(sqrt((float)a*a + b*b) * sqrt((float)c*c + d*d) );
return acos(ohSnap) * 180 / 3.1415926545f;
}
It would appear that a simple scheme will work here.
Reduce the number of points in the set, by first computing the convex hull. Only the points on the convex hull will contribute to any interaction with any convex bounding shape. So retain only the subset of points on the perimeter of the hull.
It can easily be argued that the minimal radius bounding semi-circle must have one edge (two points) of the convex hull coincident along the diameter of the semi-circle. I.e., if some edge of the hull does not lie in the diameter, then there exists a different semi-circle with smaller diameter that contains the same set of points.
Test each edge in sequence. (A convex hull often has relatively few edges, so this will go quickly.) Now it becomes a simple 1-d minimization problem. If we choose to assume the edge in question lies on the diameter, then we merely need to find the center of the sphere. It must lie along the current line which we are considering to be the diameter. So as a function of the position of the point along the current diameter, just find the point which lies farthest away from the nominal center. By minimizing that distance, we find the radius of the minimal semi-circle along that line as a diameter.
Now, just choose the best of the possible semi-circles found over all edges of the convex hull.
If your points have integer co-ordinates, the fastest solution may be a lookup table. Since a semicircle is convex, for each y co-ordinate, you get a fixed range of x, so each entry in your lookup table gives maximum and minimum X co-ordinates.
Of course you still need to precalculate the table, and if your semicircle isn't fixed, you may be doing that a lot. That said, this is basically one part of what would once have been done to render a semicircle - the full shape would be rendered as a series of horizontal spans by repeatedly calling a horizontal line drawing function.
To calculate the spans in the first place (if you need to do it repeatedly), you'd probably want to look for an old copy of Michael Abrash's Zen of Graphics Programming. That described Bresenhams well-known line algorithm, and the not-so-well-known Hardenburghs circle algorithm. It shouldn't be too hard to combine the span-oriented versions of the two to quickly calculate the spans for a semi-circle.
IIRC, Hardenburgh uses the x^2 + y^2 = radius^2, but exploits the fact that you're stepping through spans to avoid calculating square roots - I think it uses the fact that (x+1)^2 = x^2 + 2x + 1 and (y-1)^2 = y^2 - 2y + 1, maintaining running values for x, y, x^2 and (radius^2 - y^2), so each step only requires a comparison (is the current x^2 + y^2 too big) and a few additions. It's done for one octant only (the only way to ensure single-pixel steps), and extended to the full circle through symmetry.
Once you have the spans for the full circle, it should be easy to use Bresenhams to cut off the half you don't want.
Of course you'd only do all this if you're absolutely certain that you need to (and that you can work with integers). Otherwise stick with stbuton.
translate the center of the arc to the origin
compute angle between ordinate axis and end points of radii of semi-cirlce
translate the point in question by same dx,dy
compute distance from origin to translated x,y of point, if d > radius of circle/arc eliminate
compute angle between ordinate axis and end point
if angle is not between starting and ending arc of semi-cirlce, eliminate
points remaning should be inside semi-circle
I guess someone found the same solution as me here but I have no code to show as its pretty far in my memory...
I'd do it by steps...
1. I'd look if i'm within a circle... if yes look on which side of the circle.
2. By drawing a normal vector that come from the vector made by the semi-sphere. I could know if I'm behind or in front of the vector...and if you know which side is the semi sphere and which side is the void...It will be pretty damn easy to find if you're within the semi sphere. You have to do the dot product.
I'm not sure if it's clear enough but the test shouldn't be that hard to do...In the end you have to look for a negative or positive value...if it's 0 you're on the vector of the semisphere so it's up to you to say if it's outside or inside the semi-sphere.
The fastest way to do this will depend on your typical data. If you have real-world data to look at, do that first. When points are outside the semi-circle, is it usually because they are outside the circle? Are your semi-circles typically thin pie slices?
There are several ways to do this with vectors. You can scale the circle to a unit circle and use cross-products and look at the resultant vectors. You can use dot-products and see how the prospective point lands on the other vectors.
If you want something really easy to understand, first check to make sure it's inside the circle, then get the angle and make sure it's between the angle of the two vectors that dictate the semi-circle.
Edit: I had forgotten that a semicircle is always half a circle. I was thinking of any arbitrary section of a circle.
Now that I have remembered what a semicircle is, here's how I would do that. It's similar to stbuton's solution, but it represents the semicircle differently.
I'd represent the semicircle as the unit vector that bisects the semicircle. You can easily get that from either one of the vectors that indicate the boundary of the semicircle (because they are 90 degrees away from the representation) by swapping x and y and negating one of them.
Now you just cross the vector created by subtracting the point to be tested from the circle's center. The sign of z tells you whether the point is in the semicircle, and the length of z can be compared against the radius.
I did all the physics for Cool Pool (from Sierra Online). It's all done in vectors and it's filled with dots and crosses. Vectors solutions are fast. Cool Pool was able to run on a P60, and did reasonable breaks and even spin.
Note: For solutions where you're checking sqrt(xx+yy), don't even do the sqrt. Instead, keep the square of the radius around and compare against that.

Resources