Creating a navigation system (ArcTan2) - delphi

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.

Related

How do I find specific points on a image, regardless of the rotate?

I have such a picture.
This is the numbers of the dots on the picture. I want the dot numbers to stay the same even if I turn the picture upside down. This rotation can be any angle value.
For example
Head up
Upside down
90 degree
45 degree
I tried a few things like Opencv camera calibration and Pose Estimation but I couldn't get the point numbers to be fixed.
I don't think this is a programming problem, but a basic geometry one.
You've got 7 points in that configuration and you want to find some geometric properties which are robust to rotation. The first thing I can think of is distance.
Compute the squared distance (SD) between all points, then find the one which maximizes the sum of squared distances (SSD) to all others. That point is P7.
Find the one with maximum SD from P7. That point is P1.
Find the one with minimum SD from P7. That point is P6.
Find the one with second minimum SD from P7. That point is P5.
Find the one with minimum SD from P1. That point is P2.
In order to find P3 and P4 you need to detect a side (left/right) with respect to a direction. Let's call Q and R the two unknown points and a direction we are already sure of, such as the one from 1 to 7. You can now look at the sign of the cross product between vector from P1 to P7 and the one from P1 to Q. If it's at the right, the value will be positive. So we are able to find its identity.
if ( (Q.x - P1.x) * (P2.y - P1.x) - (Q.y - P1.y) * (P2.x - P1.x) > 0) {
P3 = Q;
P4 = R;
}
else {
P3 = R;
P4 = Q;
}

Delphi GDI+ find point on an arc using the known rectangle and angle

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)

Moving multiple sprites in elliptical path with uniform speed

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.

Trying to determine if a movement vector is CW or CCW around a point

I'm writing some Touch input code for an iOS device and need to determine whether the movement of a swipe is clockwise or counterclockwise relative to the center of the screen.
Using the position and deltaPosition of the touch, I can calculate an angle between vectors from the center of the screen to those points using the dot product but that doesn't give me a signed angle to decide whether it's CW or not.
How can I tell which direction around the center the swipe has moved?
Let A denote the swipe vector, and B the vector from the start of the swipe to the center of the screen. You can then calculate the determinant of the components of A and B:
| A.x A.y |
| B.x B.y |
= A.x * B.y - B.x * A.y
The sign of the determinant will tell you whether B points to the right side or to the left side of A.
As #Jeremy W. Sherman correctly notes, which sign corresponds to which direction depends on how the coordinate system of the screen is laid out. If the x axis runs to the right and the y axis runs downward, positive means CW and negative means CCW (if I got the mental math right). Zero always means movement directly towards or directly away from the center.

Calculating control points for a shorthand/smooth SVG path Bezier curve

Link: Official SVG Reference
Hello men and women, I am having some trouble with shorthand (defined by S or s in pathdata) bezier curves defined as SVG paths. Specifically, how to calculate the first control point.
Say we have one curveto command with control points (X1, Y1) and (X2, Y2), endpoint (X3, Y3) and starting point (X0, Y0).
Next comes a shorthand/smooth curve command with a first control point (X4, Y4) and second control point (X5, Y5). Assume everything is in absolute coordinates for simplicity.
How would one calculate the unknown first control point (X4, Y4) from the other known points?
Your first point is the last point of the previous curve. In this case it would be (x3, y3). Then your second point in the short hand is the terminating point for the length of the curve the shorthand represents.
If we are to translate your paths into both full length versions we would have:
M X0, Y0 C X1, Y1 X2, Y2 X3, Y3
M X3, Y3 C XR, YR X4, Y4 X5, Y5
Where XR, YR is the reflection of the last control point of the previous curve about the first point of the current curve.
XR, YR is just the reflection of P2 about P3 so:
XR = 2*X3 - X2 and
YR = 2*Y3 - Y2
you can treat the last control point from the last curve and the end point of the last curve( which is the first point in the new curve) as a line, and the mirrored control point should lie on that line at a distance equal to the distance from the last control point to the last end point
I found this. The shortest answer I can cite from it is:
We join the anchor points surrounding the start and the end anchor points with a line (let’s call these the opposed-lines):
For the line to be smooth, the position of each control point has to
be relative to its opposed-line:
The control point is on a line parallel to the opposed-line, and tangent to the current anchor point.
On this tangent line, the distance from the anchor point to the control point depends on the length of the opposed-line and an arbitrary smoothing ratio.
The start control point goes in the same direction as the opposed-line, while the end control point goes backward.
// When 'current' is the first or last point of the array
// 'previous' or 'next' don't exist.
// Replace with 'current'
const p = previous || current
const n = next || current
My interpretation:
Calculate the 2 control points for each pair of "anchor" (actual curve) points.
If points 1 (start/end - 1) and 2 (start + 1/end) are being calculated:
The first control point runs from point 1 (start) parallel to { the line going from point 0 (start - 1) to point 2 (start + 1) }.
The second control point runs backwards from point 2 (end) parallel to { the line going from point 1 (end - 1) to point 3 (end + 1) }.
The distance from the point 1 or 2 to the corresponding control point is a ratio of the desired smoothness variable (0.0 - 1.0) of the curve to the length of the parallel lines. (You can use basic trig, i.e. cos() and sin() for the angles.)
In the case of the end points (which have no point before/after them), replace start - 1 with start or end + 1 with end.

Resources