You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
251 lines
7.7 KiB
251 lines
7.7 KiB
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<centerDist then
|
|
centerDist = squaredDist
|
|
centerIndex = k
|
|
end
|
|
end
|
|
if centerIndex then
|
|
return centerIndex,centers[centerIndex][1],centers[centerIndex][2]
|
|
end
|
|
|
|
end
|
|
|