Point tangent to circle - matlab

Using this as a [reference][1]: Find a tangent point on circle?
cx = 0;
cy = 0;
px = -3;
py = -8;
dx = cx - px;
dy = cy - py;
a = asin(5 / ((dx*dx + dy*dy)^0.5));
b = atan2(dy, dx);
t_1 = deg2rad(180) + b - a;
t_2 = deg2rad(180) + b + a;
For a point (7,6) the angles are 7.9572/73.4434 and for (-3, -8) are 213.6264/285.2615. So for the first quadrant, the angles do not make sense, but for third quadrant they do. What I am doing wrong?

Your formula for a is wrong. You should use
a = acos(5 / ((dx*dx + dy*dy)^0.5))
instead of
a = asin(5 / ((dx*dx + dy*dy)^0.5))
i.e. use acos(...) instead of asin(...). The reason is shown in the image below. The formula for angle a is a=acos(r/H), where r is the radius of the circle and H is the length of the hypotenuse of the right angle triangle. So this has nothing to do with the fact that asin(...) has no way to know which of the two possible quadrants the value that is passed in lies. the argument of the asin is always positive, and you always want the answer in the range 0 to 90 degrees.
So the answer for the two angles that you want are b+a and b-a. Using acos instead of asin in your two cases produces 97.7592 & -16.5566 (or equivalently 343.4434) for your first quadrant example, and -164.7385 & -56.3736 (or equivalently 195.2615 and 303.6264) for your third quadrant example. (NB: instead of adding 180 degrees in the formula for t_1 and t-2, you could just switch the signs of dx and dy)

First -- I spent like 10 minutes figuring out what the heck you're trying to do (which in the end, I got from a comment in one of the answers), while solving your problem took 2 minutes. So, for future reference, please give a description of your problem as clear as you can first.
Now, I think you just have your signs messed up. Try the following:
%// difference vector
%// NOTE: these go the other way around for the atan2 to come out right
dx = px - cx;
dy = py - cy;
%// tip angle of the right triangle
a = asin( 5 / sqrt(dx*dx + dy*dy) );
%// angle between the (local) X-axis and the line of interest
b = atan2(dy, dx);
%// the third angle in the right triangle
%// NOTE: minus a here instead of plus b
g = pi/2 - a;
%// Angles of interest
%// NOTE1: signs are flipped; this automatically takes care of overshoots
%// NOTE2: don't forget to mod 360
t_1 = mod( rad2deg(b - g), 360)
t_2 = mod( rad2deg(b + g), 360)
Alternatively, you could skip computing the intermediate angle a by using acos instead of asin:
%// difference vector
dx = px - cx;
dy = py - cy;
%// Directly compute the third angle of the right triangle
%// (that is, the angle "at the origin")
g = acos( 5 / sqrt(dx*dx + dy*dy) );
%// angle between the (local) X-axis and the line of interest
b = atan2(dy, dx);
%// Angles of interest
t_1 = mod( rad2deg(b - g), 360)
t_2 = mod( rad2deg(b + g), 360)
Just another wayto re-discover the trigonometric identity acos(x) = pi/2 - asin(x) :)

This MathWorld entry is what you want: http://mathworld.wolfram.com/CircleTangentLine.html.

Alright, it looks like you are not accounting for the fact that asin, atan, ( any a-trig function ) has no way to know which of the two possible quadrants the value you passed in lies. To make up for that, a-trig function will assume that your point is in the first or fourth quadrant ( northeast / southeast ). Therefore, if you call atan function and your original point was in the second or third quadrant, you need to add 180 degrees / pi radians onto whatever value it returns.
See the documentation here stating that asin returns a value from [-pi/2, pi/2] :
http://www.mathworks.com/help/matlab/ref/asin.html
Hope that helps :)
EDIT
I misunderstood the situation originally
Here is what I think you have calculated :
t_1 and t_2 represent the angles you would travel at if you started on the circle from the tangent point and wanted to travel to your original starting point.
Viewed with this perspective your angles are correct.
For the point (7,6)
If you started on the circle at approx. (0,5) and traveled at 7 degrees, you would hit the point.
If you started on the circle at approx. (5,0) and traveled at 70 degrees, you would hit the point.
Now, what is going to be more useful and less confusing than angles, will be to know the slope of the line. To get this from the angle, do the following with angle in degrees:
angle = (angle + 90 + 360) % 180 - 90 // this gives us the angle as it would be in quad 1 or 4
slope = tan( deg2rad( angle ) )

Related

Distance from point to ellipse

I need to somehow compute the distance between a point and an Ellipse.
I describe the Ellipse in my program as coordinates x = a cos phi and y = b sin phi (where a,b are constants and phi the changing angle).
I want to compute the shortest distance between a point P and my ellipse.
My thought were to calculate the vector from the center of my ellipse and the point P and then find the vector that start from the center and reaches the end of the ellipse in the direction of the point P and at the end subtract both vectors to have the distance (thi may not give the shortest distance but it's still fine for what I need.
The problem is I don't know how to compute the second vector.
Does someone has a better Idea or can tell me how I can find the second vetor?
Thanks in advance!
EDIT1:
ISSUE:COMPUTED ANGLE DOESN'T SEEM TO GIVE RIGHT POINT ON ELLIPSE
Following the suggestion of MARTIN R, I get this result:
The white part is created by the program of how he calculates the distance. I compute the angle phi using the vector from the center P (of ellipse) to the center of the body. But as I use the angle in the equation of my ellipse to get the point that should stay on the ellipse BUT also having same direction of first calculated vector (if we consider that point as a vector) it actually gives the "delayed" vector shown above.
What could be the problem? I cannot really understand this behavior (could it have something to do with atan2??)
EDIT2:
I show also that in the other half of the ellipse it gives this result:
So we can see that the only case where this works is when we have phi = -+pi/2 and phi = -+pi
IMPLEMENTATION FAILED
I tried using the implementation of MARTIN R but I still get the things wrong.
At first I thought it could be the center (that is not always the same) and I changed the implementation this way:
func pointOnEllipse(ellipse: Ellipse, p: CGPoint) -> CGPoint {
let maxIterations = 10
let eps = CGFloat(0.1/max(ellipse.a, ellipse.b))
// Intersection of straight line from origin to p with ellipse
// as the first approximation:
var phi = atan2(ellipse.a*p.y, ellipse.b*p.x)
// Newton iteration to find solution of
// f(θ) := (a^2 − b^2) cos(phi) sin(phi) − x a sin(phi) + y b cos(phi) = 0:
for _ in 0..<maxIterations {
// function value and derivative at phi:
let (c, s) = (cos(phi), sin(phi))
let f = (ellipse.a*ellipse.a - ellipse.b*ellipse.b)*c*s - p.x*ellipse.a*s + p.y*ellipse.b*c - ellipse.center.x*ellipse.a*s + ellipse.center.y*ellipse.b*c
//for the second derivative
let f1 = (ellipse.a*ellipse.a - ellipse.b*ellipse.b)*(c*c - s*s) - p.x*ellipse.a*c - p.y*ellipse.b*s - ellipse.center.x*ellipse.a*c - ellipse.center.y*ellipse.b*s
let delta = f/f1
phi = phi - delta
if abs(delta) < eps { break }
}
return CGPoint(x: (ellipse.a * cos(phi)) + ellipse.center.x, y: (ellipse.b * sin(phi)) + ellipse.center.y)
}
We can see what happens here:
This is pretty strange, all points stay in that "quadrant". But I also noticed when I move the green box far far away from the ellipse it seems to get the right vector for the distance.
What could it be?
END RESULT
Using updated version of MARTIN R (with 3 iterations)
x = a cos(phi), y = b sin (phi) is an ellipse with the center at
the origin, and the approach described in your question can be realized like this:
// Point on ellipse in the direction of `p`:
let phi = atan2(a*p.y, b*p.x)
let p2 = CGPoint(x: a * cos(phi), y: b * sin(phi))
// Vector from `p2` to `p`:
let v = CGVector(dx: p.x - p2.x, dy: p.y - p2.y)
// Length of `v`:
let distance = hypot(v.dx, v.dy)
You are right that this does not give the shortest distance
of the point to the ellipse. That would require to solve 4th degree
polynomial equations, see for example distance from given point to given ellipse or
Calculating Distance of a Point from an Ellipse Border.
Here is a possible implementation of the algorithm
described in http://wwwf.imperial.ac.uk/~rn/distance2ellipse.pdf:
// From http://wwwf.imperial.ac.uk/~rn/distance2ellipse.pdf .
func pointOnEllipse(center: CGPoint, a: CGFloat, b: CGFloat, closestTo p: CGPoint) -> CGPoint {
let maxIterations = 10
let eps = CGFloat(0.1/max(a, b))
let p1 = CGPoint(x: p.x - center.x, y: p.y - center.y)
// Intersection of straight line from origin to p with ellipse
// as the first approximation:
var phi = atan2(a * p1.y, b * p1.x)
// Newton iteration to find solution of
// f(θ) := (a^2 − b^2) cos(phi) sin(phi) − x a sin(phi) + y b cos(phi) = 0:
for i in 0..<maxIterations {
// function value and derivative at phi:
let (c, s) = (cos(phi), sin(phi))
let f = (a*a - b*b)*c*s - p1.x*a*s + p1.y*b*c
let f1 = (a*a - b*b)*(c*c - s*s) - p1.x*a*c - p1.y*b*s
let delta = f/f1
phi = phi - delta
print(i)
if abs(delta) < eps { break }
}
return CGPoint(x: center.x + a * cos(phi), y: center.y + b * sin(phi))
}
You may have to adjust the maximum iterations and epsilon
according to your needs, but those values worked well for me.
For points outside of the ellipse, at most 3 iterations were required
to find a good approximation of the solution.
Using that you would calculate the distance as
let p2 = pointOnEllipse(a: a, b: b, closestTo: p)
let v = CGVector(dx: p.x - p2.x, dy: p.y - p2.y)
let distance = hypot(v.dx, v.dy)
Create new coordinate system, which transforms ellipse into circle https://math.stackexchange.com/questions/79842/is-an-ellipse-a-circle-transformed-by-a-simple-formula, then find distance of point to circle, and convert distance
I wrote up an explanation using Latex so it could be more readable and just took some screen shots. The approach I am sharing is one using a Newton step based optimization approach to the problem.
Note that for situations where you have an ellipse with a smaller ratio between the major and minor axis lengths, you only need a couple iterations, at most, to get pretty good accuracy. For smaller ratios, you could even probably get away with just the initial guess's result, which is essentially what Martin R shows. But if your ellipses can be any shape, you may want to add in some code to improve the approximation.
You have the Ellipsis center of (a, b) and an arbitrary point of P(Px, Py). The equation of the line defined by these two points looks like this:
(Y - Py) / (b - Py) = (X - Px) / (a - Px)
The other form you have is an ellipse. You need to find out which are the (X, Y) points which are both on the ellipse and on the line between the center and the point. There will be two such points and you need to calculate both their distance from P and choose the smaller distance.

Find Position based on signal strength (intersection area between circles)

I'm trying to estimate a position based on signal strength received from 4 Wi-Fi Access Points. I measure the signal strength from 4 access points located in each corner of a square room with 100 square meters (10x10). I recorded the signal strengths in a known position (x, y) = (9.5, 1.5) using an Android phone. Now I want to check how accurate can a multilateration method be under the circumstances.
Using MATLAB, I applied a formula to calculate distance using the signal strength. The following MATLAB function shows the application of the formula:
function [ d_vect ] = distance( RSS )
% Calculate distance from signal strength
result = (27.55 - (20 * log10(2400)) + abs(RSS)) / 20;
d_vect = power(10, result);
end
The input RSS is a vector with the four signal strengths measured in the test point (x,y) = (9.5, 1.5). The RSS vector looks like this:
RSS =
-57.6000
-60.4000
-44.7000
-54.4000
and the resultant vector with all the estimated distances to each access points looks like this:
d_vect =
7.5386
10.4061
1.7072
5.2154
Now I want to estimate my position based on these distances and the access points position in order to find the error between the estimated position and the known position (9.5, 1.5). I want to find the intersection area (In order to estimate a position) between four circles where each access point is the center of one of the circles and the distance is the radius of the circle.
I want to find the grey area as shown in this image :
http://www.biologycorner.com/resources/venn4.gif
If you want an alternative way of estimating the location without estimating the intersection of circles you can use trilateration. It is a common technique in navigation (e.g. GPS) to estimate a position given a set of distance measurements.
Also, if you wanted the area because you also need an estimate of the uncertainty of the position I would recommend solving the trilateration problem using least squares which will easily give you an estimate of the parameters involved and an error propagation to yield an uncertainty of the location.
I found an answear that solved perfectly the question. It is explained in detail in this link:
https://gis.stackexchange.com/questions/40660/trilateration-algorithm-for-n-amount-of-points
I also developed some MATLAB code for the problem. Here it goes:
Estimate distances from the Access Points:
function [ d_vect ] = distance( RSS )
result = (27.55 - (20 * log10(2400)) + abs(RSS)) / 20;
d_vect = power(10, result);
end
The trilateration function:
function [] = trilat( X, d, real1, real2 )
cla
circles(X(1), X(5), d(1), 'edgecolor', [0 0 0],'facecolor', 'none','linewidth',4); %AP1 - black
circles(X(2), X(6), d(2), 'edgecolor', [0 1 0],'facecolor', 'none','linewidth',4); %AP2 - green
circles(X(3), X(7), d(3), 'edgecolor', [0 1 1],'facecolor', 'none','linewidth',4); %AP3 - cyan
circles(X(4), X(8), d(4), 'edgecolor', [1 1 0],'facecolor', 'none','linewidth',4); %AP4 - yellow
axis([0 10 0 10])
hold on
tbl = table(X, d);
d = d.^2;
weights = d.^(-1);
weights = transpose(weights);
beta0 = [5, 5];
modelfun = #(b,X)(abs(b(1)-X(:,1)).^2+abs(b(2)-X(:,2)).^2).^(1/2);
mdl = fitnlm(tbl,modelfun,beta0, 'Weights', weights);
b = mdl.Coefficients{1:2,{'Estimate'}}
scatter(b(1), b(2), 70, [0 0 1], 'filled')
scatter(real1, real2, 70, [1 0 0], 'filled')
hold off
end
Where,
X: matrix with APs coordinates
d: distance estimation vector
real1: real position x
real2: real position y
If you have three sets of measurements with (x,y) coordinates of location and corresponding signal strength. such as:
m1 = (x1,y1,s1)
m2 = (x2,y2,s2)
m3 = (x3,y3,s3)
Then you can calculate distances between each of the point locations:
d12 = Sqrt((x1 - x2)^2 + (y1 - y2)^2)
d13 = Sqrt((x1 - x3)^2 + (y1 - y3)^2)
d23 = Sqrt((x2 - x3)^2 + (y2 - y3)^2)
Now consider that each signal strength measurement signifies an emitter for that signal, that comes from a location somewhere at a distance. That distance would be a radius from the location where the signal strength was measured, because one would not know at this point the direction from where the signal came from. Also, the weaker the signal... the larger the radius. In other words, the signal strength measurement would be inversely proportional to the radius. The smaller the signal strength the larger the radius, and vice versa. So, calculate the proportional, although not yet accurate, radius's of our three points:
r1 = 1/s1
r2 = 1/s2
r3 = 1/s3
So now, at each point pair, set apart by their distance we can calculate a constant (C) where the radius's from each location will just touch one another. For example, for the point pair 1 & 2:
Ca * r1 + Ca * r2 = d12
... solving for the constant Ca:
Ca = d12 / (r1 + r2)
... and we can do this for the other two pairs, as well.
Cb = d13 / (r1 + r3)
Cc = d23 / (r2 + r3)
All right... select the largest C constant, either Ca, Cb, or Cc. Then, use the parametric equation for a circle to find where the coordinates meet. I will explain.
The parametric equation for a circle is:
x = radius * Cos(theta)
y = radius * Sin(theta)
If Ca was the largest constant found, then you would compare points 1 & 2, such as:
Ca * r1 * Cos(theta1) == Ca * r2 * Cos(theta2) &&
Ca * r1 * Sin(theta1) == Ca * r2 * Sin(theta2)
... iterating theta1 and theta2 from 0 to 360 degrees, for both circles. You might write code like:
for theta1 in 0 ..< 360 {
for theta2 in 0 ..< 360 {
if( abs(Ca*r1*cos(theta1) - Ca*r2*cos(theta2)) < 0.01 && abs(Ca*r1*sin(theta1) - Ca*r2*sin(theta2)) < 0.01 ) {
print("point is: (", Ca*r1*cos(theta1), Ca*r1*sin(theta1),")")
}
}
}
Depending on what your tolerance was for a match, you wouldn't have to do too many iterations around the circumferences of each signal radius to determine an estimate for the location of the signal source.
So basically you need to intersect 4 circles. There can be many approaches to it, and there are two that will generate the exact intersection area.
First approach is to start with one circle, intersect it with the second circle, then intersect the resulting area with the third circle and so on. that is, on each step you know current intersection area, and you intersect it with a new circle. The intersection area will always be a region bounded by circle arcs, so to intersect it with a new circle you walk along the boundary of the area and check whether each bounding arc intersects with a new circle. If it does, then you leave only the part of the arc that lies inside a new circle, remember that you should continue with an arc from a new circle, and continue traversing the boundary until you find the next intersection.
Another approach that seems to result in a worse time complexity, but in your case of 4 circles this will not be important, is to find all the intersection points of two circles and choose only those points that are of interest for you, that is which lie inside all other circles. These points will be the corners of your area, and then it is rather easy to reconstruct the area. After googling a bit, I have even found a live demo of this approach.

calculate the angle between 2 vectors, clockwise and from 0 to 2*pi

I have two (2-D) vectors with a common vertex ( I had made these 2 vectors out of 3 given points ) . I want to find the angle between them, from 0 to 2*pi, and I need it clockwise and positive. I currently use this:
v1=[x1 y1]-[X Y];
v2=[x2 y2]-[X Y];
ang = mod(atan2(v1(1)*v2(2)-v2(1)*v1(2),v1(1)*v2(1)+v1(2)*v2(2)),2*pi);
if ang==0
Angle=ang;
else
Angle=360 - (ang*180/pi); % change Radian to Degree
end
Although it works correctly, I was wondering if there is any better way to find the angle, maybe not using if/else??!
Thanks in advance
I assume you want to restrict the output to the half-open interval [0, 360). In that case, simply do the mod at the end, after your other conversions, no if required:
ang = atan2(v1(1)*v2(2)-v2(1)*v1(2),v1(1)*v2(1)+v1(2)*v2(2));
Angle = mod(-180/pi * ang, 360);
The clockwise angle is the exact opposite from what atan2 assumes, so you just have to negate it:
Angle = mod(-atan2(v1(1)*v2(2)-v1(2)*v2(1), v1*v2'), 2*pi) * 180/pi;
which is, in essence, identical to Bas' answer I see now :)

Angle between looking direction and latitude/longitude

I am experimenting a little with AR. I have got the angle of the direction I am looking to from a compass in degrees. I know my own position and the position of another object (POI), the position is giving in form of latitude and longitude.
Now I would like to know how I can calculate the angle between the direction I am looking to and the POI.
Dot Product:
a . b = ||a|| ||b|| cos(t)
t = acos( (a.b)/(||a|| ||b||) )
||vector|| = length of vector (magnitude)
t = angle between the two vectors
Your probably going to need to do this a couple times for each plane you have. (1x for 2D, 2x for 3D)
Or:
/|
/ |
h / | y
/ |
/____|
x
t is the lower left corner, which we'll assume is your object, the upper right corner is going to be your other object
x = obj2.x - obj1.x
y = obj2.y - obj1.y
h = sqrt( (x*x) + (y*y) )
sin(t) = y/h
cos(t) = x/h
tan(t) = y/x
t = asin(y/h)
t = acos(x/h)
t = atan(y/x)
What makes the first method better, is that it account's for you're current rotation. The second method (using atan, asin, and acos) doesn't.

Trigonometry calculation

I assume this is would be a basic question however, my math skills are lacking.
I am working on an iphone game where people draw their own platform to bounce an egg up.
The game consists of a platform connecting 2 nodes each of these nodes has an x and y value this platform can be at any angle depending on how the user draws it, when something hits this platform I need it to hit off perpendicularly. I know how much total power I need, how would I break it down between X and Y. I drew a picture to better explain...
Here are two examples the info I have about the problem is the X & Y coordinate of the nodes, and the length of the dotted perpendicular line. What I need to find is the length of the X and Y lines and if the X is going in a positive or negative direction.
If you have two nodes, N1 and N2, and line length of L, then:
ndx = N1.x - N2.x
ndy = N1.y - N2.y
ndist = sqrt(ndx*ndx + ndy*ndy)
x = ndy * L / ndist
y = ndx * L / ndist
If your two points are A and B, and the length of your line is L, you first need to find the angle AB makes with respect to the x-axis:
theta = atan( (B.x - A.x) / (B.y - A.y) )
Armed with this, you can figure out x and y thusly:
x = L * cos( theta )
y = L * sin( theta )
The only edge case you will have to consider is for a horizontal line (in which case the computation will fail because of divide by zero when calculating theta). In the case of a horizontal line, x=0 and y=L.