How to calculate coordinates of tangent points? - math

I need to make a svg file for a project and I need some parameters that I haven't figured out how to calculate yet.
I have a point of coordinates x1,y1 and a circumference with a center of coordinates x2,y2 with radius r. The point x1,y1 is outside the circumference. How do I calculate the coordinates of the points belonging to the circumference (x3,y3 and x4,y4) from which the two tangent lines would pass? The outer point (x1,y1) will never touch the circumference and will never belong to the circumference.
This is the drawing to make the concept better understood, in red the values to be calculated.
Tangents scheme

Shift coordinate system to make origin in circle center (to get simpler equations). Now point is
x1' = x1 - x2
y1' = y1 - y2
Solve the next equation system (point belongs to circumference and radius is perpendicular to tangent)
x^2 + y^2 = r^2
(x - x1') * x + (y - y1') * y = 0
for unknown x, y.
To get final result, add x2, y2 to solution results (should be two solutions)
import math
def tangpts(px, py, cx, cy, r):
px -= cx
py -= cy
r2 = r*r
r4 = r2*r2
a = px*px+py*py
b = -2*r2*px
c = r4 - r2*py*py
d = b*b-4*a*c
if d < 0:
return None
d = math.sqrt(d)
xx1 = (-b - d) / (2*a)
xx2 = (-b + d) / (2*a)
if (abs(py) > 1.0e-8):
yy1 = (r2 - px * xx1) / py
yy2 = (r2 - px * xx2) / py
else:
yy1 = math.sqrt(r2 - xx1*xx1)
yy2 = -yy1
return((xx1+cx,yy1+cy),(xx2+cx,yy2+cy))
print(tangpts(0.5, 0.5, 0, 0, 1))
print(tangpts(1, 1, 0, 0, 1))
print(tangpts(0, 0, -3, -3, 3))
print(tangpts(2, 0, 0, 0, 1))
print(tangpts(0, 1, 0, 0, 1))
>>>
None #point inside
((0.0, 1.0), (1.0, 0.0)) #common case
((-3.0, 0.0), (0.0, -3.0)) #common case
((0.5, 0.8660254037844386), (0.5, -0.8660254037844386)) #py is zero case
((0.0, 1.0), (0.0, 1.0)) # single tangent case - point at circumference

In order to post the python code for the solution, I'm copying the explanation originally in comments:
The center of the circle is P2(x2, y2), the radius is r. The unknown point P3(x3, y3) satisfies the equation of the circle:
(x3-x2)^2 + (y3-y2)^2 = r^2 (1).
The tangent P1P3 is perpendicular to the radius of the circle P2P3. So apply the Pythagorean theorem to the triangle P1P2P3:
a) the distance between P1 and P2 is (x1-x2)^2 + (y1-y2)^2,
b) the distance between P1 and P3 is (x1-x3)^2 + (y1-y3)^2
c) the distance P2P3 is r, the radius
(x1-x3)^2 + (y1-y3)^2 + r^2 = (x1-x2)^2 + (y1-y2)^2 (2)
We have thus to solve the equations (1) and (2) for x3 and y3.
We now separate the unknowns (a linear relation between x3 and y3 can be obtained by (1)-(2) => (x3-x2)(x1-x2) + (y3-y2)(y1-y2) = r^2), and we get the two equations of second degree.
The python implementation:
import math
def tangentPoints(x1, y1, x2, y2, r):
a = (y1-y2)**2+(x1-x2)**2
bx = -r**2 * (x1-x2)
cx = r**2 * (r**2-(y1-y2)**2)
sqDeltax = math.sqrt(bx**2 - a*cx)
x3 = x2 + (-bx + sqDeltax)/a
x4 = x2 + (-bx - sqDeltax)/a
by = -r**2 * (y1-y2)
cy = r**2 * (r**2 - (x1-x2)**2)
sqDeltay = math.sqrt(by**2 - a*cy)
y3 = y2 + (-by - sqDeltay)/a
y4 = y2 + (-by + sqDeltay)/a
return (x3, y3), (x4, y4)

Related

Find xy coordinates of a point knowing its distance to other 2 points

I'm writing a code in R to calculate the xy coordinates of point, using the law of cosines.
I have two reference points (1 and 2) which the xy coordinates are known. I want to find the coordinates of the other point (3). I know the distances 3-1, 3-2 and 1-2, but I don't know the angles between them.
Thanks in advance for any help!
I've tried some trigonometric equations I've found on web and Rohlf&Archie 1978 paper, but they don't work.
You haven't told us your set-up exactly, but it sounds as though you have two known x, y, co-ordinates:
x1 <- 1
x2 <- 5
y1 <- 3
y2 <- 6
And known distances between these two points plus a third point:
d12 <- 5
d13 <- 8
d23 <- 5
We can draw them like this:
plot(c(x1, x2), c(y1, y2), xlim = c(0, 12), ylim = c(0, 12))
text(c(x1, x2), c(y1, y2) + 0.5, labels = c('1', '2'))
Now, it's obviously easy to calculate the angle between the horizontal line and the segment joining points 1 and two - it's just the arctangent of the slope:
abline(h = y1, lty = 2)
theta <- atan2(y2 - y1, x2 - x1)
segments(x1, y1, x1 + d12 * cos(theta), y1 + d12 * sin(theta), lty = 2)
Now, although we don't know where point 3 is, we can use the law of cosines to calculate the angle 3-1-2 like this:
angle_312 <- acos((d12^2 + d13^2 - d23^2)/(2 * d12 * d13))
To get this in terms of angle from the horizontal we can do:
angle_13 <- angle_312 - theta
This allows us to work out the co-ordinates of point 3:
x3 <- x1 + d13 * cos(angle_13)
y3 <- y1 + d13 * sin(angle_13)
We can draw this point on our plot as follows:
points(x3, y3)
text(x3, y3 + 0.5, '3')
And we can show that it is correct by drawing circles of the correct radius around points one and two. Point 3 should be at the meeting point of the two circles:
polygon(x1 + dist_1_3 * cos(seq(0, 2 * pi, length = 100)),
y1 + dist_1_3 * sin(seq(0, 2 * pi, length = 100)), lty = 2)
polygon(x2 + dist_2_3 * cos(seq(0, 2 * pi, length = 100)),
y2 + dist_2_3 * sin(seq(0, 2 * pi, length = 100)), lty = 2)
Note that there is a second solution at the other point where the circles meet: in this case we would get that by changing angle_13 <- angle_312 - theta to angle_13 <- angle_312 + theta:
angle_13 <- angle_312 + theta
x3 <- x1 + d13 * cos(angle_13)
y3 <- y1 + d13 * sin(angle_13)
points(x3, y3)
text(x3, y3 + 0.5, '3')
Suppose we are using the following conditions:
pointA <- c(x1 = 1, y1 = 1)
pointC <- c(x2 = 4, y2 = 1)
AC <- sqrt(
(pointA[["x1"]] - pointC[["x2"]])^2 +
(pointA[["y1"]] - pointC[["y2"]])^2
)
AB <- 4
BC <- 5
We are looking for coordinates of point B (points B1 and B2) (x3 and y3 / x3' and y3').
First we find cos and sin of angle C (ACB1 == ACB2 as CB1==CB2==a; AB1==AB2==c and AC=b is common):
cosC <-(AC^2 + BC^2 - AB^2) / (2*AC*BC)
sinC <- sqrt(1-cosC^2)
It is obvious that there are two possible solutions for the conditions.
Then the points will be
pointB1 <- c(x3 = pointC[["x2"]] + BC*cosC,
y3 = pointC[["y2"]] + BC*sinC)
pointB2 <- c(x3 = pointC[["x2"]] - BC*cosC,
y3 = pointC[["y2"]] - BC*sinC)
Now we can check the results:
> sqrt(
+ (pointB1[["x3"]] - pointC[["x2"]])^2 +
+ (pointB1[["y3"]] - pointC[["y2"]])^2
+ )
[1] 5
> sqrt(
+ (pointB2[["x3"]] - pointC[["x2"]])^2 +
+ (pointB2[["y3"]] - pointC[["y2"]])^2
+ )
[1] 5
The advantage of this solution that we do not call low precision acosfunction as well as other trigonometric functions. And use cosC / sinC as temporary variables only.

how to goal seek in R

I am attempting to write a function in R to determine the distance between two circles with known radii (r0 and r1) and a given area of overlap.
I first wrote a function to determine the area of overlap.
overlap <- function(x0=0, y0=0, r0, x1, y1=0, r1) {
#plot two circles and calculate the area of overlap
#doesn't work if one circle completely overlaps the other!
library("plotrix", lib.loc="~/R/win-library/3.2")
xmin = min(x0 - r0, x1 - r1)
xmax = max(x0 + r0, x1 + r1)
ymin = min(y0 - r0, y1 - r1)
ymax = max(y0 + r0, y1 + r1)
plot(c(x0,x1), c(y0,y1), xlim=c(xmin, xmax), ylim=c(ymin, ymax), asp=1)
draw.circle(x=x0, y=y0, radius=r0)
draw.circle(x=x1, y=y1, radius=r1)
d = sqrt((x1-x0)^2 + (y1-y0)^2) #distance between centroids
CBA = acos((r1^2 + d^2 - r0^2)/(2*r1*d))
CBD = 2 * CBA
CAB = acos((r0^2 + d^2 - r1^2)/(2*r0*d))
CAD = 2 * CAB
area = .5 * (r1^2 * (CBD - sin(CBD)) + r0^2 * (CAD - sin(CAD)))
return(area)
}
I want to write another function that includes the overlap function and takes 3 areas as input.
dist_between <- function(a_not_b, b_not_a, a_and_b) {
r0 <- sqrt((a_not_b + a_and_b)/pi)
r1 <- sqrt((b_not_a + a_and_b)/pi)
#minimize a_and_b - overlap(r0=r0, x1=?, r1=r1) by changing x1
return(x1)
}
I want to be able to enter something like dist_between(60, 30, 10) and have the function return the value 5.805.
I think the optim function would suit my needs but I'm not sure how to begin.
This is the line of code needed to approximate the solution for x1.
x1 <- optimize(function(x) abs(overlap(r0=r0, x1=x, r1=r1)-a_and_b), interval=c(0,r0+r1))

find inverse (x, y pos) point in circle

I have a fixed point (x1, y1) and a moving/rotating point (x2, y2), how do I find the tangent inverse point (x3, y3)
My circle radius is 40.
Assuming p1 and p2 are 2-vectors, the following will do it.
v12 = normalize(p2 - p1) // the unit vector from p1 to p2
p3 = p1 - 40 * v12 // 40 away from p1 in the direction opposite p2
The value of normalize(u) is simply u / sqrt(u.x * u.x + u.y * u.y).
achieved it this way, modified to be rotated to any angle
http://jsfiddle.net/christianpugliese/g2Lk9k12/1/
var dx = x2 - x1;
var dy = y2 - y1;
var radianAngle = Math.atan2(dy, dx);
var diameter = -80;
p3x = x1 + diameter * Math.cos(radianAngle);
p3y = y1 + diameters * Math.sin(radianAngle);

How to randomize points on a sphere surface evenly?

Im trying to make stars on the sky, but the stars distribution isnt even.
This is what i tried:
rx = rand(0.0f, PI*2.0f);
ry = rand(0.0f, PI);
x = sin(ry)*sin(rx)*range;
y = sin(ry)*cos(rx)*range;
z = cos(ry)*range;
Which results to:
img http://img716.imageshack.us/img716/3320/sphererandom.jpg
And:
rx = rand(-1.0f, 1.0f);
ry = rand(-1.0f, 1.0f);
rz = rand(-1.0f, 1.0f);
x = rx*range;
y = ry*range;
z = rz*range;
Which results to:
img2 http://img710.imageshack.us/img710/5152/squarerandom.jpg
(doesnt make a sphere, but opengl will not tell a difference, though).
As you can see, there is always some "corner" where are more points in average. How can i create random points on a sphere where the points will be distributed evenly?
you can do
z = rand(-1, 1)
rxy = sqrt(1 - z*z)
phi = rand(0, 2*PI)
x = rxy * cos(phi)
y = rxy * sin(phi)
Here rand(u,v) draws a uniform random from interal [u,v]
You don't need trigonometry if you can generate random gaussian variables, you can do (pseudocode)
x <- gauss()
y <- gauss()
z <- gauss()
norm <- sqrt(x^2 + y^2 + z^2)
result = (x / norm, y / norm, z / norm)
Or draw points inside the unit cube until one of them is inside the unit ball, then normalize:
double x, y, z;
do
{
x = rand(-1, 1);
y = rand(-1, 1);
z = rand(-1, 1);
} while (x * x + y * y + z * z > 1);
double norm = sqrt(x * x + y * y + z * z);
x / norm; y /= norm; z /= norm;
It looks like you can see that it's the cartesian coordinates that are creating the concentrations.
Here is an explanation of one right (and wrong) way to get a proper distribution.

Constraining the drawing of a line to 45 degree angles

I have the start point (x1,y1) and the desired length and angle of the line.
If the angles were directions, 0 degrees is W, 90 is N, 180 is E and 270 is S. I can modify this if needed.
How can I use the start point, length and angle to determine the end point(x2, y2)?
x2 = x1 + lengthcos(angle)
y2 = y1 + lengthsin(angle)
In this case angle is counter-clockwise increasing with 0 pointing towards positive x. The x axis is increasing to the right, and the y axis up.
For a screen:
For W = 0, N = 90, E = 180, S = 270:
x2 = x1 - length * cos(angle)
y2 = y1 - length * sin(angle)
For E = 0, N = 90, W = 180, S = 270:
x2 = x1 + length * cos(angle)
y2 = y1 - length * sin(angle)
Note that you need to make sure your implementation of cos works in degrees not radians otherwise you will get lines at strange angles.

Resources