12

Below is an example image, if I have a point of the white dot in the middle and I want to find the nearest possible location for the blue circle (which is obviously at the location where I placed it) if all the red circles already exist. How can I find that location?

Performance for me is not a major concern for this application.

enter image description here

Robert Harvey
  • 198,589
  • 55
  • 464
  • 673
Botanic
  • 129
  • 4
  • in what format is the input data? – Ewan Jan 13 '17 at 16:07
  • 1
    what is the significance of the black circle? can you place the blue circle over it? – Ewan Jan 13 '17 at 16:08
  • are you limited to the resolution of the image? – Ewan Jan 13 '17 at 16:10
  • 1) input data is points for the circles with a radius value. 2)For the black circle it is just the middle circle so it was easier to see. 3)The resolution could be anything. – Botanic Jan 13 '17 at 16:17
  • 2
    So to be clear you want the location where you can place the blue circle such that it is the shortest possible distance from the white point without overlapping any of the other circles? – Robert Harvey Jan 13 '17 at 16:21
  • 3
    Related: [Circle Packing](https://en.wikipedia.org/wiki/Circle_packing) – Robert Harvey Jan 13 '17 at 16:32
  • 2
    Will all circles always touch some other circle in at least one place? – Robert Harvey Jan 13 '17 at 16:35
  • 3
    Related: http://stackoverflow.com/questions/10666116 and http://stackoverflow.com/questions/5509151. Also possibly relevant: http://stackoverflow.com/a/19375601 – Robert Harvey Jan 13 '17 at 17:10
  • Can you please answer Ewan question? Why [this image](http://imgur.com/a/1oyNr) is not a solution? – Mandrill Jan 13 '17 at 19:09
  • @mandrill: It is a solution for that image, but that's not the image that the OP posted. – Robert Harvey Jan 13 '17 at 19:10
  • That is correct the black was just for contrast for all intents it is a circle same as any other – Botanic Jan 13 '17 at 23:10
  • Also circle packing looks really close to what im looking for back to the research, thanks! Also they will always touch as it will always be the closest just by the nature of the problem. – Botanic Jan 13 '17 at 23:16
  • your edit with the orange area is incorrect. the circle if small enough could fit between the closer circles. and also it cant approach existing circles closer than its radius. – Ewan Jan 13 '17 at 23:26
  • also i think you misunderstand my answer. it only requires you brute force lines around each circle. not the whole area. imagine drawing a large circle around each red circle. that's the line of possible solutions – Ewan Jan 13 '17 at 23:28
  • yes you are correct i was wrong in my idea – Botanic Jan 13 '17 at 23:50

5 Answers5

4

This is not a general solution, since there are several situations were it will not provide the position of the blue circle with shortest distance to the white dot. For example, if you have 100 red balls grouped together and the white dot is far away from this group of red balls then none of the red balls will have any influence in the position of the blue circle that can just be centered on the white dot. Neither will it show all the calculations details. Anyway, for a subset of configurations, where the solution (blue circle) is tangent to two red circles the following should work:
1) let R be the radius of the blue circle
2) make a loop over all pair of red circles, yes I know this is O(n2).
3) for each pair of circles i,j with centers at (xi,yi) and (xj,yj) with respective radius ri and rj, compute the square of the distance between the pair of circles

d_ij^2=(xi-xj)^2+(yi-yj)^2  

4) put all pairs of circles that

dij^2<R^2

into a list.

5) traverse the list, finding the 2 solutions of circles of radius R tangent to both circles i and j. To do this use these equations together with this image two blue circle canditates for a pair of red circles

a = R+ri  
b = R+rj  
c = dij  
α = arccos((b^2+c^2-a^2)/(2bc)  

with above information you can find (X1ij,Y1ij) and (X2ij,Y2ij) the centers of the the 2 circles tangent to circles i and j. For each candidate blue circle loop over all other red circles and see if it don't overlap. If they do discart it if not check distance to white circle. If you keep the one with smaller distance I think you will have the solution when you finish traversing the list of pairs of circles. The algorithm seems like O(n3).

Mandrill
  • 517
  • 1
  • 3
  • 12
  • doesn't work when there is only one circle – Ewan Jan 13 '17 at 23:14
  • or two circles but with a target point outside both of them – Ewan Jan 13 '17 at 23:21
  • the problem is you cant be sure you have got all the edge cases – Ewan Jan 16 '17 at 11:00
  • also. there are unique solutions for those cases – Ewan Jan 16 '17 at 11:01
  • You need to write down all the assumptions under which the solution is correct or at least point out all the border cases. Some of them can be obvious, but some aren't. For example this won't work if it is possible to draw a line which separates the white dot from all of the red circles and the white dot is less than R away from the nearest circle. – Vlad Jan 16 '17 at 19:22
  • annoyed that this has got more upvotes than my answer even though it is demonstrably false #wisdomOfTheCrowd – Ewan Jan 18 '17 at 16:40
  • @Ewan: this answer is only incomplete, not plain false, since AFAICS it covers all situations where the optimal blue circle touches two red ones. The missing cases can be classified into the ones where the optimal blue circle touches exactly one red circle, or no circle at all. I think it is possible (and not really hard) to construct the potential solutions for those two categories, too, in an analytical manner. That might not be trivial, but IMHO not so hard as you and Vlad are pretending. – Doc Brown Jan 18 '17 at 21:37
  • it doesn't find the closest point. it doesn't even give an equation for the intersection point. and you have to prove those are the only other cases possible – Ewan Jan 18 '17 at 21:40
  • @Ewan: I don't have to prove anything, I am just pointing out what you (or Mandrill, or anyone who tries to use this approach) could do to complete this solution. – Doc Brown Jan 18 '17 at 21:49
  • what i mean is if you assemble a solution from parts like that you need some demonstration or proof that the parts cover all the cases. – Ewan Jan 18 '17 at 22:14
2

The closest placement to the point will either be on the point, or touching a circle.

therefore, first check the point, then roll the new circle around the edge of each existing circle, calculating the distance from the point and if you overlap as you go and keeping track of the minimum distance point. Stop when you have traversed every circle.

ie. check all points on the green lines, plus the white circle. where the green line is a circle with radius of the red plus the blue

possible center points

you need to check the whole of the green line, not just intersections so that you cover these edge cases.

single circle cases

Obviously the step size of your traversal is going to be important in terms of performance. But as you state performance is not an issue, choose the value corresponding to the resolution of your output value. ie float, long?

clarification:

my suggestion is to brute force all points around each circle testing for overlap with all other circles at each point. no cleverness.

If the example pic is indicative of the number of circles and resolution, it shouldnt be a problem for a standard pc

we have 20 circles of average radius 200 so thats approx 20 * 2 π * 200 points * 20 intersection tests = 4800000 iterations

Note:

Iterative approaches like this are flawed in that your step size, in this case the resolution of your output, can greatly affect the result.

Say i have two red circles 2 pixels apart and a 1 pixel radius blue circle to squeeze between them. Clearly with either of the two pixels as the center of the blue circle it will overlap one of the reds. but obviously there is room for the circle if the center lies between the two pixels.

Hence my comment asking about the resolution of the output. which you said could be anything.

you can also solve the simultaneous equation for each pair of circles with radius increase by the radius of the blue circle.

this will give you the points where the blue circle will touch both red circles more accurately than iterating.

However. there are several conditions where if you only do this you get the wrong or no answer. ie.

1 or no circles

2 or more circles but with target point far away and outside of them.

many circles but with target point close to the surface

Ewan
  • 70,664
  • 5
  • 76
  • 161
  • 2
    That he needs to roll the edge of the blue circle around the outside of the other circles is the easy part to figure out. The hard part is figuring out the equations/calculations to do it. – Robert Harvey Jan 13 '17 at 17:06
  • 1
    really? its just (x-x1)^2 + (y-y1)^2 = (r + r1)^2 – Ewan Jan 13 '17 at 17:54
  • It would be an algebraic equation that could be graphed as a semicircle in either direction – maple_shaft Jan 13 '17 at 17:55
  • the real problem is this this iterative method fails if you have a place where the circle exactly fits but the coordinate is an irrational number – Ewan Jan 13 '17 at 17:58
  • but the op says in the comment the res can be anything, so i assume he has an infinite tape turning machine or slightly squishy circles – Ewan Jan 13 '17 at 18:00
  • I see you haven't thought this out. Which circles are you going to apply that equation to? All of them? For every pixel in the diagram, or just neighboring ones? Are you going to spiral out until you find the closest circle, move one pixel in some direction and try again? Or is your algorithm going to be a bit smarter than that? Clearly it's going to take more than just calculating the distance between two circles. – Robert Harvey Jan 13 '17 at 18:01
  • i have thought it out, plz reread. my suggestion is to brute force all points around each circle testing for overlap with all other circles at each point. no cleverness, but if the example pic is indicative of the number of circles and resolution, it shouldnt be a problem for a standard pc – Ewan Jan 13 '17 at 18:05
  • 2
    And then you have to do all that again when you try the next point over. I know the OP said that performance was not a concern, but it does have to complete before the heat death of the universe. – Robert Harvey Jan 13 '17 at 18:06
  • its essentially the same calc any game physics engine does per frame – Ewan Jan 13 '17 at 18:15
  • You should include a brief description of that calc in your answer. – Robert Harvey Jan 13 '17 at 18:16
  • if i get ten upvotes ill post working c# code – Ewan Jan 13 '17 at 18:17
  • 2
    The only way to know whether or not you'll get ten upvotes is to post your C# code and see what happens. – Robert Harvey Jan 13 '17 at 18:18
  • 2
    what i think will happen is the OP will code this up as his homework answer and we will never hear from him again – Ewan Jan 13 '17 at 18:20
  • This is one of those questions where, unless you want to go rigorously through the math and algorithms involved, code is the best way to convey your message. Frankly, working code is the most valuable thing you could provide to the community, not just to the OP. – Robert Harvey Jan 13 '17 at 19:04
  • @RobertHarvey We are not a coding site. A good answer will discuss the algorithm and touch on the math involved but not implement it. Good call though on the heat death of the universe. There are infinite decimal representations of coordinates in any given circle. Collisions have to be approximated with circles. – maple_shaft Jan 13 '17 at 19:22
  • @robert i agree, but ultimately no one is paying me to write it – Ewan Jan 13 '17 at 19:29
  • @maple you have to make some assumptions about the question. my answer works fine for drawing circles on bitmaps. I cant imagine the OP was expecting a PhD thesis – Ewan Jan 13 '17 at 19:31
  • @maple_shaft: Are you seriously advocating the position that we can't write code to answer a question here? – Robert Harvey Jan 13 '17 at 19:32
  • @Ewan: Does the solution require a PhD thesis to answer properly? – Robert Harvey Jan 13 '17 at 19:32
  • I think to *prove* your answer always finds the closet possible position would be very hard indeed even if you could formulate a solution. I mean I just use 'common sense' to justify the blue circle must touch a red – Ewan Jan 13 '17 at 19:38
  • i have been thinking, you could improve the search by assuming that under most conditions the blue is going to touch two reds. – Ewan Jan 13 '17 at 19:40
  • @Ewan: That's why the answer needs to be code. The code is the proof. – Robert Harvey Jan 13 '17 at 21:56
  • @RobertHarvey I am advocating that a proper answer need not display a proof or code. That is not saying that code is not welcome here. It might be helpful to communicate an idea but the amswer should not be code. – maple_shaft Jan 13 '17 at 22:44
  • Obviously code defiantly helps see how things work in order but cant expect someone to do all your work for you for free. I just appreciate any help I get at this point ^.^ – Botanic Jan 13 '17 at 23:12
  • @maple the best answer would be an algorithm with rigourous mathematical proof. next best brute force all possible answers. I think my premise that blue circle must touch a red (or be on the target exactly) is provable by simple deduction and guarantees a solution of known accuracy – Ewan Jan 13 '17 at 23:45
  • I don't think the problem is a brute force one. If you can find a way to compute the path that **the center of the blue circle** must traverse around the overall shape, you only have to check those points that lie along that path. – Robert Harvey Jan 14 '17 at 00:38
  • yes, but its a n body problem. the solution is not simple and an iterative approach is acceptable – Ewan Jan 14 '17 at 11:19
  • 1
    When I got you right (which is not easy, since you start talking about "the point" without ever saying what that means), this is a solution trying to make a discrete approximation, assuming a fixed raster image resolution and circle positions or angle in discrete steps. IMHO that is not what the OP is after, he is probably looking for a continuous approach, with circle coordinates and radii given (and expected) in arbitrary float or double values. – Doc Brown Jan 16 '17 at 10:18
  • possibly you are correct, it is not made clear – Ewan Jan 16 '17 at 11:20
1

This plunk contains working code,

Concept

Given circles are C1, C2 .... Cn

and coordinates of circle Cn is Cnx,Cny and radius is Cr

and radius of required circle is R

if the blue circle is in X,Y location and if it does not conflict with any other circles, following equations are true

(C1x - X)^2 + (C1y - Y)^2 > (C1r + R)^2
(C2x - X)^2 + (C2y - Y)^2 > (C2r + R)^2
....
(Cnx - X)^2 + (Cny - Y)^2 > (Cnr + R)^2

changing first equation,

C1x^2 - 2C1x*X + X^2 + C1y^2 - 2C1y*Y + Y^2 > C1r^2 + 2C1r*R + R^2
X^2 + Y^2 - 2C1x*X - 2C1y*Y > C1r^2 + 2C1r*R + R^2 - C1x^2 - C1y^2

so equations can re-write as,

X^2 + Y^2 - 2C1x*X - 2C1y*Y > C1r^2 + 2C1r*R + R^2 - C1x^2 - C1y^2
X^2 + Y^2 - 2C2x*X - 2C2y*Y > C2r^2 + 2C2r*R + R^2 - C2x^2 - C2y^2
....
X^2 + Y^2 - 2Cnx*X - 2Cny*Y > Cnr^2 + 2Cnr*R + R^2 - Cnx^2 - Cny^2

Implementation

start from the coordinate of the white dot (Xw, Yw),

    var isValidLocation = function(x,y,r){
       var valid = true;
       for (var i = 0; i< circles.length; i++){
          var circle = circles[i];
          valid = valid && ((x*x + y*y - 2*circle.x*x - 2*circle.y*y) > (circle.radius*circle.radius + 2*circle.radius*r + r*r - circle.x*circle.x - circle.y*circle.y));
       }
       return valid;
      };

      var find = function(Xw,Yw,Rw){
        var radius = 0;
        while(true){
          for (var x=-1 * radius ;x <= radius; x++) {
            for (var y=-1 * radius;y <= radius; y++) {
               if (isValidLocation(Xw + x,Yw + y, Rw)){
                 drawCircle(Xw + x,Yw + y,Rw,"#0000FF");
                 return;
               }
            }   
          } 
          radius++;
        }
     }; 

the first coordinate found to satisfy all equations is the location of blue circle

Low Flying Pelican
  • 1,602
  • 9
  • 13
  • Can someone please explain what's wrong with this approach? – Low Flying Pelican Jan 17 '17 at 19:57
  • That it's hard to read. Use some good names and abstractions. Would it kill you to add a diagram? – candied_orange Jan 18 '17 at 04:46
  • As far as I can see, this approach tries to find only valid placements for the blue circle, but not the nearest possible location. This could be fixed, however, the approach also makes the (most probably invalid) assumption there are only a finite number of integer values coordinates. – Doc Brown Jan 18 '17 at 07:34
  • It starts from the coordinate of the white dot, and go around it expanding the search grid. Because of that it will not face any situation where it has infinite number of coordinates.. Eventually it'll find matching coordinate. – Low Flying Pelican Jan 18 '17 at 08:50
  • The search grid expansion is not done in a way it increases search radius correctly, so your algorithm would be wrong even if your restriction to *integer* values is what the OP is meant (which I doubt). – Doc Brown Jan 18 '17 at 09:28
  • Can you please point out where it's wrong? – Low Flying Pelican Jan 18 '17 at 12:18
  • Well, lets assume for a moment *integer* coordinates is what the OP wants (which I doubt, so I am pretty sure the whole approach is doomed), then your search space would still be a sequence of rectangular shapes where, for example, for a fixed width 2*i you increase the height 2*j until the shape is big enough to contain a valid solution. If MAX_Y is big enough, this will be always the case even if i=0, so this always delivers a solution with x=0 and a large y. However, if the nearest solution has x!=0, this is obviously wrong. – Doc Brown Jan 18 '17 at 13:31
  • 1
    ... for a correct solution in integer coordinates, you need to use an increasing radius, and make your search space a circle of this radius around the white point. And though the OP wrote efficiency is not his concern, it would be nevertheless a good idea not to test every already tested coordinate pair in every loop again and again. – Doc Brown Jan 18 '17 at 13:39
  • (And a hint: [use the @ sign](http://meta.stackexchange.com/questions/43019/how-do-comment-replies-work), otherwise I don't get a notification about a reply.) – Doc Brown Jan 18 '17 at 13:54
  • I like this approach, although it is slightly less efficient than my answer, at least you test *all* possible points and make no assumptions which might be false. However! this is assuming : 1) you add a test for nearest valid point as well as just valid point. 2) the OP is looking for the integer point on a bitmap. 3) i think you have some bugs in that loop – Ewan Jan 18 '17 at 16:39
  • @DocBrown I have updated the answer, and added a working plunk, although there were some minor issue to be ironed out, it works fine – Low Flying Pelican Jan 18 '17 at 23:57
0
  • O being the point that you are trying to be close to

  • P being the point that you are looking for (the center of the blue circle

  • r being the radius of the blue circle

  • C0 .. Cn being the centers of all the circles that restrict placement of the blue on

  • extended circle is one of The circles with it radius extended by r

    There is some extra work if O is not at a circle center. So right now assume O == C0

Calculate all the intersections of all the circles with C0, by using their respective radii plus the r, I.e intersect the extend circles with the extended C0. If there are no intersections then the point you are looking for is anywhere on C0, if there are intersections, for each intersection check if it is inside another extended circle (you can limit yourself to the circles that had intersections with C0). Take the first intersection that is not in another extended circle as P, there might be others.

If there are no intersections between the extended circles and C0 that are not inside another extended circle, calculate the intersections of all extended circles with each other. Then check these intersections in order of distance to O, again wether any of the intersections lies within another extended circle, if yes discard, if no that is your result.

If you envision this imagine drawing a line around all the circles that indicate a possible location for your blue circle, taking the union of all of the extended circles will indicate the area your blue circle can't be. The point that you are looking for is the closest point that is not in that union. If there is any point on C0 that is not in that union that is the solution, if C0 is fully covered then P has to be on an intersection between two other extended circles, and it has to be in an area that is not covered by this union (I.e not in an extended circle).

This is O(n^2), there are some ways to improve this though, a gridcan be used to reduce the effort of the pair wise search, also I think sorting the circles by their closeness to O, (the distance between the two circles reduce by the radio) would help to limit the search space for the coverage and intersection search

0

Possible solutions lookup

  1. Check if the white point is the solution by itself. It covers case with 0 red circles and trivial case when red circles are far away from the white point.
  2. One red circle.
    1. The white point is the center of the circle. Possible solutions are infinite number of points on the circle with its center in the white point and radius being sum of the blue circles radius and the red circle diameter. Let's call it the green circle.
    2. White point is somewhere else. There is only one possible solution on the line which connects the white point and center of the red circle, it is radius of the blue circle away from the point where the red circle crosses the line towards white point.
  3. Two or more red circles.
    1. Let's take red circles one by one and look for possible solution for each of them individually according to point 2 (one circle).
    2. For each pair of the red circles let's check if you can draw the blue circle touching both of the red ones. I.e. if distance between their centers is equal or less than sum of their radiuses plus diameter of the blue circle. If you can then you have two (or one if the red circles are exactly one blue circle diameter away) possible solutions.

Actual solution lookup among possible solutions

Now you have a set of points which are possible solutions, iterate through them and check for each.

  1. If the point is actually a solution. No red circle should have its center closer than its radius to this point.
  2. If it is closer to the white point than solution found before.
  3. If you have the green circle (point 2.1)
    • If among individual points there is no solution which belongs to the green circle then the green circle is the answer.
    • If you have individual solutions on the green circle and you need just any solution then just take one of those.
    • If you have individual solutions on the green circle and you need all of the unlimited number of solutions then you need to solve another problem. You need to cut from the green circle all the arcs defined by pair of individual solutions from each red circle.

NB: I'm not saying that implementation of the algorithm should be exactly is described. You can try to improve performance using dynamic programming or skipping possible solutions where it is obvious that they won't work.

Vlad
  • 559
  • 1
  • 3
  • 6