
local GetTime = QuestHelper_GetTime

QuestHelper_File["dodads_triangles.lua"] = "4.0.1.$svnversion$"
QuestHelper_Loadtime["dodads_triangles.lua"] = GetTime()

-- I'm really curious what people might make out of this file. I'm not actually open-sourcing it yet, but let's say that if you *were* to come up with a neat idea, and wanted to use this code, I would almost certainly be willing to let you use it. Contact me as ZorbaTHut on EFNet/Freenode/Synirc, or zorba-qh-triangles@pavlovian.net email, or ZorbaTHut on AIM.

local function print()
end

function matrix_create()
  return {1, 0, 0, 0, 1, 0, 0, 0, 1}
end

function matrix_rescale(matrix, x, y)
  matrix[1], matrix[4] = matrix[1] * x, matrix[4] * x
  matrix[2], matrix[5] = matrix[2] * y, matrix[5] * y
end
function matrix_mult(matrix, a, b, c, d, e, f)  -- this is probably buggy
  matrix[1], matrix[2], matrix[3], matrix[4], matrix[5], matrix[6], matrix[7], matrix[8], matrix[9] =
    matrix[1] * a + matrix[4] * b + matrix[7] * c, matrix[2] * a + matrix[5] * b + matrix[8] * c, matrix[3] * a + matrix[6] * b + matrix[9] * c,
    matrix[1] * d + matrix[4] * e + matrix[7] * f, matrix[2] * d + matrix[5] * e + matrix[8] * f, matrix[3] * d + matrix[6] * e + matrix[9] * f,
    matrix[7], matrix[8], matrix[9]
end
function matrix_rotate(matrix, angle)
  matrix_mult(matrix, cos(angle), -sin(angle), 0, sin(angle), cos(angle), 0)
end
function matrix_print(matrix)
  print(string.format("\n%f %f %f\n%f %f %f\n%f %f %f", unpack(matrix)))
end

local function dist(sx, sy, ex, ey)
  local dx = sx - ex
  local dy = sy - ey
  dx, dy = dx * dx, dy * dy
  return math.sqrt(dx + dy)
end

local function testrange(...)
  for k = 1, select("#", ...) do
    if not (select(k, ...) > -60000 and select(k, ...) < 60000) then
      return true
    end
  end
end
-- thoughts about the transformation
-- start with a right triangle, define the top as the base (find a base)
-- rescale Y to get the right height
-- skew X to get the right bottom X position
-- now we have the right shape
-- rotate, rescale, translate?

-- for now, we define a-b as the base, which means c is the peak

local spots = {}
for k = 1, 3 do
  local minbutton = CreateFrame("Button", nil, UIParent)
  minbutton:SetWidth(50)
  minbutton:SetHeight(50)
  
  local minbutton_tex = minbutton:CreateTexture()
  minbutton_tex:SetAllPoints()
  minbutton_tex:SetTexture(1, 0, 0, 0.5)

  minbutton.Moove = function(self, x, y)
    minbutton:ClearAllPoints()
    minbutton:SetPoint("CENTER", UIParent, "TOPLEFT", x, -y)
  end
  table.insert(spots, minbutton)
end

local function MakeTriangle(frame)
  tex = frame:CreateTexture()
  tex:SetTexture("Interface\\AddOns\\QuestHelper\\triangle")
  
  tex.parent_frame = frame
  -- relative to 0,1 coordinates relative to parent
  tex.SetTriangle = function(self, ax, ay, bx, by, cx, cy)
    -- do we need to reverse the triangle?
    if ax * by - bx * ay + bx * cy - cx * by + cx * ay - cy * ax < 0 then
      ax, bx = bx, ax
      ay, by = by, ay
    end
    
    print(ax, ay, bx, by, cx, cy)
    ax, bx, cx = ax * frame:GetWidth(), bx * frame:GetWidth(), cx * frame:GetWidth()
    ay, by, cy = ay * frame:GetHeight(), by * frame:GetHeight(), cy * frame:GetHeight()
    print(ax, ay, bx, by, cx, cy)
    self:ClearAllPoints()
    
    local sx = math.min(ax, bx, cx)
    local sy = math.min(ay, by, cy)
    local ex = math.max(ax, bx, cx)
    local ey = math.max(ay, by, cy)
    
    local disty = math.max(ex - sx, ey - sy) / 2
    
    --print("TOPLEFT", frame, "TOPLEFT", math.min(ax, bx, cx) * frame:GetWidth(), math.min(ax, bx, cx) * frame:GetHeight())
    --print("BOTTOMRIGHT", frame, "BOTTOMRIGHT", -math.max(ax, bx, cx) * frame:GetWidth(), -math.max(ax, bx, cx) * frame:GetHeight())
    self:SetPoint("TOPLEFT", frame, "TOPLEFT", (sx + ex) / 2 - disty, -(sy + ey) / 2 + disty)
    self:SetPoint("BOTTOMRIGHT", frame, "TOPLEFT", (sx + ex) / 2 + disty, -(sy + ey) / 2 - disty)
    
    local wid = disty * 2
    local hei = disty * 2
    
    local widextra = (wid - (ex - sx)) / 2
    local heiextra = (hei - (ey - sy)) / 2
    
    local base = matrix_create()
    
    matrix_mult(base, 1, 0, -1 / 512, 0, 1, -1 / 512)
    matrix_rescale(base, 512 / 510, 512 / 510)
    
    local lenab = dist(ax, ay, bx, by)
    local lenbc = dist(bx, by, cx, cy)
    local lenca = dist(cx, cy, ax, ay)
    local s = (lenab + lenbc + lenca) / 2
    local area = math.sqrt(s * (s - lenab) * (s - lenbc) * (s - lenca)) -- heron's formula
    -- triangle area=base*height/2, therefore height=area/base*2
    local height = area / lenab * 2
    
    print(wid, hei, disty, ex - sx, ey - sy)
    print(lenab, lenbc, lenca)
    print(area, height)
    print(lenab / wid, height / hei)
    
    matrix_print(base)
    matrix_rescale(base, lenab / wid, height / hei)
    matrix_print(base)
    
    -- now we have it scaled properly, now we have to skew
    -- right now we have:
    --   A----------B
    --                   |
    --                   C
    -- We want:
    --     A------------B
    --
    --  C
    -- Virtual point:
    --  D A------------B
    --
    --  C
    -- So the question is, how long is DB? Find that out, divide by height, and there's our skew constant
    -- unit(A-B) dot (C-B) - does this work? I think so
    -- alternatively, ((A-B) dot (C-B)) / lenab
    
    print("db is", ((ax - bx) * (cx - bx) + (ay - by) * (cy - by)))
    print("height is", height)
    print("lenab is", lenab)
    
    if height == 0 then
      self:SetTexCoord(3, 3, 4, 4)
      return
    end
    
    -- same as matrix_mult(base, 1, (nastything), 0, 1) (I think? maybe not?)
    matrix_mult(base, 1, -((ax - bx) * (cx - bx) + (ay - by) * (cy - by)) / lenab / height, 0, 0, 1, 0)
    --base[2] = base[2] - ((ax - bx) * (cx - bx) + (ay - by) * (cy - by)) / lenab / height * base[5]
    
    matrix_print(base)
    
    -- next: we sit and rotate on it
    
    local angle = atan2(ax - bx, ay - by)
    print(angle)
    
    matrix_rotate(base, -angle - 90) -- this will take adjustment
    
    matrix_print(base)
    
    -- now we translate to the expected position
    
    print(ax - sx, ay - sy, (ax - sx) / lenab, (ay - sy) / lenab, (ax - sx) / wid, (ay - sy) / hei)
    
    matrix_mult(base, 1, 0, tigo or ((ax - sx + widextra) / wid), 0, 1, togo or ((ay - sy + heiextra) / hei))
    --base[3] = base[3] + (ax - sx) / lenab
    --base[6] = base[6] + (ay - sy) / lenab
    
    --[[matrix_rescale(base, 0.5, 0.5)
    base[3] = base[3] + wing
    base[6] = base[6] + wong]]
    
    
    local A, B, C, D, E, F = base[1], base[2], base[3], base[4], base[5], base[6]
    
    local det = A*E - B*D
    local ULx, ULy, LLx, LLy, URx, URy, LRx, LRy
    
    ULx, ULy = ( B*F - C*E ) / det, ( -(A*F) + C*D ) / det
    LLx, LLy = ( -B + B*F - C*E ) / det, ( A - A*F + C*D ) / det
    URx, URy = ( E + B*F - C*E ) / det, ( -D - A*F + C*D ) / det
    LRx, LRy = ( E - B + B*F - C*E ) / det, ( -D + A -(A*F) + C*D ) / det
    
    if testrange(ULx, ULy, LLx, LLy, URx, URy, LRx, LRy) then
      self:SetTexCoord(3, 3, 4, 4)
      return
    end
    
    --QuestHelper:TextOut(string.format("%f %f %f %f %f %f %f %f %f", det, ULx, ULy, LLx, LLy, URx, URy, LRx, LRy))
    --QuestHelper:TextOut(string.format("%f %f %f %f %f %f", A, B, C, D, E, F))
    
    self:SetTexCoord(ULx, ULy, LLx, LLy, URx, URy, LRx, LRy); -- the sound you hear is vomiting
    
    --[[spots[1]:Moove(ax, ay)
    spots[2]:Moove(bx, by)
    spots[3]:Moove(cx, cy)]]
  end
  
  return tex
end

local alloc = {}

function CreateTriangle(frame)
  if alloc[frame] and #alloc[frame] > 0 then
    return table.remove(alloc[frame])
  else
    return MakeTriangle(frame)
  end
end

function ReleaseTriangle(tri)
  if not alloc[tri.parent_frame] then alloc[tri.parent_frame] = {} end
  table.insert(alloc[tri.parent_frame], tri)
  tri:Hide()
end





local function MakeLine(frame)
  tex = frame:CreateTexture()
  tex:SetTexture("Interface\\AddOns\\QuestHelper\\line")
  
  tex.parent_frame = frame
  -- relative to 0,1 coordinates relative to parent
  tex.SetLine = function(self, ax, ay, bx, by)
    -- do we need to reverse the triangle? NOTE: a lot of this code is unsurprisingly copied from triangle. were you surprised by this?
    --[[
    if ax * by - bx * ay + bx * cy - cx * by + cx * ay - cy * ax < 0 then
      ax, bx = bx, ax
      ay, by = by, ay
    end]]
    
    print(ax, ay, bx, by)
    ax, bx = ax * frame:GetWidth(), bx * frame:GetWidth()
    ay, by = ay * frame:GetHeight(), by * frame:GetHeight()
    print(ax, ay, bx, by)
    self:ClearAllPoints()
    
    local sx = math.min(ax, bx)
    local sy = math.min(ay, by)
    local ex = math.max(ax, bx)
    local ey = math.max(ay, by)
    
    local disty = math.max(ex - sx, ey - sy) / 2 + 20
    
    --print("TOPLEFT", frame, "TOPLEFT", math.min(ax, bx, cx) * frame:GetWidth(), math.min(ax, bx, cx) * frame:GetHeight())
    --print("BOTTOMRIGHT", frame, "BOTTOMRIGHT", -math.max(ax, bx, cx) * frame:GetWidth(), -math.max(ax, bx, cx) * frame:GetHeight())
    self:SetPoint("TOPLEFT", frame, "TOPLEFT", (sx + ex) / 2 - disty, -(sy + ey) / 2 + disty)
    self:SetPoint("BOTTOMRIGHT", frame, "TOPLEFT", (sx + ex) / 2 + disty, -(sy + ey) / 2 - disty)
    
    local wid = disty * 2
    local hei = disty * 2
    
    local widextra = (wid - (ex - sx)) / 2
    local heiextra = (hei - (ey - sy)) / 2
    
    local base = matrix_create()
    
    matrix_mult(base, 1, 0, -1 / 512, 0, 1, 0)
    matrix_rescale(base, 512 / 510, 1 / disty)
    
    local lenny = dist(ax, ay, bx, by)
    print("lendist", lenny, disty * 2)
    matrix_rescale(base, lenny / (disty * 2), 1)
    
    
    local angle = atan2(ax - bx, ay - by)
    matrix_rotate(base, -angle - 90)
    
    
    print("trans", 1, 0, tigo or ((ax - sx + widextra) / wid), 0, 1, togo or ((ay - sy + heiextra) / hei))
    matrix_mult(base, 1, 0, tigo or ((ax - sx + widextra) / wid), 0, 1, togo or ((ay - sy + heiextra) / hei))
    matrix_print(base)
    
    local A, B, C, D, E, F = base[1], base[2], base[3], base[4], base[5], base[6]
    
    local det = A*E - B*D
    local ULx, ULy, LLx, LLy, URx, URy, LRx, LRy
    
    ULx, ULy = ( B*F - C*E ) / det, ( -(A*F) + C*D ) / det
    LLx, LLy = ( -B + B*F - C*E ) / det, ( A - A*F + C*D ) / det
    URx, URy = ( E + B*F - C*E ) / det, ( -D - A*F + C*D ) / det
    LRx, LRy = ( E - B + B*F - C*E ) / det, ( -D + A -(A*F) + C*D ) / det
    
    if testrange(ULx, ULy, LLx, LLy, URx, URy, LRx, LRy) then
      self:SetTexCoord(3, 3, 4, 4)
      return
    end
    
    --QuestHelper:TextOut(string.format("%f %f %f %f %f %f %f %f %f", det, ULx, ULy, LLx, LLy, URx, URy, LRx, LRy))
    --QuestHelper:TextOut(string.format("%f %f %f %f %f %f", A, B, C, D, E, F))
    self:SetTexCoord(ULx, ULy, LLx, LLy, URx, URy, LRx, LRy); -- the sound you hear is vomiting
    
    --[[spots[1]:Moove(ax, ay)
    spots[2]:Moove(bx, by)
    spots[3]:Moove(cx, cy)]]
  end
  
  return tex
end



-- haha
-- yeeeeaah, I just overrode a local variable with another near-identical local variable
-- that's gonna bite me someday
local alloc = {}

-- guess whether I changed this code after copying it
-- hint:
-- I didn't change this code after copying it
-- are you shocked
-- man, if you've read this far in the QH sourcecode, you sure as hell better not be shocked
-- 'cause
-- yeah
-- that'd be kind of sad.
function CreateLine(frame)
  if alloc[frame] and #alloc[frame] > 0 then
    return table.remove(alloc[frame])
  else
    return MakeLine(frame)
  end
end

function ReleaseLine(tri)
  if not alloc[tri.parent_frame] then alloc[tri.parent_frame] = {} end
  table.insert(alloc[tri.parent_frame], tri)
  tri:Hide()
end

-- note: variable name is "tritest". try to guess why
function testit()
  if tritest then tritest:Hide() end
  tritest = CreateLine(UIParent)
  tritest:SetLine(0.5, 0.6, 0.8, 0.7)
  tritest:Show()
end
