local _, MDT = ... local L = MDT.L local db local twipe,tinsert,tremove,tgetn,CreateFrame = table.wipe,table.insert,table.remove,table.getn,CreateFrame -- return true if a is more lower-left than b local function is_lower_left(a, b) if a[1] < b[1] then return true end if a[1] > b[1] then return false end if a[2] < b[2] then return true end if a[2] > b[2] then return true end return false end -- return true if c is left of line a-b local function is_left_of(a, b, c) local u1 = b[1] - a[1] local v1 = b[2] - a[2] local u2 = c[1] - a[1] local v2 = c[2] - a[2] return u1 * v2 - v1 * u2 < 0 end local function convex_hull(pts) local lower_left = 1 for i = 2, #pts do if is_lower_left(pts[i], pts[lower_left]) then lower_left = i end end local hull = {} local final = 1 local tries = 0 repeat table.insert(hull, lower_left) final = 1 for j = 2, #pts do if lower_left == final or is_left_of(pts[lower_left], pts[final], pts[j]) then final = j end end lower_left = final tries = tries + 1 until final == hull[1] or tries>100 --deadlocked here otherwise?!? local hullpts = {} for _, index in ipairs(hull) do table.insert(hullpts, pts[index]) end return hullpts end local function cross(a,b) return a[1] * b[2] - a[2] * b[1] end local function area(points) local res = cross(points[#points], points[1]) for i = 1, #points-1 do res = res + cross(points[i], points[i+1]) end return math.abs(res)/2 end local function centroid(pts) local rx = 0 local ry = 0 local area = area(pts) for i = 1, #pts-1 do rx = rx + ((pts[i][1] + pts[i+1][1]) * ((pts[i][1] * pts[i+1][2]) - (pts[i+1][1] * pts[i][2]))) ry = ry + ((pts[i][2] + pts[i+1][2]) * ((pts[i][1] * pts[i+1][2]) - (pts[i+1][1] * pts[i][2]))) end rx = rx + ((pts[#pts][1] + pts[1][1]) * ((pts[#pts][1] * pts[1][2]) - (pts[1][1] * pts[#pts][2]))) ry = ry + ((pts[#pts][2] + pts[1][2]) * ((pts[#pts][1] * pts[1][2]) - (pts[1][1] * pts[#pts][2]))) rx = rx / (area * 6) ry = ry / (area * 6) return {rx, ry} end local function expand_polygon(poly, numCirclePoints) local res = {} local resIndex = 1 for i = 1, #poly do local x = poly[i][1] local y = poly[i][2] local r = poly[i][3]*10 local adjustedNumPoints = math.max(1,math.floor(numCirclePoints*poly[i][3])) for j = 1, adjustedNumPoints do local cx = x+r*math.cos(2*math.pi/adjustedNumPoints*j) local cy = y+r*math.sin(2*math.pi/adjustedNumPoints*j) res[resIndex] = {cx,cy,r} resIndex = resIndex + 1 end end return res end ---TexturePool local activeTextures = {} local texturePool = {} local function getTexture() local size = tgetn(texturePool) if size == 0 then return MDT.main_frame.mapPanelFrame:CreateTexture(nil, "OVERLAY") else local tex = texturePool[size] tremove(texturePool, size) tex:SetRotation(0) tex:SetTexCoord(0, 1, 0, 1) tex:ClearAllPoints() tex.coords = nil tex.points = nil return tex end end local function releaseTexture(tex) tex:Hide() tinsert(texturePool,tex) end ---ReleaseAllActiveTextures function MDT:ReleaseHullTextures() for k,tex in pairs(activeTextures) do releaseTexture(tex) end twipe(activeTextures) end function MDT:DrawHullCircle(x, y, size, color, layer, layerSublevel) local circle = getTexture() circle:SetDrawLayer(layer, layerSublevel) circle:SetTexture("Interface\\AddOns\\MythicDungeonTools\\Textures\\Circle_White") circle:SetVertexColor(color.r,color.g,color.b,color.a) circle:SetWidth(1.1*size) circle:SetHeight(1.1*size) circle:ClearAllPoints() circle:SetPoint("CENTER", MDT.main_frame.mapPanelTile1,"TOPLEFT",x,y) circle:Show() tinsert(activeTextures,circle) end function MDT:DrawHullLine(x, y, a, b, size, color, smooth, layer, layerSublevel, lineFactor) local line = getTexture() line:SetTexture("Interface\\AddOns\\MythicDungeonTools\\Textures\\Square_White") line:SetVertexColor(color.r,color.g,color.b,color.a) DrawLine(line, MDT.main_frame.mapPanelTile1, x, y, a, b, size, lineFactor and lineFactor or 1.1,"TOPLEFT") line:SetDrawLayer(layer, layerSublevel) line:Show() line.coords = {x,y,a,b} tinsert(activeTextures,line) if smooth == true then MDT:DrawHullCircle(x,y,size*0.9,color,layer,layerSublevel) end end function MDT:DrawHull(vertices,pullColor,pullIdx) --if true then return end local hull = convex_hull(vertices) if hull then hull = expand_polygon(hull,13) hull = convex_hull(hull) for i = 1, #hull do local a = hull[i] local b = hull[1] if i ~= #hull then b = hull[i+1] end --layerSublevel go from -8 to 7 --we rotate through the layerSublevel to avoid collisions MDT:DrawHullLine(a[1], a[2], b[1], b[2], 3*(MDT.scaleMultiplier[MDT:GetDB().currentDungeonIdx] or 1), pullColor, true, "ARTWORK", pullIdx%16-8, 1) end end end local function getPullVertices(p,blips) local vertices = {} for enemyIdx,clones in pairs(p) do if tonumber(enemyIdx) then for _,cloneIdx in pairs(clones) do if MDT:IsCloneIncluded(enemyIdx, cloneIdx) then for _,blip in pairs(blips) do if (blip.enemyIdx == enemyIdx) and (blip.cloneIdx == cloneIdx) then local endPoint, endRelativeTo, endRelativePoint, endX, endY = blip:GetPoint() table.insert(vertices, {endX, endY, blip.normalScale}) break end end end end end end return vertices end function MDT:DrawAllHulls(pulls) MDT:ReleaseHullTextures() local preset = MDT:GetCurrentPreset() local blips = MDT:GetDungeonEnemyBlips() local vertices pulls = pulls or preset.value.pulls for pullIdx,p in pairs(pulls) do local r,g,b = MDT:DungeonEnemies_GetPullColor(pullIdx,pulls) vertices = getPullVertices(p,blips) MDT:DrawHull(vertices,{r=r, g=g, b=b, a=1},pullIdx) end end function MDT:FindClosestPull(x,y) local preset = MDT:GetCurrentPreset() local blips = MDT:GetDungeonEnemyBlips() local vertices,hull,center local centers = {} --1. construct all hulls of pulls in this sublevel for pullIdx,p in pairs(preset.value.pulls) do vertices = getPullVertices(p,blips) hull = convex_hull(vertices) --2. get centroid of each pull if hull and hull[#hull] then if #hull>2 then center = centroid(hull) centers[pullIdx]=center elseif #hull==2 then local x1 = hull[1][1] local y1 = hull[1][2] local x2 = hull[2][1] local y2 = hull[2][2] centers[pullIdx] = {(x1+x2)/2,(y1+y2)/2} elseif #hull==1 then local x1 = hull[1][1] local y1 = hull[1][2] centers[pullIdx] = {x1,y1} end end end --3. find closest centroid local centerDist = math.huge local centerIndex for k,center in pairs(centers) do local squaredDist = (x-center[1])^2+(y-center[2])^2 if squaredDist