Here’s the code for the specific scenario. It’ll run as is and has no dependencies.
-- create new vertices for a shape after it is rotated local function rotatePolygon(vertices,r) -- matrixRotate returns rotation matrix for angle theta local function matrixRotate(theta) local t = setmetatable({},mt) t[1] = {math.cos(theta),math.sin(theta)} t[2] = {-math.sin(theta),math.cos(theta)} return t end -- multiply two matrices and return the resulting matrix local function matrixMultiply( m1, m2 ) -- matrixMultiply source: https://github.com/davidm/lua-matrix/blob/master/lua/matrix.lua if #m1[1] ~= #m2 then return nil end local res = {} for i = 1, #m1 do res[i] = {} for j = 1, #m2[1] do res[i][j] = 0 for k = 1, #m2 do res[i][j] = res[i][j] + m1[i][k] \* m2[k][j] end end end return res end local matrix = {} -- turn the vertices table into a matrix for i = 1, #vertices\*0.5 do matrix[i] = {} matrix[i][1] = vertices[i\*2-1] matrix[i][2] = vertices[i\*2] end -- create a rotation matrix for the given rotation local matrixRotation = matrixRotate(math.rad(r)) -- multiply the vertices matrix with the rotation metrix local matrixFinal = matrixMultiply(matrix,matrixRotation) -- update the original vertices and turn the matrix back into a table for i = 1, #matrixFinal do vertices[i\*2-1] = matrixFinal[i][1] vertices[i\*2] = matrixFinal[i][2] end return vertices end -- doLinesIntersect source: https://gist.github.com/HoraceBury/9431861 local function doLinesIntersect( a, b, c, d ) -- parameter conversion local L1 = {X1=a.x,Y1=a.y,X2=b.x,Y2=b.y} local L2 = {X1=c.x,Y1=c.y,X2=d.x,Y2=d.y} -- Denominator for ua and ub are the same, so store this calculation local \_d = (L2.Y2 - L2.Y1) \* (L1.X2 - L1.X1) - (L2.X2 - L2.X1) \* (L1.Y2 - L1.Y1) -- Make sure there is not a division by zero - this also indicates that the lines are parallel. -- If n\_a and n\_b were both equal to zero the lines would be on top of each -- other (coincidental). This check is not done because it is not -- necessary for this implementation (the parallel check accounts for this). if (\_d == 0) then return false end -- n\_a and n\_b are calculated as seperate values for readability local n\_a = (L2.X2 - L2.X1) \* (L1.Y1 - L2.Y1) - (L2.Y2 - L2.Y1) \* (L1.X1 - L2.X1) local n\_b = (L1.X2 - L1.X1) \* (L1.Y1 - L2.Y1) - (L1.Y2 - L1.Y1) \* (L1.X1 - L2.X1) -- Calculate the intermediate fractional point that the lines potentially intersect. local ua = n\_a / \_d local ub = n\_b / \_d -- The fractional point will be between 0 and 1 inclusive if the lines -- intersect. If the fractional calculation is larger than 1 or smaller -- than 0 the lines would need to be longer to intersect. if (ua \>= 0 and ua \<= 1 and ub \>= 0 and ub \<= 1) then local x = L1.X1 + (ua \* (L1.X2 - L1.X1)) local y = L1.Y1 + (ua \* (L1.Y2 - L1.Y1)) return {x=x, y=y} end return false end local light = display.newCircle(0,0,4) light:setFillColor(1,1,0) light.brightness = 1 local shadow = display.newPolygon( 222, 186, {-86,-25,-65,-46,-8,-49,50,6,21,37,-41,102,-63,81,-21,38,-36,23,-64,39,-85,18,-64,-4} ) shadow:setFillColor(1,0,0,0.5) local vertices = {-40,-30,-20,-30,-20,10,0,10,0,-10,20,-10,20,10,40,10,40,30,-40,30} local object = display.newPolygon( 240, 160, vertices ) object.rotation = 224 -- light coordinates 1: five decimals, which ultimately lead to intersect light.x = 346.34442 light.y = 104.40447 -- light coordinates 2: four decimals, which no longer lead to intersect -- light.x = 346.3444 -- light.y = 104.4044 local rotatedVertices = rotatePolygon(vertices,object.rotation) local function newVertex(vX,vY) local shadowLength = math.sqrt((vX-light.x)^2+(vY-light.y)^2)\*(0.5\*light.brightness) local shadowAngle = math.deg(math.atan2(vY-light.y,vX-light.x)) local dx = math.sin(math.rad(shadowAngle-90))\*shadowLength local dy = math.cos(math.rad(shadowAngle-90))\*shadowLength vX = vX-dx vY = vY+dy return vX, vY end local vertex = {} vertex[#vertex+1] = {} vertex[#vertex].x, vertex[#vertex].y = newVertex(rotatedVertices[5]+object.x, rotatedVertices[6]+object.y) vertex[#vertex+1] = {} vertex[#vertex].x, vertex[#vertex].y = newVertex(rotatedVertices[7]+object.x, rotatedVertices[8]+object.y) vertex[#vertex+1] = {} vertex[#vertex].x, vertex[#vertex].y = newVertex(rotatedVertices[13]+object.x, rotatedVertices[14]+object.y) vertex[#vertex+1] = {} vertex[#vertex].x, vertex[#vertex].y = newVertex(rotatedVertices[15]+object.x, rotatedVertices[16]+object.y) local line12 = display.newLine(vertex[1].x,vertex[1].y,vertex[2].x,vertex[2].y) local line34 = display.newLine(vertex[3].x,vertex[3].y,vertex[4].x,vertex[4].y) local number = {} for k = 1, 4 do number[k] = display.newText( k, vertex[k].x,vertex[k].y, native.systemFont, 12 ) number[k]:setFillColor(1,1,0) end -- method 1: using the actual, non-rounded numbers --------------------------------------------------- local intersect = doLinesIntersect( vertex[1], vertex[2], vertex[3], vertex[4] ) -- method 2: print the values and use them directly --------------------------------------------------- -- print(vertex[1].x,vertex[1].y,vertex[2].x,vertex[2].y,vertex[3].x,vertex[3].y,vertex[4].x,vertex[4].y) -- vertex[1].x = 218.82785887369 -- vertex[1].y = 197.84741793315 -- vertex[2].x = 197.24766486353 -- vertex[2].y = 177.00766681938 -- vertex[3].x = 175.66747085337 -- vertex[3].y = 156.16791570561 -- vertex[4].x = 154.08727684321 -- vertex[4].y = 135.32816459184 -- method 3: use floored (or rounded) values --------------------------------------------------- -- for i = 1, 4 do -- vertex[i].x = math.floor(vertex[i].x) -- vertex[i].y = math.floor(vertex[i].y) -- end local intersect = doLinesIntersect( vertex[1], vertex[2], vertex[3], vertex[4] ) print("---") if intersect == false then print("The lines do not intersect.") else print("The lines intersect at x: "..intersect.x..", y: "..intersect.y) end local distance = math.sqrt((vertex[2].x-vertex[3].x)^2+(vertex[2].y-vertex[3].y)^2) print("The distance between vertex 2 and 3 is "..distance.."px.")
I replaced my own intersect function with Horace Bury’s that I found online just to ensure that his function returns the same results as mine, which it does.
I reiterate, the reason why I believe that this has to do with number precision in lua is because,
- if the light’s coordinates are given with four decimal points instead of five, then the intersect no longer occurs.
- if the four vertices are not altered, then the intersect occurs (as long as light uses 5 decimals), but
- if the four vertices are rounded, floored or printed out and inserted with 11 decimal point accuracy, then the intersect no longer occurs.
I am interested in why this kind behaviour of happening. This isn’t really a debugging issue.