diff --git a/HarvestRoute.lua b/HarvestRoute.lua
index c27646b..861524e 100644
--- a/HarvestRoute.lua
+++ b/HarvestRoute.lua
@@ -1,7 +1,7 @@
HarvestRoute = {}
HarvestRoute.name = "HarvestRoute"
HarvestRoute.displayName = 'HarvestRoute for Harvestmap'
-HarvestRoute.version = "1.0.6"
+HarvestRoute.version = "1.0.7"
HarvestRoute.author = "generic"
HarvestRoute.settingsVersion = 3
HarvestRoute.savedVars = {}
@@ -44,6 +44,7 @@ local pathNodes = {}
local playerX = 0
local playerY = 0
local playerZ = 0
+local ourPathChange = false
@@ -101,16 +102,16 @@ local function initialize( eventCode, addOnName )
Harvest.callbackManager:RegisterForEvent(Harvest.events.TOUR_CHANGED, HarvestRoute.checkPath )
HarvestRoute.ApplyStyle()
if HarvestRoute.savedVars.enableTrackerWindow and HarvestRoute.savedVars.showTrackerWindow then
- HarvestRoute:SetTrackerHidden( false )
- HarvestRoute:InitTracker()
- HarvestRoute:UpdateTracker()
+ HarvestRoute.SetTrackerHidden( false )
+ HarvestRoute.InitTracker()
+ HarvestRoute.UpdateTracker()
end
end
local function TrackerWindowDisabled() return not HarvestRoute.savedVars.enableTrackerWindow end
-function HarvestRoute:InitializeSettingsMenu()
+function HarvestRoute.InitializeSettingsMenu()
local panel = {
type = "panel",
name = HarvestRoute.name,
@@ -146,9 +147,9 @@ function HarvestRoute:InitializeSettingsMenu()
setFunc = function (value)
HarvestRoute.savedVars.showTrackerWindow = value
if value then
- HarvestRoute:SetTrackerHidden( false )
- HarvestRoute:InitTracker()
- HarvestRoute:UpdateTracker()
+ HarvestRoute.SetTrackerHidden( false )
+ HarvestRoute.InitTracker()
+ HarvestRoute.UpdateTracker()
end
end,
default = HarvestRoute.defaultSettings.showTrackerWindow,
@@ -179,58 +180,63 @@ function HarvestRoute:InitializeSettingsMenu()
LibAddonMenu2:RegisterOptionControls(HarvestRoute.name.."OptionsMenu", options)
end
-function HarvestRoute:OnButton()
+function HarvestRoute.OnButton()
if isActive then
isActive = false
- HarvestRoute:StopTracker()
+ HarvestRoute.StopTracker()
else
isActive = true
- HarvestRoute:StartTracker()
+ HarvestRoute.StartTracker()
end
- HarvestRoute:UpdateTracker()
+ HarvestRoute.UpdateTracker()
end
-function HarvestRoute:StartTracker()
+function HarvestRoute.StartTracker()
EVENT_MANAGER:RegisterForUpdate("HarvestRouteUpdatePosition", 50, HarvestRoute.OnUpdate)
local mapMetaData = Harvest.mapTools:GetViewedMapMetaData()
MapCache = Harvest.Data:GetMapCache( mapMetaData )
currentZoneId = GetUnitZoneIndex("player")
-
- HarvestRoute:SetTrackerHidden(false)
- HarvestRoute:InitTracker()
+
+ Farm = Harvest.farm
+ Editor = Harvest.editor
+ Helper = Farm.helper
+
+ HarvestRoute.SetTrackerHidden(false)
+ HarvestRoute.InitTracker()
end
-function HarvestRoute:StopTracker()
+function HarvestRoute.StopTracker()
EVENT_MANAGER:UnregisterForUpdate("HarvestRouteUpdatePosition")
- HarvestRoute:InitTracker()
+ HarvestRoute.InitTracker()
end
-function HarvestRoute:OnPlayerLoaded()
+function HarvestRoute.OnPlayerLoaded()
local newZoneId = GetUnitZoneIndex("player")
if currentZoneId and currentZoneId == newZoneId then
return
end
- HarvestRoute:debug('zone switched')
+ HarvestRoute.debug('zone switched')
lastNodeId = nil
pathNodeId = nil
- lastPathIndex = nill
+ lastPathIndex = nil
pathNodes = {}
currentZoneId = newZoneId
if isActive then
- HarvestRoute:OnButton()
+ HarvestRoute.OnButton()
end
if HarvestRoute.savedVars.enableTrackerWindow then
if HarvestRoute.savedVars.showTrackerWindow or isTrackerVisible then
- HarvestRoute:SetTrackerHidden( false )
- HarvestRoute:UpdateTracker()
+ HarvestRoute.SetTrackerHidden( false )
+ HarvestRoute.UpdateTracker()
end
end
end
-- reset pathnodes when path has changed from outside, and either last node or last path node are invalid
-function HarvestRoute:checkPath(event, path)
+function HarvestRoute.checkPath(event, path)
+ if ourPathChange then return end -- if we are responsible we do not care.
local validpath = false
local validnode = false
if lastNodeId and MapCache then
@@ -247,26 +253,26 @@ function HarvestRoute:checkPath(event, path)
end
end
if not validnode then
- HarvestRoute:debug('last node invalid')
+ HarvestRoute.debug('last node invalid')
lastNodeId = nil
end
if not validpath then
- HarvestRoute:debug('last path index invalid')
+ HarvestRoute.debug('last path index invalid')
lastNodeId = nil
pathNodeId = nil
lastPathIndex = nil
pathNodes = {}
end
- HarvestRoute:UpdateTracker()
+ HarvestRoute.UpdateTracker()
end
-function HarvestRoute:OnUpdate (time)
+function HarvestRoute.OnUpdate (time)
if isActive then
playerX, playerY, playerZ = Harvest.GetPlayer3DPosition()
- local nodeId, nodeDistance, nodePinType = HarvestRoute:GetClosestNode()
+ local nodeId, nodeDistance, nodePinType = HarvestRoute.GetClosestNode()
if nodeId then
if nodePinType ~= Harvest.UNKNOWN and nodeId ~= lastNodeId and (nodeDistance < HarvestRoute.savedVars.trackerRange) then
- HarvestRoute:debug('node in range: '..nodeId)
+ HarvestRoute.debug('node in range: '..nodeId)
local x, y = MapCache:GetLocal(nodeId)
if Farm.path then
local index = Farm.path:GetIndex(nodeId)
@@ -285,20 +291,22 @@ function HarvestRoute:OnUpdate (time)
end
if switchToPathNode then
- HarvestRoute:debug('path node '..nodeId..' ')
+ HarvestRoute.debug('path node '..nodeId..' ')
pathNodeId = nodeId
lastPathIndex = index
end
else
if pathNodeId then
- HarvestRoute:debug('insert '..nodeId..' after path node '..pathNodeId..' ')
+ HarvestRoute.debug('insert '..nodeId..' after path node '..pathNodeId..' ')
if HarvestRoute.savedVars.usePathHeuristic then
- pathNodeId = HarvestRoute:checkPathHeuristic(pathNodeId, lastNodeAddedToPath, nodeId)
+ pathNodeId = HarvestRoute.getSmartInsertNode(pathNodeId, lastNodeAddedToPath, nodeId)
end
+ ourPathChange = true
Farm.path:InsertAfter(pathNodeId, nodeId)
pathNodeId = nodeId
lastNodeAddedToPath = nodeId
lastPathIndex = Farm.path:GetIndex(nodeId)
+ ourPathChange = false
Harvest.farm.display:Refresh(Farm.path, Harvest.farm.display.selectedPins, Harvest.farm.display.selectedMapCache)
Harvest.farm.editor.statusLabel:SetText(Harvest.farm.editor.textConstructor())
@@ -311,64 +319,150 @@ function HarvestRoute:OnUpdate (time)
end
else --create a new path
pathNodes[#pathNodes + 1] = nodeId
- HarvestRoute:debug('added '..nodeId..' as path node '..#pathNodes)
+ HarvestRoute.debug('added '..nodeId..' as path node '..#pathNodes)
if #pathNodes > 2 then
+ ourPathChange = true
path = Harvest.path:New(MapCache)
path:GenerateFromNodeIds(pathNodes, 1, #pathNodes)
Farm:SetPath(path)
+ ourPathChange = false
lastPathIndex = Farm.path:GetIndex(nodeId)
+ lastNodeAddedToPath = nodeId
pathNodeId = nodeId
pathNodes = {}
end
end
lastNodeId = nodeId
end --nodeDistance
- HarvestRoute:UpdateTracker()
+ HarvestRoute.UpdateTracker()
end --nodeId
end --isActive
end
-function HarvestRoute:getNodeDistance(n1, n2)
- local distance = 0
+function HarvestRoute.getNodeDistance(n1, n2)
+ local distance = 10000
if MapCache.worldX and MapCache.worldX[n1] and MapCache.worldX[n2] then
local dx = MapCache.worldX[n1] - MapCache.worldX[n2]
- local dy = MapCache.worldX[n1] - MapCache.worldX[n2]
+ local dy = MapCache.worldY[n1] - MapCache.worldY[n2]
distance = ( dx * dx + dy * dy ) ^ 0.5
end
return distance
end
-function HarvestRoute:GetNextPathNode(nodeId)
+function HarvestRoute.GetPathNodeWithOffset(nodeId, offset)
local index = Farm.path:GetIndex(nodeId)
+ local oldindex = index
if not index then return nil end
- index = ((index + 1) % Farm.path.numNodes)
+ if not offset then return nodeId end
+ local numNodes = Farm.path.numNodes
+ --offset = offset % numNodes
+ index = index + offset + numNodes
+ index = ((index - 1) % numNodes) +1
+ if index < 1 then
+ --index = index + numNodes
+ elseif index > numNodes then
+ --index = index - numNodes
+ end
+ HarvestRoute.debug("Index ".. oldindex .. " + " .. offset .. " = " .. index .. " (" .. numNodes .. ")" )
return Farm.path.nodeIndices[index]
end
+function HarvestRoute.GetNextPathNode(nodeId)
+ return HarvestRoute.GetPathNodeWithOffset(nodeId, 1)
+end
+function HarvestRoute.GetPreviousPathNode(nodeId)
+ return HarvestRoute.GetPathNodeWithOffset(nodeId, -1)
+end
+
--- be "smart" and detect which of n1 or n2 adds less total length, to prevent zigzag accidents when backtracking
-function HarvestRoute:checkPathHeuristic(n1, n2, addNode)
- if not n2 then return n1 end
- if n1 == n2 then return n1 end
- HarvestRoute:debug("checkPathHeuristic " .. n1 .." / ".. n2 .. " (" .. addNode ..")")
+-- be "smart" and detect if adding before or after either n1 or n2 wourld result in a better path
+-- should remove most zigzags when backtracking or enhancing existing paths
+function HarvestRoute.getSmartInsertNode(n1, n2, addNode)
+ --if not n2 then return n1 end
+ --if n1 == n2 then return n1 end
+ HarvestRoute.debug("getSmartInsertNode")
+ -- HarvestRoute.debug("checkPathHeuristic " .. n1 .." / ".. n2 .. " (" .. addNode ..")")
+ local result = n1
if Farm.path then
- local n1next = HarvestRoute:GetNextPathNode(n1)
- local n2next = HarvestRoute:GetNextPathNode(n2)
- if n1next and n2next then
- local d1 = HarvestRoute:getNodeDistance(n1, addNode) + HarvestRoute:getNodeDistance(n1next, addNode) - HarvestRoute:getNodeDistance(n1, n1next)
- local d2 = HarvestRoute:getNodeDistance(n2, addNode) + HarvestRoute:getNodeDistance(n2next, addNode) - HarvestRoute:getNodeDistance(n2, n2next)
- HarvestRoute:debug("Lastpathnode " .. d1 .. " / Lastinsertnode " .. d2 )
- if d2 < d1 then
- return n2
+ local n1_result, n1_distance = HarvestRoute.getBetterInsertNode(n1, addNode)
+ result = n1_result
+ if n2 and n1 ~= n2 then
+ local n2_result, n2_distance = HarvestRoute.getBetterInsertNode(n2, addNode)
+ if n2_distance < n1_distance then
+ result = n2_result
end
+ end
+ end
+ return result
+end
+
+-- return previous node, if the resulting path would be better (basically insert before node, instead of insert after)
+function HarvestRoute.getBetterInsertNode(node, addNode)
+ local nextnode = HarvestRoute.GetNextPathNode(node)
+ local prevnode = HarvestRoute.GetPreviousPathNode(node)
+ if prevnode and nextnode then
+ -- using stackoverflow https://stackoverflow.com/questions/33155240/how-to-check-if-a-point-is-between-two-other-points-but-not-limited-to-be-align
+ -- add = A, node = B, next / prev = C
+ local a_prev_to_node = HarvestRoute.getNodeDistance(prevnode, node)
+ local a_node_to_next = HarvestRoute.getNodeDistance(node, nextnode)
+ local b_prev_to_add = HarvestRoute.getNodeDistance(prevnode, addNode)
+ local b_add_to_next = HarvestRoute.getNodeDistance(addNode, nextnode)
+ local c_node_to_add = HarvestRoute.getNodeDistance(node, addNode)
+
+ -- path length changes for both node and prevnode
+ local d_next = a_prev_to_node + c_node_to_add + b_add_to_next - a_node_to_next
+ local d_prev = b_prev_to_add + c_node_to_add + a_node_to_next - a_prev_to_node
+
+ -- some mathemagics which are not needed
+ --[[
+ local node_between_next = HarvestRoute.NodeAisBetweenBandCusingDistances(a_node_to_next, b_add_to_next, c_node_to_add)
+ local node_between_prev = HarvestRoute.NodeAisBetweenBandCusingDistances(a_prev_to_node, b_prev_to_add, c_node_to_add)
+
+ local prev_crossed = HarvestRoute.linesAreCrossed(prevnode, addNode, node, nextnode)
+ local next_crossed = HarvestRoute.linesAreCrossed(prevnode, node, addNode, nextnode)
+ --]]
+ if d_prev < d_next then
+ HarvestRoute.debug("PrevNode " .. prevnode .. " (prevnode shorter " .. d_prev .. " vs. " .. d_next .. ")")
+ return prevnode, d_prev
else
- HarvestRoute:debug("NOT IN PATH n1 and n2")
+ HarvestRoute.debug("Node " .. node .. " (node shorter " .. d_prev .. " vs. " .. d_next.. ")")
+ return node, d_next
end
- end
- return n1
+ end
+ return node, 0
+end
+
+-- checks if the two line-segments defined by points [a/b] to [c/d] and [p/q] to [r/s] do intersect or not
+function HarvestRoute.intersects(a,b,c,d, p,q,r,s)
+ local det, gamma, lambda;
+ det = (c - a) * (s - q) - (r - p) * (d - b);
+ if det == 0 then return false end
+ lambda = ((s - q) * (r - a) + (p - r) * (s - b)) / det;
+ gamma = ((b - d) * (r - a) + (c - a) * (s - b)) / det;
+ return (0 < lambda and lambda < 1) and (0 < gamma and gamma < 1);
+end
+
+function HarvestRoute.linesAreCrossed(node_a, node_b, node_c, node_d)
+ local wx = MapCache.worldX
+ local wy = MapCache.worldY
+ return HarvestRoute.intersects(
+ wx[node_a],wy[node_a],
+ wx[node_b],wy[node_b],
+ wx[node_c],wy[node_c],
+ wx[node_d],wy[node_d])
end
+function HarvestRoute.NodeAisBetweenBandC(nodeA, nodeB, nodeC)
+ local a = HarvestRoute.getNodeDistance(nodeB, nodeC)
+ local b = HarvestRoute.getNodeDistance(nodeC, nodeA)
+ local c = HarvestRoute.getNodeDistance(nodeA, nodeB)
+ return HarvestRoute.NodeAisBetweenBandCusingDistances(a, b, c)
+end
+
+function HarvestRoute.NodeAisBetweenBandCusingDistances(a, b, c)
+ return (a*a + b*b >= c*c and a*a + c*c >= b*b)
+end
-- get the closest node to the player, using HarvestMap MapCache Divisions (and only check 4 divisions, from -50 to +50 from current position)
-function HarvestRoute:GetClosestNode()
+function HarvestRoute.GetClosestNode()
local bestNodeId = nil
if not MapCache then --yeah, no cache no cookies.
return nil, nil
@@ -453,19 +547,19 @@ function HarvestRoute:OnMoveStop( )
HarvestRoute.savedVars.wm.height = self:GetHeight()
end
-function HarvestRoute:ApplyStyle()
+function HarvestRoute.ApplyStyle()
HarvestRouteTracker:SetAnchor( TOPLEFT, GuiRoot, TOPLEFT, HarvestRoute.savedVars.wm.x, HarvestRoute.savedVars.wm.y )
end
-function HarvestRoute:SetTrackerHidden(value)
+function HarvestRoute.SetTrackerHidden(value)
isTrackerVisible = false
if not HarvestRoute.savedVars.enableTrackerWindow then value = true end
HarvestRouteTracker:SetHidden(value)
isTrackerVisible = not value
end
-function HarvestRoute:GetNodeDescription(nodeId)
+function HarvestRoute.GetNodeDescription(nodeId)
local description = HarvestRoute.GetLocalization( "nodeinfounknown" )
local angle = nil
if MapCache and MapCache.worldX and MapCache.worldX[nodeId] then
@@ -486,7 +580,7 @@ function HarvestRoute:GetNodeDescription(nodeId)
return description, angle
end
-function HarvestRoute:InitTracker()
+function HarvestRoute.InitTracker()
if isActive then
HarvestRouteButton:SetText(HarvestRoute.GetLocalization( "buttonstoptracker" ))
HarvestRouteTrackerButton:SetText(HarvestRoute.GetLocalization( "buttonstoptracker" ))
@@ -511,20 +605,20 @@ function HarvestRoute:InitTracker()
end
end
-function HarvestRoute:UpdateTracker()
- -- HarvestRoute:debug('UpdateTracker')
+function HarvestRoute.UpdateTracker()
+ -- HarvestRoute.debug('UpdateTracker')
if not HarvestRoute.savedVars.enableTrackerWindow then
if isTrackerVisible then
- HarvestRoute:SetTrackerHidden( true )
+ HarvestRoute.SetTrackerHidden( true )
end
return
end
if not isTrackerVisible then
- HarvestRoute:debug('tracker not visible')
+ HarvestRoute.debug('tracker not visible')
return
end
if isActive then
- nearestText, nearestAngle = HarvestRoute:GetNodeDescription(closestOutOfPathId)
+ nearestText, nearestAngle = HarvestRoute.GetNodeDescription(closestOutOfPathId)
HarvestRouteTrackerNearestNode:SetText( nearestText )
if nearestAngle then
HarvestRouteTrackerNearestArrow:SetHidden(false)
@@ -541,7 +635,7 @@ function HarvestRoute:UpdateTracker()
if isActive then
HarvestRouteTrackerLastPathNodeTitle:SetHidden( false )
HarvestRouteTrackerLastPathNode:SetHidden( false )
- pathText, pathAngle = HarvestRoute:GetNodeDescription(pathNodeId)
+ pathText, pathAngle = HarvestRoute.GetNodeDescription(pathNodeId)
HarvestRouteTrackerLastPathNode:SetText( pathText )
if pathAngle then
HarvestRouteTrackerPathArrow:SetHidden(false)
@@ -559,7 +653,7 @@ function HarvestRoute:UpdateTracker()
end
-function HarvestRoute:debug(text)
+function HarvestRoute.debug(text)
--CHAT_SYSTEM:AddMessage(text)
end