Tangent Line On A Circle

Hi I’m wondering if Corona has a built in function or way creating a tangent line connecting two circles.  I know how to do it with trigonometry.  Any ideas?

I tested my game on the iphone 4 today and it lagged horribly due to the excessive amounts of math.

Thanks

There’s not really any built in functions for handling complex maths, but there are the typical math.* library functions available. If you can post some of your code I’m sure it could be optimised to perform adequately. For example, it’s very rare that very complex calculations really need to be done in real time, they can usually be cached.

Basically when the user draws slowly the game runs fine however if the user starts drawing really fast the game comes to a stand still until all of the drawing lines are made.  Thanks

By the way it runs perfect in the simulator but not on the phone I tested it on iPhone 4 and iPhone 5.

[lua]

– General Setup: Variables and Tables ==============

local atan2 = math.atan2

local pi= math.pi

width = display.contentWidth

height = display.contentHeight

display.setStatusBar(display.HiddenStatusBar)

configDraw = {}

configDraw.type = “continuous”

configDraw.w = 15; configDraw.length = 50^2; configDraw.state = nil

drawTable = {}

cords = {}; cords.drawX = nil; cords.drawY = nil

–===================================================

function startDraw( draw )

    if draw.phase == “began” then

    configDraw.state = “inProgress”

    cords.drawX = draw.x

    cords.drawY = draw.y

    

    drawTable[#drawTable+1] = display.newCircle(draw.x,draw.y, configDraw.w/2)

    drawTable[#drawTable]:setFillColor(255,10,10)

    drawTable[#drawTable].x = draw.x

    drawTable[#drawTable].y = draw.y

    end

    – changes the coordinants of where the persons finger is at

    if draw.phase == “moved” and

    configDraw.state == “inProgress” then

    cords.drawX = draw.x

    cords.drawY = draw.y

    end

    

    

    if configDraw.type == “continuous” and

        draw.phase == “moved” and

        configDraw.state == “inProgress” and

        overload == nil and

        drawTable[1] ~= nil and

            (math.abs(drawTable[#drawTable].x-cords.drawX)^2 + – Makes sure the persons finer is

            math.abs(drawTable[#drawTable].y-cords.drawY)^2       – Farther away then the configDraw.length

                     ) > configDraw.length then

                    

        createDrawLines(draw)

        for a,b in pairs(drawTable) – tells me number of items in the table

        do print(a, B)

        end

    end

    

    

    if draw.phase == “ended”   and

    configDraw.state == “inProgress” then

        configDraw.state = nil

    display.remove(drawTable[#drawTable])

    table.remove(drawTable, #drawTable)

    end

    

    

end

    

function createDrawLines(draw)

    

    – creates a second circle that will be used properly align the rectangle between the first and the second.

    drawTable[#drawTable+1] = display.newCircle(cords.drawX,cords.drawY, configDraw.w)

    drawTable[#drawTable]:setFillColor(0,0,255)

    physics.addBody( drawTable[#drawTable], “kinematic”,{friction = 0, bounce = 0})

    midPointX = (drawTable[#drawTable-1].x+drawTable[#drawTable].x)/2

    midPointY = (drawTable[#drawTable-1].y+drawTable[#drawTable].y)/2

    length = 

        math.sqrt(

        math.abs(drawTable[#drawTable].x-drawTable[#drawTable-1].x)^2 + 

        math.abs(drawTable[#drawTable].y-drawTable[#drawTable-1].y)^2

                )

                + configDraw.w 

                

        deltaX = drawTable[#drawTable].x-drawTable[#drawTable-1].x – used for calculating angle

        deltaY = drawTable[#drawTable].y-drawTable[#drawTable-1].y  – used for calculating angle

    angle = math.atan2(deltaY,deltaX)*(180/math.pi) – radian angle converted to degrees using 180/pi

    --removes  old circle

    display.remove(drawTable[#drawTable-1])

    table.remove(drawTable, #drawTable-1)

    

    table.insert(drawTable, 1, display.newRoundedRect(999,999,length,configDraw.w,configDraw.w/2))

    drawTable[1].x = midPointX

    drawTable[1].y = midPointY

    drawTable[1].rotation = angle

    drawTable[1]:setFillColor(30,10,10)

    physics.addBody( drawTable[1], “static”,{friction = 0, bounce = 0})

    

end

screen = display.newRect(0,0,width,height)

screen.alpha = 0.5

screen:addEventListener(“touch”,startDraw)

-----===================================================================

physics = require( “physics” )

physics.setDrawMode( “hybrid” )

physics.start()

physics.setGravity(0,6)

gameBall = display.newCircle(320,50,16)

physics.addBody( gameBall, “dynamic”,{radius = 16, bounce = 0}) [/lua]

Just scanning through your code, I think you have some opportunities to optimize it and make it more efficient:

  • You reference drawTable[#drawTable] and drawTable[#drawTable-1] many times.  Each table access requires a Lua operation, so it would be more efficient to create a local reference to each of these at the top of the function, and use those local references within the function
  • table.insert is quite a slow operation.  I haven’t examined your logic close, but is there any reason you need to insert the new line to the first index of the table?  Instead, it would be more efficient to insert it at the end using drawTable[#drawTable+1] = display.newImage(…)
  • You can precalculate the value of 180/math.pi at the top of your module, so that you don’t have to do the division every time the function is called
  • You don’t need to call math.abs in startDraw, since you’re already squaring the values (which makes them positive)
  • Most importantly, you might want to insert some logic so that it doesn’t do the heavy lifting unless the new touch coordinate is sufficiently far away from the last touch coordinate.  It’ll waste a lot of processing time to do all of this calculation if the touch has only moved by a few pixels

Hope this helps.

  • Andrew

Thanks aukStudios for the excellent response.

1.) Is an excellent point I will get rid of as many drawTable[#drawTable] as I can.

2.)  The reason I put the new line at the beginning of the table is that way the circles are at the end and I know where they are at.  I didn’t realize this was such a slow operation I will get rid of the circles all together (instead store their loaction as variables) and insert the lines at the end.

3.)  Good point

4.) Good Point

5.)  This one I’m not fully understanding.  I have some logic so that a new line is not drawn unless it is sufficiently far enough away.  Lines 43 and 44.  It does have to check each time which is a decent amount of calculation though.

On #5, you’re probably right, I just wasn’t looking at your code closely enough then.

By the way, you might also want to try turning off the loop that prints the contents of drawTable.  Once drawTable gets large, print statements can be surprisingly taxing when run on a device and can cause a big slow down.

  • Andrew

So I went through and applied all of your suggestions.  I noticed very little improvement until I turned of the print statements which appears to have made a massive improvement.  I was actually able to get the simulator to lag with the print statements on. Haven’t tested on the iPhone yet but fingers crossed.  Thanks

There’s not really any built in functions for handling complex maths, but there are the typical math.* library functions available. If you can post some of your code I’m sure it could be optimised to perform adequately. For example, it’s very rare that very complex calculations really need to be done in real time, they can usually be cached.

Basically when the user draws slowly the game runs fine however if the user starts drawing really fast the game comes to a stand still until all of the drawing lines are made.  Thanks

By the way it runs perfect in the simulator but not on the phone I tested it on iPhone 4 and iPhone 5.

[lua]

– General Setup: Variables and Tables ==============

local atan2 = math.atan2

local pi= math.pi

width = display.contentWidth

height = display.contentHeight

display.setStatusBar(display.HiddenStatusBar)

configDraw = {}

configDraw.type = “continuous”

configDraw.w = 15; configDraw.length = 50^2; configDraw.state = nil

drawTable = {}

cords = {}; cords.drawX = nil; cords.drawY = nil

–===================================================

function startDraw( draw )

    if draw.phase == “began” then

    configDraw.state = “inProgress”

    cords.drawX = draw.x

    cords.drawY = draw.y

    

    drawTable[#drawTable+1] = display.newCircle(draw.x,draw.y, configDraw.w/2)

    drawTable[#drawTable]:setFillColor(255,10,10)

    drawTable[#drawTable].x = draw.x

    drawTable[#drawTable].y = draw.y

    end

    – changes the coordinants of where the persons finger is at

    if draw.phase == “moved” and

    configDraw.state == “inProgress” then

    cords.drawX = draw.x

    cords.drawY = draw.y

    end

    

    

    if configDraw.type == “continuous” and

        draw.phase == “moved” and

        configDraw.state == “inProgress” and

        overload == nil and

        drawTable[1] ~= nil and

            (math.abs(drawTable[#drawTable].x-cords.drawX)^2 + – Makes sure the persons finer is

            math.abs(drawTable[#drawTable].y-cords.drawY)^2       – Farther away then the configDraw.length

                     ) > configDraw.length then

                    

        createDrawLines(draw)

        for a,b in pairs(drawTable) – tells me number of items in the table

        do print(a, B)

        end

    end

    

    

    if draw.phase == “ended”   and

    configDraw.state == “inProgress” then

        configDraw.state = nil

    display.remove(drawTable[#drawTable])

    table.remove(drawTable, #drawTable)

    end

    

    

end

    

function createDrawLines(draw)

    

    – creates a second circle that will be used properly align the rectangle between the first and the second.

    drawTable[#drawTable+1] = display.newCircle(cords.drawX,cords.drawY, configDraw.w)

    drawTable[#drawTable]:setFillColor(0,0,255)

    physics.addBody( drawTable[#drawTable], “kinematic”,{friction = 0, bounce = 0})

    midPointX = (drawTable[#drawTable-1].x+drawTable[#drawTable].x)/2

    midPointY = (drawTable[#drawTable-1].y+drawTable[#drawTable].y)/2

    length = 

        math.sqrt(

        math.abs(drawTable[#drawTable].x-drawTable[#drawTable-1].x)^2 + 

        math.abs(drawTable[#drawTable].y-drawTable[#drawTable-1].y)^2

                )

                + configDraw.w 

                

        deltaX = drawTable[#drawTable].x-drawTable[#drawTable-1].x – used for calculating angle

        deltaY = drawTable[#drawTable].y-drawTable[#drawTable-1].y  – used for calculating angle

    angle = math.atan2(deltaY,deltaX)*(180/math.pi) – radian angle converted to degrees using 180/pi

    --removes  old circle

    display.remove(drawTable[#drawTable-1])

    table.remove(drawTable, #drawTable-1)

    

    table.insert(drawTable, 1, display.newRoundedRect(999,999,length,configDraw.w,configDraw.w/2))

    drawTable[1].x = midPointX

    drawTable[1].y = midPointY

    drawTable[1].rotation = angle

    drawTable[1]:setFillColor(30,10,10)

    physics.addBody( drawTable[1], “static”,{friction = 0, bounce = 0})

    

end

screen = display.newRect(0,0,width,height)

screen.alpha = 0.5

screen:addEventListener(“touch”,startDraw)

-----===================================================================

physics = require( “physics” )

physics.setDrawMode( “hybrid” )

physics.start()

physics.setGravity(0,6)

gameBall = display.newCircle(320,50,16)

physics.addBody( gameBall, “dynamic”,{radius = 16, bounce = 0}) [/lua]

Just scanning through your code, I think you have some opportunities to optimize it and make it more efficient:

  • You reference drawTable[#drawTable] and drawTable[#drawTable-1] many times.  Each table access requires a Lua operation, so it would be more efficient to create a local reference to each of these at the top of the function, and use those local references within the function
  • table.insert is quite a slow operation.  I haven’t examined your logic close, but is there any reason you need to insert the new line to the first index of the table?  Instead, it would be more efficient to insert it at the end using drawTable[#drawTable+1] = display.newImage(…)
  • You can precalculate the value of 180/math.pi at the top of your module, so that you don’t have to do the division every time the function is called
  • You don’t need to call math.abs in startDraw, since you’re already squaring the values (which makes them positive)
  • Most importantly, you might want to insert some logic so that it doesn’t do the heavy lifting unless the new touch coordinate is sufficiently far away from the last touch coordinate.  It’ll waste a lot of processing time to do all of this calculation if the touch has only moved by a few pixels

Hope this helps.

  • Andrew

Thanks aukStudios for the excellent response.

1.) Is an excellent point I will get rid of as many drawTable[#drawTable] as I can.

2.)  The reason I put the new line at the beginning of the table is that way the circles are at the end and I know where they are at.  I didn’t realize this was such a slow operation I will get rid of the circles all together (instead store their loaction as variables) and insert the lines at the end.

3.)  Good point

4.) Good Point

5.)  This one I’m not fully understanding.  I have some logic so that a new line is not drawn unless it is sufficiently far enough away.  Lines 43 and 44.  It does have to check each time which is a decent amount of calculation though.

On #5, you’re probably right, I just wasn’t looking at your code closely enough then.

By the way, you might also want to try turning off the loop that prints the contents of drawTable.  Once drawTable gets large, print statements can be surprisingly taxing when run on a device and can cause a big slow down.

  • Andrew

So I went through and applied all of your suggestions.  I noticed very little improvement until I turned of the print statements which appears to have made a massive improvement.  I was actually able to get the simulator to lag with the print statements on. Haven’t tested on the iPhone yet but fingers crossed.  Thanks