0

I am trying to implement a mathematical procedure to ensure that a circle c1 is completely inside another circle c2.

It should work the following way:

Given c1(x, y, r) and c2(x, y, r) and c2.r>c1.r

  • return true if c1 is inside c2
  • return a vector V(x,y) being the minimum correction to apply to c1 so it is inside c2.

How does it look to you? should be easy for a mathematician or a physicist but it's quite hard for me.

I already tried an implementation in lua, but there's definitely something wrong on it.

local function newVector(P1, P2)
    local w, h=(P2.x-P1.x), (P2.y-P1.y)
    local M=math.sqrt(w^2 + h^2)
    local alpha=math.atan(h/w)
    return {m=M, alpha=alpha}
end

local function isWithin(C1, C2)
    local V12=newVector(C1, C2)
    local R12=C2.r-C1.r
    local deltaR=R12-V12.m
    if deltaR>=0 then
        return true
    else
        local correctionM=(V12.m+deltaR)    --module value to correct
        local a=V12.alpha
        print("correction angle: "..math.deg(a))
        local correctionX=correctionM*math.cos(a)
        local correctionY=correctionM*math.sin(a)
        return {x=correctionX, y=correctionY}
    end
end

Thanks!

nest
  • 1,385
  • 1
  • 15
  • 34
  • 1
    You should probably use `math.atan2`. – lhf Jul 30 '13 at 16:26
  • What kind of correction do you mean? Translation of center? Scale of radius? Both? – lhf Jul 30 '13 at 16:57
  • I mean Translation of circle 1, so that adding the returned vector V(x,y) to C1 makes C1 be inside C2. For instance if C1 was outside C2 for 2px right and 1px down, return value should be {x=-2, y=-1} – nest Jul 30 '13 at 21:15
  • No wonder you are getting confused. `R12` is actually "semantically" `deltaR` (and pretty much useless as a variable), `deltaR` is semantically `correctionM` and `correctionM` is actually semantically `deltaR` again. There are of course following this mathematical errors. It usually helps to make a sketch of what you are trying to achieve. – dualed Jul 30 '13 at 22:30

2 Answers2

1

Isn't it enough to check that distance(Center1, Center2) + Radius1 <= Radius2 ?

local function isWithin(C1, C2)
  local distance = math.sqrt((C1.x-C2.x)^2+(C1.y-C2.y)^2)
  return distance + C1.r <= C2.r + Epsilon

Epsilon is used in order to avoid numerical errors. (e.g. Epsilon = 1e-9)

Sounds easy this way.

David
  • 1,138
  • 5
  • 15
  • 1
    What is `Epsilon` for? – lhf Jul 30 '13 at 16:56
  • @David Yes, that should be enough. Circles are a very simple (mathematical) shape after all. However the correction vector is a little bit more complex. Not too much though – dualed Jul 30 '13 at 21:18
  • That returns true or false. If false I need the retuned value to be a vector(x, y) that applied to C1, makes C1 be inside C2. This is what makes it a bit more complex and requires to know the direction C1C2 – nest Jul 30 '13 at 21:20
  • 1e-9 means 1*10^-9 or math.exp(-9)? – nest Jul 30 '13 at 21:43
0

Ok, finally I have it working fine.

The key was to use math.atan2 as lhf suggested. And I had some numerical mistake in the correction value.

Here's the final code. I have also included the circleFromBounds function that I use to create the circles from any corona display object.

local function newVector(P1, P2)
    local w, h=(P2.x-P1.x), (P2.y-P1.y)
    local M=math.sqrt(w^2 + h^2)
    local alpha=math.atan2(h, w)
    return {m=M, alpha=alpha}
end

local function isWithin(C1, C2)
    local V12=newVector(C1, C2)
    local epsilon = 10^(-9)
    if (V12.m + C1.r <= C2.r + epsilon) then
        return true
    else
        local correctionM=(C2.r-(C1.r+V12.m))   --module value to correct
        local A=V12.alpha
        local correctionX=correctionM*math.cos(A)
        local correctionY=correctionM*math.sin(A)
        return {x=correctionX, y=correctionY}
    end
end

local function circleFromBounds(bounds, type)   
    local x, y, r
    local width, height = (bounds.xMax-bounds.xMin), (bounds.yMax-bounds.yMin)
    local ratio=width/height

    x=bounds.xMin+width*.5
    y=bounds.yMin+height*.5

    if "inner"==type then
        if ratio>1 then
            r=height*.5
        else
            r=width*.5
        end
    elseif "outer"==type then
        local c1, c2 = width*.5, height*.5
        r = math.sqrt(c1^2 + c2^2)
    end

    return {x=x, y=y, r=r}
end

Thanks for your help!

nest
  • 1,385
  • 1
  • 15
  • 34