Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

determine circle center based on two points (radius known) with solve/optim

I have a pair of points and I would like to find a circles of known r that are determined by these two points. I will be using this in a simulation and possible space for x and y have boundaries (say a box of -200, 200).

It is known that square of radius is

(x-x1)^2 + (y-y1)^2 = r^2
(x-x2)^2 + (y-y2)^2 = r^2

I would now like to solve this non-linear system of equations to get two potential circle centers. I tried using package BB. Here is my feeble attempt which gives only one point. What I would like to get is both possible points. Any pointers into right direction will be met with complimentary beer on first possible occasion.

library(BB)
known.pair <- structure(c(-46.9531139599816, -62.1874917150412, 25.9011462171242, 
16.7441676243879), .Dim = c(2L, 2L), .Dimnames = list(NULL, c("x", 
"y")))

getPoints <- function(ps, r, tr) {
    # get parameters
     x <- ps[1]
     y <- ps[2]

     # known coordinates of two points
     x1 <- tr[1, 1]
     y1 <- tr[1, 2]
     x2 <- tr[2, 1]
     y2 <- tr[2, 2]

     out <- rep(NA, 2)
     out[1] <- (x-x1)^2 + (y-y1)^2 - r^2
     out[2] <- (x-x2)^2 + (y-y2)^2 - r^2
     out
}

slvd <- BBsolve(par = c(0, 0),
                fn = getPoints,
                method = "L-BFGS-B",
                tr = known.pair,
                r = 40
                )

Graphically you can see this with the following code, but you will need some extra packages.

library(sp)
library(rgeos)
plot(0,0, xlim = c(-200, 200), ylim = c(-200, 200), type = "n", asp = 1)
points(known.pair)
found.pt <- SpatialPoints(matrix(slvd$par, nrow = 1))
plot(gBuffer(found.pt, width = 40), add = T)

enter image description here

ADDENDUM

Thank you all for your valuable comments and code. I provide timings for answers by posters who complimented their answers with code.

    test replications elapsed relative user.self sys.self user.child sys.child
4   alex          100    0.00       NA      0.00        0         NA        NA
2  dason          100    0.01       NA      0.02        0         NA        NA
3   josh          100    0.01       NA      0.02        0         NA        NA
1 roland          100    0.15       NA      0.14        0         NA        NA
like image 311
Roman Luštrik Avatar asked Sep 04 '12 13:09

Roman Luštrik


People also ask

How do you find center with radius and point?

In order to find the center and radius, we need to change the equation of the circle into standard form, ( x − h ) 2 + ( y − k ) 2 = r 2 (x-h)^2+(y-k)^2=r^2 (x−h)2​+(y−k)2​=r2​, where h and k are the coordinates of the center and r is the radius.


3 Answers

The following code will get you the points at the centers of the two desired circles. No time right now to comment this up or convert the results to Spatial* objects, but this should give you a good start.

First, here's an ASCII-art diagram to introduce point names. k and K are the known points, B is a point on the horizontal drawn through k, and C1 and C2 are the centers of the circles you are after:

        C2





                            K


                  k----------------------B






                                       C1

Now the code:

# Example inputs
r <- 40
known.pair <- structure(c(-46.9531139599816, -62.1874917150412, 
25.9011462171242, 16.7441676243879), .Dim = c(2L, 2L), 
.Dimnames = list(NULL, c("x", "y")))

## Distance and angle (/_KkB) between the two known points
d1 <- sqrt(sum(diff(known.pair)^2))
theta1 <- atan(do.call("/", as.list(rev(diff(known.pair)))))

## Calculate magnitude of /_KkC1 and /_KkC2
theta2 <- acos((d1/2)/r)

## Find center of one circle (using /_BkC1)
dx1 <- cos(theta1 + theta2)*r
dy1 <- sin(theta1 + theta2)*r
p1 <- known.pair[2,] + c(dx1, dy1)

## Find center of other circle (using /_BkC2)
dx2 <- cos(theta1 - theta2)*r
dy2 <- sin(theta1 - theta2)*r
p2 <- known.pair[2,] + c(dx2, dy2)

## Showing that it worked
library(sp)
library(rgeos)
plot(0,0, xlim = c(-200, 200), ylim = c(-200, 200), type = "n", asp = 1)
points(known.pair)
found.pt <- SpatialPoints(matrix(slvd$par, nrow = 1))
points(p1[1], p1[2], col="blue", pch=16)
points(p2[1], p2[2], col="green", pch=16)

enter image description here

like image 167
Josh O'Brien Avatar answered Sep 22 '22 14:09

Josh O'Brien


This is the basic geometric way of going about solving it that everybody else is mentioning. I use polyroot to get the roots of the resulting quadratic equation but you could easily just use the quadratic equation directly.

# x is a vector containing the two x coordinates
# y is a vector containing the two y coordinates
# R is a scalar for the desired radius
findCenter <- function(x, y, R){
    dy <- diff(y)
    dx <- diff(x)
    # The radius needs to be at least as large as half the distance
    # between the two points of interest
    minrad <- (1/2)*sqrt(dx^2 + dy^2)
    if(R < minrad){
        stop("Specified radius can't be achieved with this data")
    }

    # I used a parametric equation to create the line going through
    # the mean of the two points that is perpendicular to the line
    # connecting the two points
    # 
    # f(k) = ((x1+x2)/2, (y1+y2)/2) + k*(y2-y1, x1-x2)
    # That is the vector equation for our line.  Then we can
    # for any given value of k calculate the radius of the circle
    # since we have the center and a value for a point on the
    # edge of the circle.  Squaring the radius, subtracting R^2,
    # and equating to 0 gives us the value of t to get a circle
    # with the desired radius.  The following are the coefficients
    # we get from doing that
    A <- (dy^2 + dx^2)
    B <- 0
    C <- (1/4)*(dx^2 + dy^2) - R^2

    # We could just solve the quadratic equation but eh... polyroot is good enough
    k <- as.numeric(polyroot(c(C, B, A)))

    # Now we just plug our solution in to get the centers
    # of the circles that meet our specifications
    mn <- c(mean(x), mean(y))
    ans <- rbind(mn + k[1]*c(dy, -dx),
                 mn + k[2]*c(dy, -dx))

    colnames(ans) = c("x", "y")

    ans
}

findCenter(c(-2, 0), c(1, 1), 3)
like image 35
Dason Avatar answered Sep 20 '22 14:09

Dason


Following @PhilH's solution, just using trigonometry in R:

radius=40

Draw the original points on the radius

plot(known.pair,xlim=100*c(-1,1),ylim=100*c(-1,1),asp=1,pch=c("a","b"),cex=0.8)

Find the midpoint c of ab (which is also the midpoint of de the two circle centers)

AB.bisect=known.pair[2,,drop=F]/2+known.pair[1,,drop=F]/2
C=AB.bisect
points(AB.bisect,pch="c",cex=0.5)

Find the length and angle of the chord ab

AB.vector=known.pair[2,,drop=F]-known.pair[1,,drop=F]
AB.len=sqrt(sum(AB.vector^2))
AB.angle=atan2(AB.vector[2],AB.vector[1])
names(AB.angle)<-NULL

Calculate the length and angle of the line from c to the centers of the two circles

CD.len=sqrt(diff(c(AB.len/2,radius)^2))
CD.angle=AB.angle-pi/2

Calculate and plot the position of the two centers d and e from the perpendicular to ab and the length:

center1=C+CD.len*c(x=cos(CD.angle),y=sin(CD.angle))
center2=C-CD.len*c(x=cos(CD.angle),y=sin(CD.angle))
points(center1[1],center1[2],col="blue",cex=0.8,pch="d")
points(center2[1],center2[2],col="blue",cex=0.8,pch="e")

Shows:

enter image description here

like image 39
Alex Brown Avatar answered Sep 20 '22 14:09

Alex Brown