How do I move through an arc between two specific points?

I've found many answers to similar questions here, but I'm still stuck.

I want to move an object from point sx,sy to point dx,dy through an arc that bulges by distance b from the line straight between those two points.

The equations for a circle are:

cx,cy = center of circle
x = r * cos(t) + cx
y = r * sin(t) + cy
d = distance between the two points
r = (4*b*b + d*d) / (8*b)


I think the center of the circle is:

cx = sx - r * cos(startingT)
cy = sy - r * sin(startingT)


The total angle that must be traveled between the two points is:

travelAng = atan2(dy-sy,dx-sx)


However, I don't know what the starting angle (startingT) is which I'd use in the equations for the circle.

EDIT:

I've tried a few points and the following seems to work:

r =(4*b^2 + d^2) / (8*b)
cx = r * cos((2*atan(b) + 90)*PI/180) + sx
cy = r * sin((2*atan(b) + 90)*PI/180) + sy
startingT = acos((sx - cx)/r)


To get the opposite bulge along the same lines:

cx = r * cos((2*atan(b) + 180)*PI/180) + sx
cy = r * sin((2*atan(b) + 180)*PI/180) + sy
startingT = acos((sx - cx)/r) + PI


Theses results can then be plugged into the equations for the circle.

x = r * cos(t) + cx
y = r * sin(t) + cy


To plot 11 points along the arc I'd plot with t=startingT and then add travelAng/10 for each new point.

I'm not sure if these equations can be simplified somehow, but so far they seem to work.

EDIT: Ok, this just simply doesn't work. I got it to work for a circle around 0,0 with r=1, but changing parameters always breaks things. If I set the bulge b=0.001 to try and create a nearly straight line, the results end up ridiculously wrong. I have no idea what else to try.

EDIT: Ok, I'm just going to forget about this approach. I see lots of questions about this sort of thing but no answers that actually work given these inputs. However, I now realize that I could just apply apply an acceleration perpendicular to the path of travel and then reverse the acceleration half way through. The result would be a curve. I'll just experiment until I find an acceleration which looks decent. (I feel stupid for not thinking of this earlier.)

-

Let $d$ be the distance between your starting and ending points, and $b$ the bulge. Note that the starting point, the midpoint of the starting and ending points, and the centre of the circle form a right triangle. If $r$ is the radius of the circle, we have $r^2 = (d/2)^2 + (r-b)^2$.
Solving that for $r$, we get $$r = \frac{4 b^2 + d^2}{8b}$$
The centre of the circle is at a distance $r - b$ from the midpoint on the perpendicular bisector of the line from start to end. In vectors, if $A = [x_A,y_A]$ is the start and $B = [x_B, y_B]$ the end, the centre is $$C = \dfrac{A+B}{2} \pm \frac{4b^2 + d^2}{8bd} [y_A - y_B, x_B - x_A]$$

-
I'm afraid I don't follow how you derive the origin using the perpendicular bisector. I can find the point halfway along the line between the two points using (A+B)/2. However, I don't understand the rest. To get x0 it looks like x0=(sx+dx)/2 + r/d * (sy-dy), but I put some values in there and that doesn't work. – HappyEngineer Sep 3 '13 at 7:26

On the page I've been lookinga t on the subject http://www.afralisp.net/archive/lisp/Bulges1.htm they actually have that c (for chord) is the distance between the 2 points and $s = (c/2)*b$ (s for sagitta) with $r = ((c/2)^2+s^2)/2s$

On the webpage I've listed above it explains very well why the travel angle is 4arctan(b) where b is the bulge

Right: I think i've finally cracked it, using the almost complete explanation on the page linked to above. Here's how it goes:

We know starting point S and finishing point D and bulge (b).

1. We can find the angle turned through $(\theta)$ using $\theta = 4arctan(b)$

2. By Pythagoras, the chord (the line directly joining S and D) is given by

$c = \sqrt{(Sx-Dx)^2+(Sy-Dy)^2}$

3. The sagitta is computed using $s = \frac{bc}{2}$

4. The radius $r = \frac{((\frac{c}{2})^2 + s^2)}{2s}$

5. With angles in degrees, we find the centre of the circle using $Cx = rcos(\frac{\theta}{2} + 90) + Sx$ and $Cy = rsin(\frac{\theta}{2} + 90) + Sy$ OR

6. If the arc is clockwise, rather than anticlockwise (I think I've got clockwise and anitclockwise the right way round here) $Cx = rcos(\frac{3\theta}{2} - 90) + Sx$ and $Cy = rsin(\frac{3\theta}{2} - 90) + Sy$ OR

(see webpage quoted for an explanation of why). Points 1 requires a but of reading to understand. Point 2 is simple. 3's quites straight forward. I don't know why 4 works at the moment, but I've taken the author of the webpage's word for it. I haven't got my head around why 5 works either. I'm not even 100% sure I've implemented it correctly. I'd check on the webpage to make sure you agree with my reasoning. The author actually gives 2 methods (I've used the first) but neither is explained comprehensively.

-
I have a game in which I want to fly an object through an arc. I know the starting and ending points. I know the bulge in the arc. The angles need to be derived from that information. – HappyEngineer Sep 3 '13 at 5:58
Yes, the angle I swing through is the same, but I need to display images at various points along the arc on the screen, so I can't choose an arbitrary starting point. The equations you've given me do give me r, but I still don't know startingT. – HappyEngineer Sep 3 '13 at 6:29
I can't make that work. I tested with sx,sy=1,0 and dx,dy=0,1 which has a midpoint of 0.5,0.5. Using that I calculated the bulge would be 0.293 if the center point was at 0,0. However, plugging those values into your equations gives an r of 1.31 when it should be r=1 obviously. – HappyEngineer Sep 3 '13 at 19:45
Oh, but if I use the real value of r which I can get from Robert's answer, and plug that into your equations for Cx and Cy I get 1,1 which is the OTHER possible center for the given values. I'll see if the answer holds up for other solutions. – HappyEngineer Sep 3 '13 at 20:25
Oh, yes, sorry, I forgot to say there's a term in the fifth equation (which finds the center of the circle) which can be pos or neg (depending on whether the arc is clockwise or anticlockwise): see my modifications to the answer. Also, you need to use the absolute value of bulge in all the equations, or else you can end up with a negative radius. – George Tomlinson Sep 4 '13 at 11:13

OK. I started trying to express my solution in words, and found out it was faster to write it in Matlab. If you're not familiar with matlab, the only subtlety is that variables store arrays of data, so p = [2 4] makes a 1 x 2 array with two elements, p(1) = 2 and p(2) = 4. (Note that indexing starts at 1, not zero). To make a column vector, you can transpose things with an apostrophe, as in

p = [2 4]'

or you can separate items with a semicolon:

p = [2 ; 4]

Both produce a 2 x 1 matrix.

Multiplying a number by a matrix is allowed, as in

2 * [1 3]

which produces [2 6].

Adding matrices of the same size is allowed, as in [2 3] + [1 0], which produces [3 3].

Comments start at a "%" sign and extend to the right. Lines end with semicolons to suppress Matlab's default, which is to print out any value you compute.

There are lots of built-in functions, like atan2() and dot() (the inner product of vectors) and sqrt() (the square root).

The last half of the code below is used to produce nicely labeled figures, but the meat of the thing is in the computation of x(i) and y(i). I've run the code on a bunch of examples, and copied the output to a picassa album; the top of each picture shows the parameters that the function was invoked with. See https://picasaweb.google.com/115433231134409106747/MatlabPics?authuser=0&feat=directlink

The code below seems to work in all cases, although the "draw and label the figure at the same time" part fails when the bump is larger than half the distance between the two points.

======
MATLAB code for solving the "bulge" problem.
======

function bulge(x1, y1, x2, y2, b)
% draw a circle arc from P1 = (x1, y1) to P2 = (x2, y2) that bulges a
% distance b to the LEFT of the arrow from P1 to P2. (use b < 0 to get a
% bulge to the right.) The radius of the circle will be called "r".

% Setting up how test appears for Matlab
set(0, 'DefaultTextInterpreter', 'latex', 'DefaultTextFontSize', 10)

if (b == 0)
error('code does not handle the straight-line case');
end
P1 = [x1, y1]';           % The ' means "transpose", so P1 is a col. vector
P2 = [x2, y2]';
v = P2 - P1;              % vector from p1 to p2
t2 = sqrt(dot(v, v));     % distance between p1 and p2
if (t2 == 0)
error('start and end point must be distinct')
end
v = v / t2;               % make v have unit length
vp = [-v(2) v(1)]';        % v rotated 90 degrees clockwise.
M = (P1 + P2)/2;          % midpoint of chord.
t = t2/2;                 % distance from M to P1 or to P2.

% Let S denote the midpoint of the arc we're drawing.
%
% The distance u from M to the circle center C satisfies two
% equations:
% First,
%   u^2 + t^2 = r^2
% because C M P2 is a right triangle, and the distance from C to P2 is r,
% the radius of the circle
%
% Second
%   u + |b| = r
% because the union of the segments CM and MS is a radius of the circle,
% and CM has length u, while MS has length b.
%
% We can solve for u:
% u = (t^2 - b^2)/(2|b|).
%
u = (t^2 - b^2)/(2*abs(b));

% Now compute the locations of S and C, and the radius.

if (b > 0)
C = M - u*vp;
else
C = M + u * vp;
end
S = M + b*vp;
r = sqrt(u^2 + t^2);

% From here on, it's downhill sledding.
% Find the ray from C to P1 and C to P2:

dir1 = (P1 - C)/r;
dir2 = (P2 - C)/r;

% Find the angles of these rays relative to the x-axis
% (so a ray in the positive-x direciton ahs angle 0; postive y gives pi/2
% negative y gives -pi/2, and so on, wiht the max values being +pi and -pi.
%

theta1 = atan2(dir1(2), dir1(1));
theta2 = atan2(dir2(2), dir2(1));

% We now want to build points of the form
% C + r [cos t, sin t]'
%
% where t ranges from theta1 to theta2.
%
% But the wraparound at -pi and pi poses problems.
%
% One observation: for b > 0, the angle t should be DECREASING from
% theta1 to theta2, so if theta1 is less than theta2, we need to add 2pi.
% The opposite holds if b < 0.

if (b > 0)
if (theta1 < theta2)
theta1 = theta1 + 2*pi;
end
else
if (theta2 < theta1)
theta2 = theta2 + 2*pi;
end
end

n = 15; % draw 15 points.
dt = (theta2 - theta1) / (n-1);

xs = zeros(1, n);
ys = zeros(1, n);
for i = 1:n  % "for i = 0 to n" in many programming languages
u = theta1 + (i-1)*dt;
vv = (r * [cos(u), sin(u)]') + C;
xs(i) = vv(1);
ys(i) = vv(2);
end
plot(xs, ys, '-or', 'MarkerSize', 1.5, 'MarkerFaceColor', 'k');

hold on;   % let other stuff be drawn over this same plot
plot(P1(1), P1(2), 'og', 'MarkerSize', 3, 'MarkerFaceColor', 'g');
text(P1(1), P1(2)-0.05, 'P1');
plot(P2(1), P2(2), 'og', 'MarkerSize', 3, 'MarkerFaceColor', 'g');
text(P2(1), P2(2)-0.05, 'P2');
plot(M(1), M(2), 'or', 'MarkerSize', 3, 'MarkerFaceColor', 'r');
text(M(1), M(2)-0.05, 'M');
plot(C(1), C(2), 'or', 'MarkerSize', 3, 'MarkerFaceColor', 'r');
text(C(1), C(2)-0.05, 'C');
plot([C(1), S(1)], [C(2), S(2)], 'k-');
plot(S(1), S(2), 'ob', 'MarkerSize', 3, 'MarkerFaceColor', 'b');
text(S(1), S(2)+0.05, 'S');
plot([M(1), P2(1)], [M(2), P2(2)], 'k-');
zz = (M + P2)/2;
text(zz(1), zz(2), 't');
zz = (M + S)/2;
text(zz(1), zz(2), ' $| b |$ ');
zz = (M + C)/2;
text(zz(1), zz(2), 'u');
zz = (C + P2)/2;
text(zz(1), zz(2), 'r');
plot([C(1), P2(1)], [C(2), P2(2)], 'k-');

hold off;
set(gca, 'DataAspectRatio', [1 1 1]);
titlestring = ['$\mathbf {P_1 = ', mat2str(P1), '; P_2 = ', ... mat2str(P2),'; b = ', ... mat2str(b),'}$'];
title(titlestring);
figure(gcf);

-

I reuse the formula for the radius of the circle from prof. Israel's answer: $$r=\frac{4b^2+d^2}{8b},$$ where $d$ is the distance between two points and $b$ is the bulge. The center of the circle will be at distance $r-b$ from the midpoint. So if the two points are $A=(x_A,y_A)$ and $B=(x_B,y_B)$ then $$(x_C,y_C)=\frac{(x_A+x_B,y_A+y_B)}2\pm \frac{r-b}d(y_B-y_A,x_A-x_B).$$ Here the vector $(y_B-y_A,x_A-x_B)$ is orthogonal to the line from $A$ to $B$, and its length is also $d$.

You asked for tests with $A=(0,1)$ and $B=(1,0)$. Here's what Mathematica gave me with $b=0.2$, $b=0.1$ and $b=0.05$. I used the built-in function ParametricPlot and clipped the image to contain only the part within the square $[0,2]\times [0,2]$. The respective radii of the circles were $1.35,2.55, 5.025$.

-
Sorry about the typo in the formula for $r$. Now fixed. – Jyrki Lahtonen Sep 15 '13 at 5:39