I've opted for a picture, which I think may better describe the angle I'm trying to calculate:
CGPoint P2 is anywhere where the user tapped, and CGPoint P1 always has its P1.y = P2.y and P1.x = self.view.bounds.size.width/2.
I was wondering how I could try to calculate the angle between the two points given that I want to base the angle on the half way x-axis?
Thanks!
The angle is:
90-arctan((self.view.bounds.size.height - P2.y)/(P2.x - self.view.bounds.size.width/2))
(It will be positive at the right of the line, negative at the left. If you always want it positive, use abs())
What I'm doing is basically setting the origin at the bottom center of the screen, then calculating the slope of the line from the origin to P2. Then arctan gives the angle of the line respect to the X axis. Then you do 90-arctan(..) to make it respect the Y axis.
Alternatively you can use this formula, which is the same with the axes already flipped.
arctan((P2.x - self.view.bounds.size.width/2)/(self.view.bounds.size.height - P2.y))
Related
Using GDI+ in Delphi 10.2.3: I have an elliptical (not circular) arc drawn from a rectangular RectF and defined start and swept angles using DrawArcF. I need to be able to find any point along the centerline of the arc (regardless of pen width) based just on the degrees of the point - e.g., if the arc starts at 210 for 120 degrees, I need to find the point at, say, 284 degrees, relative to the RectF.
In this case, the aspect ratio of the rectangle remains constant regardless of its size, so the shape of the arc should remain consistent as well, if that makes a difference.
Any ideas on how to go about this?
Parametric equation for axis-aligned ellipse centered at cx, cy with semiaxes a,b against angle Fi is:
t = ArcTan2(a * Sin(Fi), b * Cos(Fi))
x = cx + a * Cos(t)
y = cy + b * Sin(t)
(I used atan2 to get rid off atan range limitation/sign issues)
Note that parameter t runs through the same range 0..2*Pi but differs from true angle Fi (they coincide at angles k*Pi/2).
Picture of Fi/t ratio for b/a=0.6 from Mathworld (near formula 58)
I am currently working on a navigation system using way-points, We can define the following perimeters, assume point B is where we want to go and point A is your current location :
We know the locations (X,Y) of both points A & B.
Point A (you) and Point B (our destination) are both positive in their respective X and Y values.
We know the angle Point A (you) are facing. (360 - 0 degrees)
My question is how would I get the smallest angle to turn in order to face point B (our destination)?
My current method is using ArcTan2(X,Y)
B := ArcTan2(Y1 - Y2,X1 - X2)
B := B * 180 / pi ---- To convert radians into degrees.
This does return a suitable angle, but only sometimes... Other times it returns an angle that will make me face the opposite direction of point B (our destination).
Another issue I am having is figuring out if I should turn left or right - Assume we have a returned angle of 80 degrees, Should that then mean that I rotate to the left or the right ?
I hope my explanation is somewhat clear, Trigonometry was never really my strong point.
I'd be very grateful for any input or sources you guys may be able to provide me.
Thanks
MrClear
You are using wrong X/Y argument order
B := ArcTan2(Y2 - Y1, X2 - X1)
is correct formula to get direction from 1st point to 2nd one.
If you really need angle to turn, you also have to provide current direction (or previous point)
Let you are moving from point A to point B and after B you need to turn onto point C. In this case you need calculate relative angle to change direction (this approach uses cross product of vectors):
CBX := C.X - B.X;
CBY := C.Y - B.Y;
BAX := B.X - A.X;
BAY := B.Y - A.Y;
RotationAngle :=
RadToDeg(ArcTan2(CBX * BAY - CBY * BAX, CBX * BAX + CBY * BAY));
Note that function returns signed angle and you can easily check whether you need to turn left or right. Also RadToDeg function helps to get degrees.
If you have two points (xA, yA) and (xB, yB), with point A as the start and point B as the destination, you have a vector from the start to the destination:
v = (xB-xA)i + (yB-yA)j
In a 2D coordinate system, with x-axis to the right and y-axis pointing up, this vector makes an angle with the horizontal axis that is easy to calculate:
angle = atan2((yB-yA), (xB-xA))
where
i = unit vector in x-direction
j = unit vector in y-direction
This angle is expressed in radians. It rotates from the horizontal axis counterclockwise about point A.
Watch for zero length vectors.
Which is the orientation/angle exactly? Between which vectors?
Is it the angle between the first frame and the second frame?
Estimating Optical Flow delivers you a displacement matrix in pixels.
You get the displacement in the x direction and the displacement in y direction.
A person walking from bottom left to top right might give you a flow mean of x=5 and y = -5. As you got a vector, you can calculate the angle using arctan(5/5) = 45 degrees
I'm trying to move multiple sprites (images) in an elliptical path such that distance (arc distance) remains uniform.
I have tried
Move each sprite angle by angle, however the problem with this is that distance moved while moving unit angle around major axis is different than that while moving unit angle around minor axis - hence different distance moved.
Move sprites with just changing x-axis uniformly, however it again moves more around major axis.
So any ideas how to move sprites uniformly without them catching-up/overlapping each other?
Other info:
it will be called in onMouseMove/onTouchMoved so i guess it shouldn't
be much CPU intensive.
Although its a general algorithm question but
if it helps I'm using cocos2d-x
So this is what i ended up doing (which solved it for me):
I moved it in equation of circle and increased angle by 1 degree. Calculated x and y using sin/cos(angle) * radius. And to make it into an ellipse I multiplied it by a factor.
Factor was yIntercept/xIntercept.
so it looked like this in end
FACTOR = Y_INTERCEPT / X_INTERCEPT;
//calculate previous angle
angle = atan((prev_y/FACTOR)/prev_x);
//increase angle by 1 degree (make sure its not radians in your case)
angle++;
//new x and y
x = cos(newangle) * X_INTERCEPT;
y = sin(newangle) * X_INTERCEPT * FACTOR;
I have written a function named getPointOnEllipse that allows you to move your sprites pixel-by-pixel in an elliptical path. The function determines the coordinates of a particular point in the elliptical path, given the coordinates of the center of the ellipse, the lengths of the semi-major axis and the semi-minor axis, and finally the offset of the point into the elliptical path, all in pixels.
Note: To be honest, unfortunately, the getPointOnEllipse function skips (does not detect) a few of the points in the elliptical path. As a result, the arc distance is not exactly uniform. Sometimes it is one pixel, and sometimes two pixels, but not three or more! In spite of the fault, changes in speed will be really "faint", and IMO, your sprites will move pretty smoothly.
Below is the getPointOnEllipse function, along with another function named getEllipsePerimeter, which is used to determine an ellipse's perimeter through Euler's formula. The code is written in JScript.
function getEllipsePerimeter(rx, ry)
{
with (Math)
{
// You'll need to floor the return value to obtain the ellipse perimeter in pixels.
return PI * sqrt(2 * (rx * rx + ry * ry));
}
}
function getPointOnEllipse(cx, cy, rx, ry, d)
{
with (Math)
{
// Note: theta expresses an angle in radians!
var theta = d * sqrt(2 / (rx * rx + ry * ry));
//var theta = 2 * PI * d / getEllipsePerimeter(rx, ry);
return {x:floor(cx + cos(theta) * rx),
y:floor(cy - sin(theta) * ry)};
}
}
The following figure illustrates the parameters of this function:
cx - the x-coordinate of the center of the ellipse
cy - the y-coordinate of the center of the ellipse
rx - the length of semi-major axis
ry - the length of semi-minor axis
d - the offset of the point into the elliptical path (i.e. the arc length from the vertex to the point)
The unit of all parameters is pixel.
The function returns an object containing the x- and y-coordinate of the point of interest, which is represented by a purple ball in the figure.
d is the most important parameter of the getPointOnEllipse function. You should call this function multiple times. In the first call, set d to 0, and then place the sprite at the point returned, which causes the sprite to be positioned on the vertex. Then wait a short period (e.g. 50 milliseconds), and call the function again, setting d parameter to 1. This time, by placing the sprite at the point returned, it moves 1 pixel forward in the ellipse path. Then repeat doing so (wait a short period, call the function with increased d value, and position the sprite) until the value of d reaches the perimeter of the ellipse. You can also increase d value by more than one, so that the sprite moves more pixels forward in each step, resulting in faster movement.
Moreover, you can modify the getEllipsePerimeter function in the code to use a more precise formula (like Ramanujan's formula) for getting ellipse perimeter. But in that case, be sure to modify the getPointOnEllipse function as well to use the second version of theta variable (which is commented in the code). Note that the first version of theta is just a simplified form of the second version for the sake of optimization.
In my iphone app, I am required to draw a line between two points and display its slope.
now my calculations are simply based on.
slope = (startPoint.y - endPoint.y) / (startPoint.x - endPoint.x )
the startPoint and endPoint which I have are in terms of screen-pixel coordinates where origin is on top left corner.
but I am displaying this line over a graph where my axes are laid with coordinate system having origin on bottom-left corner on screen.
Will this affect the slope I am calculating ?
I have already taken care of converting x,y coordinates with respect to graph's x,y axes scale units.
If you are not modifying startPoint.y or endPoint.y then the slope will be unchanged, but it won't match what is being drawn to the screen. Also, you will need to handle both x values being the same which will result in a division by zero error.